Add support for 32 bit BGRA sprites.
This commit is contained in:
@@ -64,7 +64,7 @@ namespace OpenRA.Graphics
|
|||||||
return Load(fileSystem, additionalSequences);
|
return Load(fileSystem, additionalSequences);
|
||||||
});
|
});
|
||||||
|
|
||||||
spriteCache = Exts.Lazy(() => new SpriteCache(fileSystem, modData.SpriteLoaders, new SheetBuilder(SheetType.Indexed)));
|
spriteCache = Exts.Lazy(() => new SpriteCache(fileSystem, modData.SpriteLoaders));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISpriteSequence GetSequence(string unitName, string sequenceName)
|
public ISpriteSequence GetSequence(string unitName, string sequenceName)
|
||||||
@@ -130,16 +130,21 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public void Preload()
|
public void Preload()
|
||||||
{
|
{
|
||||||
SpriteCache.SheetBuilder.Current.CreateBuffer();
|
foreach (var sb in SpriteCache.SheetBuilders.Values)
|
||||||
|
sb.Current.CreateBuffer();
|
||||||
|
|
||||||
foreach (var unitSeq in sequences.Value.Values)
|
foreach (var unitSeq in sequences.Value.Values)
|
||||||
foreach (var seq in unitSeq.Value.Values) { }
|
foreach (var seq in unitSeq.Value.Values) { }
|
||||||
SpriteCache.SheetBuilder.Current.ReleaseBuffer();
|
|
||||||
|
foreach (var sb in SpriteCache.SheetBuilders.Values)
|
||||||
|
sb.Current.ReleaseBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (spriteCache.IsValueCreated)
|
if (spriteCache.IsValueCreated)
|
||||||
spriteCache.Value.SheetBuilder.Dispose();
|
foreach (var sb in SpriteCache.SheetBuilders.Values)
|
||||||
|
sb.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,17 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public Png AsPng()
|
public Png AsPng()
|
||||||
{
|
{
|
||||||
return new Png(GetData(), Size.Width, Size.Height);
|
var data = GetData();
|
||||||
|
|
||||||
|
// Convert BGRA to RGBA
|
||||||
|
for (var i = 0; i < Size.Width * Size.Height; i++)
|
||||||
|
{
|
||||||
|
var temp = data[i * 4];
|
||||||
|
data[i * 4] = data[i * 4 + 2];
|
||||||
|
data[i * 4 + 2] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Png(data, Size.Width, Size.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Png AsPng(TextureChannel channel, IPalette pal)
|
public Png AsPng(TextureChannel channel, IPalette pal)
|
||||||
|
|||||||
@@ -47,6 +47,16 @@ namespace OpenRA.Graphics
|
|||||||
return new Sheet(type, new Size(sheetSize, sheetSize));
|
return new Sheet(type, new Size(sheetSize, sheetSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SheetType FrameTypeToSheetType(SpriteFrameType t)
|
||||||
|
{
|
||||||
|
switch (t)
|
||||||
|
{
|
||||||
|
case SpriteFrameType.Indexed: return SheetType.Indexed;
|
||||||
|
case SpriteFrameType.BGRA: return SheetType.BGRA;
|
||||||
|
default: throw new NotImplementedException("Unknown SpriteFrameType {0}".F(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public SheetBuilder(SheetType t)
|
public SheetBuilder(SheetType t)
|
||||||
: this(t, Game.Settings.Graphics.SheetSize) { }
|
: this(t, Game.Settings.Graphics.SheetSize) { }
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ using OpenRA.Primitives;
|
|||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
{
|
{
|
||||||
|
public enum SpriteFrameType { Indexed, BGRA }
|
||||||
|
|
||||||
public interface ISpriteLoader
|
public interface ISpriteLoader
|
||||||
{
|
{
|
||||||
bool TryParseSprite(Stream s, out ISpriteFrame[] frames, out TypeDictionary metadata);
|
bool TryParseSprite(Stream s, out ISpriteFrame[] frames, out TypeDictionary metadata);
|
||||||
@@ -25,6 +27,8 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public interface ISpriteFrame
|
public interface ISpriteFrame
|
||||||
{
|
{
|
||||||
|
SpriteFrameType Type { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Size of the frame's `Data`.
|
/// Size of the frame's `Data`.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -43,7 +47,7 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public class SpriteCache
|
public class SpriteCache
|
||||||
{
|
{
|
||||||
public readonly SheetBuilder SheetBuilder;
|
public readonly Cache<SpriteFrameType, SheetBuilder> SheetBuilders;
|
||||||
readonly ISpriteLoader[] loaders;
|
readonly ISpriteLoader[] loaders;
|
||||||
readonly IReadOnlyFileSystem fileSystem;
|
readonly IReadOnlyFileSystem fileSystem;
|
||||||
|
|
||||||
@@ -51,9 +55,10 @@ namespace OpenRA.Graphics
|
|||||||
readonly Dictionary<string, ISpriteFrame[]> unloadedFrames = new Dictionary<string, ISpriteFrame[]>();
|
readonly Dictionary<string, ISpriteFrame[]> unloadedFrames = new Dictionary<string, ISpriteFrame[]>();
|
||||||
readonly Dictionary<string, TypeDictionary> metadata = new Dictionary<string, TypeDictionary>();
|
readonly Dictionary<string, TypeDictionary> metadata = new Dictionary<string, TypeDictionary>();
|
||||||
|
|
||||||
public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
|
public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders)
|
||||||
{
|
{
|
||||||
SheetBuilder = sheetBuilder;
|
SheetBuilders = new Cache<SpriteFrameType, SheetBuilder>(t => new SheetBuilder(SheetBuilder.FrameTypeToSheetType(t)));
|
||||||
|
|
||||||
this.fileSystem = fileSystem;
|
this.fileSystem = fileSystem;
|
||||||
this.loaders = loaders;
|
this.loaders = loaders;
|
||||||
}
|
}
|
||||||
@@ -89,7 +94,7 @@ namespace OpenRA.Graphics
|
|||||||
allSprites.Add(sprite);
|
allSprites.Add(sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK: The sequency code relies on side-effects from getUsedFrames
|
// HACK: The sequence code relies on side-effects from getUsedFrames
|
||||||
var indices = getUsedFrames != null ? getUsedFrames(sprite.Length) :
|
var indices = getUsedFrames != null ? getUsedFrames(sprite.Length) :
|
||||||
Enumerable.Range(0, sprite.Length);
|
Enumerable.Range(0, sprite.Length);
|
||||||
|
|
||||||
@@ -100,7 +105,7 @@ namespace OpenRA.Graphics
|
|||||||
{
|
{
|
||||||
if (unloaded[i] != null)
|
if (unloaded[i] != null)
|
||||||
{
|
{
|
||||||
sprite[i] = SheetBuilder.Add(unloaded[i]);
|
sprite[i] = SheetBuilders[unloaded[i].Type].Add(unloaded[i]);
|
||||||
unloaded[i] = null;
|
unloaded[i] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
using OpenRA.Support;
|
using OpenRA.Support;
|
||||||
@@ -34,7 +35,7 @@ namespace OpenRA.Graphics
|
|||||||
public sealed class Theater : IDisposable
|
public sealed class Theater : IDisposable
|
||||||
{
|
{
|
||||||
readonly Dictionary<ushort, TheaterTemplate> templates = new Dictionary<ushort, TheaterTemplate>();
|
readonly Dictionary<ushort, TheaterTemplate> templates = new Dictionary<ushort, TheaterTemplate>();
|
||||||
readonly SheetBuilder sheetBuilder;
|
SheetBuilder sheetBuilder;
|
||||||
readonly Sprite missingTile;
|
readonly Sprite missingTile;
|
||||||
readonly MersenneTwister random;
|
readonly MersenneTwister random;
|
||||||
TileSet tileset;
|
TileSet tileset;
|
||||||
@@ -53,7 +54,6 @@ namespace OpenRA.Graphics
|
|||||||
return new Sheet(SheetType.Indexed, new Size(tileset.SheetSize, tileset.SheetSize));
|
return new Sheet(SheetType.Indexed, new Size(tileset.SheetSize, tileset.SheetSize));
|
||||||
};
|
};
|
||||||
|
|
||||||
sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate);
|
|
||||||
random = new MersenneTwister();
|
random = new MersenneTwister();
|
||||||
|
|
||||||
var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders);
|
var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders);
|
||||||
@@ -75,6 +75,15 @@ namespace OpenRA.Graphics
|
|||||||
var zOffset = tile != null ? -tile.ZOffset : 0;
|
var zOffset = tile != null ? -tile.ZOffset : 0;
|
||||||
var zRamp = tile != null ? tile.ZRamp : 1f;
|
var zRamp = tile != null ? tile.ZRamp : 1f;
|
||||||
var offset = new float3(f.Offset, zOffset);
|
var offset = new float3(f.Offset, zOffset);
|
||||||
|
var type = SheetBuilder.FrameTypeToSheetType(f.Type);
|
||||||
|
|
||||||
|
// Defer SheetBuilder creation until we know what type of frames we are loading!
|
||||||
|
// TODO: Support mixed indexed and BGRA frames
|
||||||
|
if (sheetBuilder == null)
|
||||||
|
sheetBuilder = new SheetBuilder(SheetBuilder.FrameTypeToSheetType(f.Type), allocate);
|
||||||
|
else if (type != sheetBuilder.Type)
|
||||||
|
throw new InvalidDataException("Sprite type mismatch. Terrain sprites must all be either Indexed or RGBA.");
|
||||||
|
|
||||||
var s = sheetBuilder.Allocate(f.Size, zRamp, offset);
|
var s = sheetBuilder.Allocate(f.Size, zRamp, offset);
|
||||||
Util.FastCopyIntoChannel(s, f.Data);
|
Util.FastCopyIntoChannel(s, f.Data);
|
||||||
|
|
||||||
@@ -102,7 +111,7 @@ namespace OpenRA.Graphics
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1x1px transparent tile
|
// 1x1px transparent tile
|
||||||
missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1));
|
missingTile = sheetBuilder.Add(new byte[sheetBuilder.Type == SheetType.BGRA ? 4 : 1], new Size(1, 1));
|
||||||
|
|
||||||
Sheet.ReleaseBuffer();
|
Sheet.ReleaseBuffer();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,23 +61,56 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public static void FastCopyIntoChannel(Sprite dest, byte[] src)
|
public static void FastCopyIntoChannel(Sprite dest, byte[] src)
|
||||||
{
|
{
|
||||||
var data = dest.Sheet.GetData();
|
var destData = dest.Sheet.GetData();
|
||||||
var srcStride = dest.Bounds.Width;
|
var width = dest.Bounds.Width;
|
||||||
var destStride = dest.Sheet.Size.Width * 4;
|
|
||||||
var destOffset = destStride * dest.Bounds.Top + dest.Bounds.Left * 4 + ChannelMasks[(int)dest.Channel];
|
|
||||||
var destSkip = destStride - 4 * srcStride;
|
|
||||||
var height = dest.Bounds.Height;
|
var height = dest.Bounds.Height;
|
||||||
|
|
||||||
var srcOffset = 0;
|
if (dest.Channel == TextureChannel.RGBA)
|
||||||
for (var j = 0; j < height; j++)
|
|
||||||
{
|
{
|
||||||
for (var i = 0; i < srcStride; i++, srcOffset++)
|
var destStride = dest.Sheet.Size.Width;
|
||||||
|
unsafe
|
||||||
{
|
{
|
||||||
data[destOffset] = src[srcOffset];
|
// Cast the data to an int array so we can copy the src data directly
|
||||||
destOffset += 4;
|
fixed (byte* bd = &destData[0])
|
||||||
}
|
{
|
||||||
|
var data = (int*)bd;
|
||||||
|
var x = dest.Bounds.Left;
|
||||||
|
var y = dest.Bounds.Top;
|
||||||
|
|
||||||
destOffset += destSkip;
|
var k = 0;
|
||||||
|
for (var j = 0; j < height; j++)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < width; i++)
|
||||||
|
{
|
||||||
|
var r = src[k++];
|
||||||
|
var g = src[k++];
|
||||||
|
var b = src[k++];
|
||||||
|
var a = src[k++];
|
||||||
|
var cc = Color.FromArgb(a, r, g, b);
|
||||||
|
|
||||||
|
data[(y + j) * destStride + x + i] = PremultiplyAlpha(cc).ToArgb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var destStride = dest.Sheet.Size.Width * 4;
|
||||||
|
var destOffset = destStride * dest.Bounds.Top + dest.Bounds.Left * 4 + ChannelMasks[(int)dest.Channel];
|
||||||
|
var destSkip = destStride - 4 * width;
|
||||||
|
|
||||||
|
var srcOffset = 0;
|
||||||
|
for (var j = 0; j < height; j++)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < width; i++, srcOffset++)
|
||||||
|
{
|
||||||
|
destData[destOffset] = src[srcOffset];
|
||||||
|
destOffset += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
destOffset += destSkip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
|
|||||||
|
|
||||||
class ShpD2Frame : ISpriteFrame
|
class ShpD2Frame : ISpriteFrame
|
||||||
{
|
{
|
||||||
|
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
|
||||||
public Size Size { get; private set; }
|
public Size Size { get; private set; }
|
||||||
public Size FrameSize { get { return Size; } }
|
public Size FrameSize { get { return Size; } }
|
||||||
public float2 Offset { get { return float2.Zero; } }
|
public float2 Offset { get { return float2.Zero; } }
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
|
|||||||
|
|
||||||
class ImageHeader : ISpriteFrame
|
class ImageHeader : ISpriteFrame
|
||||||
{
|
{
|
||||||
|
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
|
||||||
public Size Size { get { return reader.Size; } }
|
public Size Size { get { return reader.Size; } }
|
||||||
public Size FrameSize { get { return reader.Size; } }
|
public Size FrameSize { get { return reader.Size; } }
|
||||||
public float2 Offset { get { return float2.Zero; } }
|
public float2 Offset { get { return float2.Zero; } }
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
|
|||||||
{
|
{
|
||||||
class TmpRAFrame : ISpriteFrame
|
class TmpRAFrame : ISpriteFrame
|
||||||
{
|
{
|
||||||
|
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
|
||||||
public Size Size { get; private set; }
|
public Size Size { get; private set; }
|
||||||
public Size FrameSize { get; private set; }
|
public Size FrameSize { get; private set; }
|
||||||
public float2 Offset { get { return float2.Zero; } }
|
public float2 Offset { get { return float2.Zero; } }
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
|
|||||||
{
|
{
|
||||||
class TmpTDFrame : ISpriteFrame
|
class TmpTDFrame : ISpriteFrame
|
||||||
{
|
{
|
||||||
|
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
|
||||||
public Size Size { get; private set; }
|
public Size Size { get; private set; }
|
||||||
public Size FrameSize { get; private set; }
|
public Size FrameSize { get; private set; }
|
||||||
public float2 Offset { get { return float2.Zero; } }
|
public float2 Offset { get { return float2.Zero; } }
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
|
|||||||
{
|
{
|
||||||
readonly TmpTSFrame parent;
|
readonly TmpTSFrame parent;
|
||||||
|
|
||||||
|
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
|
||||||
public Size Size { get { return parent.Size; } }
|
public Size Size { get { return parent.Size; } }
|
||||||
public Size FrameSize { get { return Size; } }
|
public Size FrameSize { get { return Size; } }
|
||||||
public float2 Offset { get { return parent.Offset; } }
|
public float2 Offset { get { return parent.Offset; } }
|
||||||
@@ -35,6 +36,7 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
|
|||||||
|
|
||||||
class TmpTSFrame : ISpriteFrame
|
class TmpTSFrame : ISpriteFrame
|
||||||
{
|
{
|
||||||
|
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
|
||||||
public Size Size { get; private set; }
|
public Size Size { get; private set; }
|
||||||
public Size FrameSize { get { return Size; } }
|
public Size FrameSize { get { return Size; } }
|
||||||
public float2 Offset { get; private set; }
|
public float2 Offset { get; private set; }
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ namespace OpenRA.Mods.Common.SpriteLoaders
|
|||||||
{
|
{
|
||||||
class ShpTSFrame : ISpriteFrame
|
class ShpTSFrame : ISpriteFrame
|
||||||
{
|
{
|
||||||
|
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
|
||||||
public Size Size { get; private set; }
|
public Size Size { get; private set; }
|
||||||
public Size FrameSize { get; private set; }
|
public Size FrameSize { get; private set; }
|
||||||
public float2 Offset { get; private set; }
|
public float2 Offset { get; private set; }
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
{
|
{
|
||||||
var ts = new TileSet(modData.DefaultFileSystem, t);
|
var ts = new TileSet(modData.DefaultFileSystem, t);
|
||||||
Console.WriteLine("Tileset: " + ts.Name);
|
Console.WriteLine("Tileset: " + ts.Name);
|
||||||
var sc = new SpriteCache(modData.DefaultFileSystem, modData.SpriteLoaders, new SheetBuilder(SheetType.Indexed));
|
var sc = new SpriteCache(modData.DefaultFileSystem, modData.SpriteLoaders);
|
||||||
var nodes = MiniYaml.Merge(modData.Manifest.Sequences.Select(s => MiniYaml.FromStream(modData.DefaultFileSystem.Open(s), s)));
|
var nodes = MiniYaml.Merge(modData.Manifest.Sequences.Select(s => MiniYaml.FromStream(modData.DefaultFileSystem.Open(s), s)));
|
||||||
foreach (var n in nodes.Where(node => !node.Key.StartsWith(ActorInfo.AbstractActorPrefix, StringComparison.Ordinal)))
|
foreach (var n in nodes.Where(node => !node.Key.StartsWith(ActorInfo.AbstractActorPrefix, StringComparison.Ordinal)))
|
||||||
modData.SpriteSequenceLoader.ParseSequences(modData, ts, sc, n);
|
modData.SpriteSequenceLoader.ParseSequences(modData, ts, sc, n);
|
||||||
|
|||||||
@@ -79,8 +79,16 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
frame.Size.Width);
|
frame.Size.Width);
|
||||||
}
|
}
|
||||||
|
|
||||||
var png = new Png(pngData, frameSize.Width, frameSize.Height, palColors);
|
if (frame.Type == SpriteFrameType.BGRA)
|
||||||
png.Save("{0}-{1:D4}.png".F(prefix, count++));
|
{
|
||||||
|
var png = new Png(pngData, frameSize.Width, frameSize.Height);
|
||||||
|
png.Save("{0}-{1:D4}.png".F(prefix, count++));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var png = new Png(pngData, frameSize.Width, frameSize.Height, palColors);
|
||||||
|
png.Save("{0}-{1:D4}.png".F(prefix, count++));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Saved {0}-[0..{1}].png", prefix, count - 1);
|
Console.WriteLine("Saved {0}-[0..{1}].png", prefix, count - 1);
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
sequences.Preload();
|
sequences.Preload();
|
||||||
|
|
||||||
var count = 0;
|
var count = 0;
|
||||||
var sb = sequences.SpriteCache.SheetBuilder;
|
|
||||||
|
var sb = sequences.SpriteCache.SheetBuilders[SpriteFrameType.Indexed];
|
||||||
foreach (var s in sb.AllSheets)
|
foreach (var s in sb.AllSheets)
|
||||||
{
|
{
|
||||||
var max = s == sb.Current ? (int)sb.CurrentChannel + 1 : 4;
|
var max = s == sb.Current ? (int)sb.CurrentChannel + 1 : 4;
|
||||||
@@ -52,6 +53,10 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
s.AsPng((TextureChannel)ChannelMasks[i], palette).Save("{0}.png".F(count++));
|
s.AsPng((TextureChannel)ChannelMasks[i], palette).Save("{0}.png".F(count++));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sb = sequences.SpriteCache.SheetBuilders[SpriteFrameType.BGRA];
|
||||||
|
foreach (var s in sb.AllSheets)
|
||||||
|
s.AsPng().Save("{0}.png".F(count++));
|
||||||
|
|
||||||
Console.WriteLine("Saved [0..{0}].png", count - 1);
|
Console.WriteLine("Saved [0..{0}].png", count - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace OpenRA.Mods.D2k.SpriteLoaders
|
|||||||
{
|
{
|
||||||
class R8Frame : ISpriteFrame
|
class R8Frame : ISpriteFrame
|
||||||
{
|
{
|
||||||
|
public SpriteFrameType Type { get; set; }
|
||||||
public Size Size { get; private set; }
|
public Size Size { get; private set; }
|
||||||
public Size FrameSize { get; private set; }
|
public Size FrameSize { get; private set; }
|
||||||
public float2 Offset { get; private set; }
|
public float2 Offset { get; private set; }
|
||||||
|
|||||||
Reference in New Issue
Block a user