Define a consistent interface for sprite loading. Fixes #4176.
This commit is contained in:
@@ -8,8 +8,10 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
|
using System.Linq;
|
||||||
using OpenRA.FileFormats;
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
@@ -17,11 +19,11 @@ namespace OpenRA.Editor
|
|||||||
{
|
{
|
||||||
static class RenderUtils
|
static class RenderUtils
|
||||||
{
|
{
|
||||||
static Bitmap RenderShp(ShpReader shp, Palette p)
|
static Bitmap RenderShp(ISpriteSource shp, Palette p)
|
||||||
{
|
{
|
||||||
var frame = shp[0];
|
var frame = shp.Frames.First();
|
||||||
|
|
||||||
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
|
var bitmap = new Bitmap(frame.Size.Width, frame.Size.Height, PixelFormat.Format8bppIndexed);
|
||||||
|
|
||||||
bitmap.Palette = p.AsSystemPalette();
|
bitmap.Palette = p.AsSystemPalette();
|
||||||
|
|
||||||
@@ -33,9 +35,9 @@ namespace OpenRA.Editor
|
|||||||
byte* q = (byte*)data.Scan0.ToPointer();
|
byte* q = (byte*)data.Scan0.ToPointer();
|
||||||
var stride2 = data.Stride;
|
var stride2 = data.Stride;
|
||||||
|
|
||||||
for (var i = 0; i < shp.Width; i++)
|
for (var i = 0; i < frame.Size.Width; i++)
|
||||||
for (var j = 0; j < shp.Height; j++)
|
for (var j = 0; j < frame.Size.Height; j++)
|
||||||
q[j * stride2 + i] = frame.Image[i + shp.Width * j];
|
q[j * stride2 + i] = frame.Data[i + frame.Size.Width * j];
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap.UnlockBits(data);
|
bitmap.UnlockBits(data);
|
||||||
@@ -78,10 +80,11 @@ namespace OpenRA.Editor
|
|||||||
var image = info.SpriteNames[0];
|
var image = info.SpriteNames[0];
|
||||||
using (var s = FileSystem.OpenWithExts(image, exts))
|
using (var s = FileSystem.OpenWithExts(image, exts))
|
||||||
{
|
{
|
||||||
var shp = new ShpReader(s);
|
// TODO: Do this properly
|
||||||
var frame = shp[shp.ImageCount - 1];
|
var shp = new ShpReader(s) as ISpriteSource;
|
||||||
|
var frame = shp.Frames.Last();
|
||||||
|
|
||||||
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed);
|
var bitmap = new Bitmap(frame.Size.Width, frame.Size.Height, PixelFormat.Format8bppIndexed);
|
||||||
bitmap.Palette = p.AsSystemPalette();
|
bitmap.Palette = p.AsSystemPalette();
|
||||||
var data = bitmap.LockBits(bitmap.Bounds(),
|
var data = bitmap.LockBits(bitmap.Bounds(),
|
||||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||||
@@ -91,13 +94,13 @@ namespace OpenRA.Editor
|
|||||||
byte* q = (byte*)data.Scan0.ToPointer();
|
byte* q = (byte*)data.Scan0.ToPointer();
|
||||||
var stride = data.Stride;
|
var stride = data.Stride;
|
||||||
|
|
||||||
for (var i = 0; i < shp.Width; i++)
|
for (var i = 0; i < frame.Size.Width; i++)
|
||||||
for (var j = 0; j < shp.Height; j++)
|
for (var j = 0; j < frame.Size.Height; j++)
|
||||||
q[j * stride + i] = frame.Image[i + shp.Width * j];
|
q[j * stride + i] = frame.Data[i + frame.Size.Width * j];
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap.UnlockBits(data);
|
bitmap.UnlockBits(data);
|
||||||
return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 };
|
return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.Frames.Count() - 1 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,17 +12,16 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace OpenRA.FileFormats
|
namespace OpenRA.FileFormats
|
||||||
{
|
{
|
||||||
public class R8Image
|
class R8Image : ISpriteFrame
|
||||||
{
|
{
|
||||||
public readonly Size Size;
|
public Size Size { get; private set; }
|
||||||
public readonly int2 Offset;
|
public Size FrameSize { get; private set; }
|
||||||
public readonly byte[] Image;
|
public float2 Offset { get; private set; }
|
||||||
|
public byte[] Data { get; set; }
|
||||||
// Legacy variable. Can be removed when the utility command is made sensible.
|
|
||||||
public readonly Size FrameSize;
|
|
||||||
|
|
||||||
public R8Image(Stream s)
|
public R8Image(Stream s)
|
||||||
{
|
{
|
||||||
@@ -52,7 +51,7 @@ namespace OpenRA.FileFormats
|
|||||||
// Skip alignment byte
|
// Skip alignment byte
|
||||||
s.ReadUInt8();
|
s.ReadUInt8();
|
||||||
|
|
||||||
Image = s.ReadBytes(width*height);
|
Data = s.ReadBytes(width*height);
|
||||||
|
|
||||||
// Ignore palette
|
// Ignore palette
|
||||||
if (type == 1 && paletteOffset != 0)
|
if (type == 1 && paletteOffset != 0)
|
||||||
@@ -60,33 +59,19 @@ namespace OpenRA.FileFormats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class R8Reader : IEnumerable<R8Image>
|
public class R8Reader : ISpriteSource
|
||||||
{
|
{
|
||||||
readonly List<R8Image> headers = new List<R8Image>();
|
readonly List<R8Image> frames = new List<R8Image>();
|
||||||
|
public IEnumerable<ISpriteFrame> Frames { get { return frames.Cast<ISpriteFrame>(); } }
|
||||||
|
|
||||||
public readonly int Frames;
|
public readonly int ImageCount;
|
||||||
public R8Reader(Stream stream)
|
public R8Reader(Stream stream)
|
||||||
{
|
{
|
||||||
while (stream.Position < stream.Length)
|
while (stream.Position < stream.Length)
|
||||||
{
|
{
|
||||||
headers.Add(new R8Image(stream));
|
frames.Add(new R8Image(stream));
|
||||||
Frames++;
|
ImageCount++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public R8Image this[int index]
|
|
||||||
{
|
|
||||||
get { return headers[index]; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<R8Image> GetEnumerator()
|
|
||||||
{
|
|
||||||
return headers.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,23 +15,28 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace OpenRA.FileFormats
|
namespace OpenRA.FileFormats
|
||||||
{
|
{
|
||||||
public class ImageHeader
|
class ImageHeader : ISpriteFrame
|
||||||
{
|
{
|
||||||
public uint Offset;
|
public Size Size { get; private set; }
|
||||||
|
public Size FrameSize { get { return Size; } }
|
||||||
|
public float2 Offset { get { return float2.Zero; } }
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
|
||||||
|
public uint FileOffset;
|
||||||
public Format Format;
|
public Format Format;
|
||||||
|
|
||||||
public uint RefOffset;
|
public uint RefOffset;
|
||||||
public Format RefFormat;
|
public Format RefFormat;
|
||||||
public ImageHeader RefImage;
|
public ImageHeader RefImage;
|
||||||
|
|
||||||
public byte[] Image;
|
// Used by ShpWriter
|
||||||
|
|
||||||
public ImageHeader() { }
|
public ImageHeader() { }
|
||||||
|
|
||||||
public ImageHeader( BinaryReader reader )
|
public ImageHeader(BinaryReader reader, Size size)
|
||||||
{
|
{
|
||||||
var data = reader.ReadUInt32();
|
var data = reader.ReadUInt32();
|
||||||
Offset = data & 0xffffff;
|
Size = size;
|
||||||
|
FileOffset = data & 0xffffff;
|
||||||
Format = (Format)(data >> 24);
|
Format = (Format)(data >> 24);
|
||||||
|
|
||||||
RefOffset = reader.ReadUInt16();
|
RefOffset = reader.ReadUInt16();
|
||||||
@@ -42,7 +47,7 @@ namespace OpenRA.FileFormats
|
|||||||
|
|
||||||
public void WriteTo(BinaryWriter writer)
|
public void WriteTo(BinaryWriter writer)
|
||||||
{
|
{
|
||||||
writer.Write(Offset | ((uint)Format << 24));
|
writer.Write(FileOffset | ((uint)Format << 24));
|
||||||
writer.Write((ushort)RefOffset);
|
writer.Write((ushort)RefOffset);
|
||||||
writer.Write((ushort)RefFormat);
|
writer.Write((ushort)RefFormat);
|
||||||
}
|
}
|
||||||
@@ -50,7 +55,7 @@ namespace OpenRA.FileFormats
|
|||||||
|
|
||||||
public enum Format { Format20 = 0x20, Format40 = 0x40, Format80 = 0x80 }
|
public enum Format { Format20 = 0x20, Format40 = 0x40, Format80 = 0x80 }
|
||||||
|
|
||||||
public class ShpReader
|
public class ShpReader : ISpriteSource
|
||||||
{
|
{
|
||||||
public readonly int ImageCount;
|
public readonly int ImageCount;
|
||||||
public readonly ushort Width;
|
public readonly ushort Width;
|
||||||
@@ -59,6 +64,7 @@ namespace OpenRA.FileFormats
|
|||||||
public Size Size { get { return new Size(Width, Height); } }
|
public Size Size { get { return new Size(Width, Height); } }
|
||||||
|
|
||||||
readonly List<ImageHeader> headers = new List<ImageHeader>();
|
readonly List<ImageHeader> headers = new List<ImageHeader>();
|
||||||
|
public IEnumerable<ISpriteFrame> Frames { get { return headers.Cast<ISpriteFrame>(); } }
|
||||||
|
|
||||||
int recurseDepth = 0;
|
int recurseDepth = 0;
|
||||||
|
|
||||||
@@ -73,13 +79,14 @@ namespace OpenRA.FileFormats
|
|||||||
Height = reader.ReadUInt16();
|
Height = reader.ReadUInt16();
|
||||||
reader.ReadUInt32();
|
reader.ReadUInt32();
|
||||||
|
|
||||||
|
var size = new Size(Width, Height);
|
||||||
for (int i = 0 ; i < ImageCount ; i++)
|
for (int i = 0 ; i < ImageCount ; i++)
|
||||||
headers.Add(new ImageHeader(reader));
|
headers.Add(new ImageHeader(reader, size));
|
||||||
|
|
||||||
new ImageHeader(reader); // end-of-file header
|
new ImageHeader(reader, size); // end-of-file header
|
||||||
new ImageHeader(reader); // all-zeroes header
|
new ImageHeader(reader, size); // all-zeroes header
|
||||||
|
|
||||||
var offsets = headers.ToDictionary(h => h.Offset, h =>h);
|
var offsets = headers.ToDictionary(h => h.FileOffset, h =>h);
|
||||||
|
|
||||||
for (int i = 0 ; i < ImageCount ; i++)
|
for (int i = 0 ; i < ImageCount ; i++)
|
||||||
{
|
{
|
||||||
@@ -89,7 +96,7 @@ namespace OpenRA.FileFormats
|
|||||||
|
|
||||||
else if (h.Format == Format.Format40)
|
else if (h.Format == Format.Format40)
|
||||||
if (!offsets.TryGetValue(h.RefOffset, out h.RefImage))
|
if (!offsets.TryGetValue(h.RefOffset, out h.RefImage))
|
||||||
throw new InvalidDataException("Reference doesnt point to image data {0}->{1}".F(h.Offset, h.RefOffset));
|
throw new InvalidDataException("Reference doesnt point to image data {0}->{1}".F(h.FileOffset, h.RefOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ImageHeader h in headers)
|
foreach (ImageHeader h in headers)
|
||||||
@@ -97,11 +104,6 @@ namespace OpenRA.FileFormats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageHeader this[int index]
|
|
||||||
{
|
|
||||||
get { return headers[index]; }
|
|
||||||
}
|
|
||||||
|
|
||||||
void Decompress(Stream stream, ImageHeader h)
|
void Decompress(Stream stream, ImageHeader h)
|
||||||
{
|
{
|
||||||
if (recurseDepth > ImageCount)
|
if (recurseDepth > ImageCount)
|
||||||
@@ -112,22 +114,22 @@ namespace OpenRA.FileFormats
|
|||||||
case Format.Format20:
|
case Format.Format20:
|
||||||
case Format.Format40:
|
case Format.Format40:
|
||||||
{
|
{
|
||||||
if (h.RefImage.Image == null)
|
if (h.RefImage.Data == null)
|
||||||
{
|
{
|
||||||
++recurseDepth;
|
++recurseDepth;
|
||||||
Decompress(stream, h.RefImage);
|
Decompress(stream, h.RefImage);
|
||||||
--recurseDepth;
|
--recurseDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
h.Image = CopyImageData(h.RefImage.Image);
|
h.Data = CopyImageData(h.RefImage.Data);
|
||||||
Format40.DecodeInto(ReadCompressedData(stream, h), h.Image);
|
Format40.DecodeInto(ReadCompressedData(stream, h), h.Data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Format.Format80:
|
case Format.Format80:
|
||||||
{
|
{
|
||||||
var imageBytes = new byte[Width * Height];
|
var imageBytes = new byte[Width * Height];
|
||||||
Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes);
|
Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes);
|
||||||
h.Image = imageBytes;
|
h.Data = imageBytes;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -137,7 +139,7 @@ namespace OpenRA.FileFormats
|
|||||||
|
|
||||||
static byte[] ReadCompressedData(Stream stream, ImageHeader h)
|
static byte[] ReadCompressedData(Stream stream, ImageHeader h)
|
||||||
{
|
{
|
||||||
stream.Position = h.Offset;
|
stream.Position = h.FileOffset;
|
||||||
// TODO: Actually, far too big. There's no length field with the correct length though :(
|
// TODO: Actually, far too big. There's no length field with the correct length though :(
|
||||||
var compressedLength = (int)(stream.Length - stream.Position);
|
var compressedLength = (int)(stream.Length - stream.Position);
|
||||||
|
|
||||||
@@ -156,12 +158,45 @@ namespace OpenRA.FileFormats
|
|||||||
return imageData;
|
return imageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<ImageHeader> Frames { get { return headers; } }
|
|
||||||
|
|
||||||
public static ShpReader Load(string filename)
|
public static ShpReader Load(string filename)
|
||||||
{
|
{
|
||||||
using (var s = File.OpenRead(filename))
|
using (var s = File.OpenRead(filename))
|
||||||
return new ShpReader(s);
|
return new ShpReader(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Write(Stream s, int width, int height, IEnumerable<byte[]> frames)
|
||||||
|
{
|
||||||
|
var compressedFrames = frames.Select(f => Format80.Encode(f)).ToArray();
|
||||||
|
|
||||||
|
// note: end-of-file and all-zeroes headers
|
||||||
|
var dataOffset = 14 + (compressedFrames.Length + 2) * ImageHeader.SizeOnDisk;
|
||||||
|
|
||||||
|
using (var bw = new BinaryWriter(s))
|
||||||
|
{
|
||||||
|
bw.Write((ushort)compressedFrames.Length);
|
||||||
|
bw.Write((ushort)0); // unused
|
||||||
|
bw.Write((ushort)0); // unused
|
||||||
|
bw.Write((ushort)width);
|
||||||
|
bw.Write((ushort)height);
|
||||||
|
bw.Write((uint)0); // unused
|
||||||
|
|
||||||
|
foreach (var f in compressedFrames)
|
||||||
|
{
|
||||||
|
var ih = new ImageHeader { Format = Format.Format80, FileOffset = (uint)dataOffset };
|
||||||
|
dataOffset += f.Length;
|
||||||
|
|
||||||
|
ih.WriteTo(bw);
|
||||||
|
}
|
||||||
|
|
||||||
|
var eof = new ImageHeader { FileOffset = (uint)dataOffset };
|
||||||
|
eof.WriteTo(bw);
|
||||||
|
|
||||||
|
var allZeroes = new ImageHeader { };
|
||||||
|
allZeroes.WriteTo(bw);
|
||||||
|
|
||||||
|
foreach (var f in compressedFrames)
|
||||||
|
bw.Write(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,17 +15,17 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace OpenRA.FileFormats
|
namespace OpenRA.FileFormats
|
||||||
{
|
{
|
||||||
public class TSImageHeader
|
class FrameHeader : ISpriteFrame
|
||||||
{
|
{
|
||||||
public readonly Size Size;
|
public Size Size { get; private set; }
|
||||||
public readonly float2 Offset;
|
public Size FrameSize { get; private set; }
|
||||||
|
public float2 Offset { get; private set; }
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
|
||||||
public readonly uint FileOffset;
|
public readonly uint FileOffset;
|
||||||
public readonly byte Format;
|
public readonly byte Format;
|
||||||
|
|
||||||
public byte[] Image;
|
public FrameHeader(Stream stream, Size frameSize)
|
||||||
|
|
||||||
public TSImageHeader(Stream stream, Size frameSize)
|
|
||||||
{
|
{
|
||||||
var x = stream.ReadUInt16();
|
var x = stream.ReadUInt16();
|
||||||
var y = stream.ReadUInt16();
|
var y = stream.ReadUInt16();
|
||||||
@@ -34,6 +34,7 @@ namespace OpenRA.FileFormats
|
|||||||
|
|
||||||
Offset = new float2(x + 0.5f * (width - frameSize.Width), y + 0.5f * (height - frameSize.Height));
|
Offset = new float2(x + 0.5f * (width - frameSize.Width), y + 0.5f * (height - frameSize.Height));
|
||||||
Size = new Size(width, height);
|
Size = new Size(width, height);
|
||||||
|
FrameSize = frameSize;
|
||||||
|
|
||||||
Format = stream.ReadUInt8();
|
Format = stream.ReadUInt8();
|
||||||
stream.Position += 11;
|
stream.Position += 11;
|
||||||
@@ -41,13 +42,13 @@ namespace OpenRA.FileFormats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ShpTSReader
|
public class ShpTSReader : ISpriteSource
|
||||||
{
|
{
|
||||||
public readonly int ImageCount;
|
public readonly int ImageCount;
|
||||||
public readonly Size Size;
|
public readonly Size Size;
|
||||||
|
|
||||||
readonly List<TSImageHeader> frames = new List<TSImageHeader>();
|
readonly List<FrameHeader> frames = new List<FrameHeader>();
|
||||||
public IEnumerable<TSImageHeader> Frames { get { return frames; } }
|
public IEnumerable<ISpriteFrame> Frames { get { return frames.Cast<ISpriteFrame>(); } }
|
||||||
|
|
||||||
public ShpTSReader(Stream stream)
|
public ShpTSReader(Stream stream)
|
||||||
{
|
{
|
||||||
@@ -58,7 +59,7 @@ namespace OpenRA.FileFormats
|
|||||||
ImageCount = stream.ReadUInt16();
|
ImageCount = stream.ReadUInt16();
|
||||||
|
|
||||||
for (var i = 0; i < ImageCount; i++)
|
for (var i = 0; i < ImageCount; i++)
|
||||||
frames.Add(new TSImageHeader(stream, Size));
|
frames.Add(new FrameHeader(stream, Size));
|
||||||
|
|
||||||
for (var i = 0; i < ImageCount; i++)
|
for (var i = 0; i < ImageCount; i++)
|
||||||
{
|
{
|
||||||
@@ -70,23 +71,23 @@ namespace OpenRA.FileFormats
|
|||||||
|
|
||||||
// Uncompressed
|
// Uncompressed
|
||||||
if (f.Format == 1 || f.Format == 0)
|
if (f.Format == 1 || f.Format == 0)
|
||||||
f.Image = stream.ReadBytes(f.Size.Width * f.Size.Height);
|
f.Data = stream.ReadBytes(f.Size.Width * f.Size.Height);
|
||||||
|
|
||||||
// Uncompressed scanlines
|
// Uncompressed scanlines
|
||||||
else if (f.Format == 2)
|
else if (f.Format == 2)
|
||||||
{
|
{
|
||||||
f.Image = new byte[f.Size.Width * f.Size.Height];
|
f.Data = new byte[f.Size.Width * f.Size.Height];
|
||||||
for (var j = 0; j < f.Size.Height; j++)
|
for (var j = 0; j < f.Size.Height; j++)
|
||||||
{
|
{
|
||||||
var length = stream.ReadUInt16() - 2;
|
var length = stream.ReadUInt16() - 2;
|
||||||
stream.Read(f.Image, f.Size.Width * j, length);
|
stream.Read(f.Data, f.Size.Width * j, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RLE-zero compressed scanlines
|
// RLE-zero compressed scanlines
|
||||||
else if (f.Format == 3)
|
else if (f.Format == 3)
|
||||||
{
|
{
|
||||||
f.Image = new byte[f.Size.Width * f.Size.Height];
|
f.Data = new byte[f.Size.Width * f.Size.Height];
|
||||||
|
|
||||||
for (var j = 0; j < f.Size.Height; j++)
|
for (var j = 0; j < f.Size.Height; j++)
|
||||||
{
|
{
|
||||||
@@ -103,7 +104,7 @@ namespace OpenRA.FileFormats
|
|||||||
length--;
|
length--;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
f.Image[k++] = b;
|
f.Data[k++] = b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2011 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. For more information,
|
|
||||||
* see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace OpenRA.FileFormats.Graphics
|
|
||||||
{
|
|
||||||
// format80-only SHP writer
|
|
||||||
|
|
||||||
public static class ShpWriter
|
|
||||||
{
|
|
||||||
public static void Write(Stream s, int width, int height, IEnumerable<byte[]> frames)
|
|
||||||
{
|
|
||||||
var compressedFrames = frames.Select(f => Format80.Encode(f)).ToArray();
|
|
||||||
|
|
||||||
// note: end-of-file and all-zeroes headers
|
|
||||||
var dataOffset = 14 + (compressedFrames.Length + 2) * ImageHeader.SizeOnDisk;
|
|
||||||
|
|
||||||
using (var bw = new BinaryWriter(s))
|
|
||||||
{
|
|
||||||
bw.Write((ushort)compressedFrames.Length);
|
|
||||||
bw.Write((ushort)0); // unused
|
|
||||||
bw.Write((ushort)0); // unused
|
|
||||||
bw.Write((ushort)width);
|
|
||||||
bw.Write((ushort)height);
|
|
||||||
bw.Write((uint)0); // unused
|
|
||||||
|
|
||||||
foreach (var f in compressedFrames)
|
|
||||||
{
|
|
||||||
var ih = new ImageHeader { Format = Format.Format80, Offset = (uint)dataOffset };
|
|
||||||
dataOffset += f.Length;
|
|
||||||
|
|
||||||
ih.WriteTo(bw);
|
|
||||||
}
|
|
||||||
|
|
||||||
var eof = new ImageHeader { Offset = (uint)dataOffset };
|
|
||||||
eof.WriteTo(bw);
|
|
||||||
|
|
||||||
var allZeroes = new ImageHeader { };
|
|
||||||
allZeroes.WriteTo(bw);
|
|
||||||
|
|
||||||
foreach (var f in compressedFrames)
|
|
||||||
bw.Write(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
188
OpenRA.FileFormats/Graphics/SpriteSource.cs
Normal file
188
OpenRA.FileFormats/Graphics/SpriteSource.cs
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2011 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. For more information,
|
||||||
|
* see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace OpenRA.FileFormats
|
||||||
|
{
|
||||||
|
public interface ISpriteFrame
|
||||||
|
{
|
||||||
|
Size Size { get; }
|
||||||
|
Size FrameSize { get; }
|
||||||
|
float2 Offset { get; }
|
||||||
|
byte[] Data { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ISpriteSource
|
||||||
|
{
|
||||||
|
IEnumerable<ISpriteFrame> Frames { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SpriteType { Unknown, ShpTD, ShpTS, TmpTD, TmpRA, R8 }
|
||||||
|
public static class SpriteSource
|
||||||
|
{
|
||||||
|
static bool IsTmpRA(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
|
||||||
|
s.Position += 20;
|
||||||
|
var a = s.ReadUInt32();
|
||||||
|
s.Position += 2;
|
||||||
|
var b = s.ReadUInt16();
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return a == 0 && b == 0x2c73;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsTmpTD(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
|
||||||
|
s.Position += 16;
|
||||||
|
var a = s.ReadUInt32();
|
||||||
|
var b = s.ReadUInt32();
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return a == 0 && b == 0x0D1AFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsShpTS(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
|
||||||
|
// First word is zero
|
||||||
|
if (s.ReadUInt16() != 0)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity Check the image count
|
||||||
|
s.Position += 4;
|
||||||
|
var imageCount = s.ReadUInt16();
|
||||||
|
if (s.Position + 24 * imageCount > s.Length)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the size and format flag
|
||||||
|
// Some files define bogus frames, so loop until we find a valid one
|
||||||
|
s.Position += 4;
|
||||||
|
ushort w, h, f = 0;
|
||||||
|
byte type;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
w = s.ReadUInt16();
|
||||||
|
h = s.ReadUInt16();
|
||||||
|
type = s.ReadUInt8();
|
||||||
|
}
|
||||||
|
while (w == 0 && h == 0 && f++ < imageCount);
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return type < 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsShpTD(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
|
||||||
|
// First word is the image count
|
||||||
|
var imageCount = s.ReadUInt16();
|
||||||
|
if (imageCount == 0)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last offset should point to the end of file
|
||||||
|
var finalOffset = start + 14 + 8 * imageCount;
|
||||||
|
if (finalOffset > s.Length)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Position = finalOffset;
|
||||||
|
var eof = s.ReadUInt32();
|
||||||
|
if (eof != s.Length)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the format flag on the first frame
|
||||||
|
s.Position = start + 17;
|
||||||
|
var b = s.ReadUInt8();
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return b == 0x20 || b == 0x40 || b == 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsR8(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
|
||||||
|
// First byte is nonzero
|
||||||
|
if (s.ReadUInt8() == 0)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the format of the first frame
|
||||||
|
s.Position = start + 25;
|
||||||
|
var d = s.ReadUInt8();
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return d == 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpriteType DetectSpriteType(Stream s)
|
||||||
|
{
|
||||||
|
if (IsShpTD(s))
|
||||||
|
return SpriteType.ShpTD;
|
||||||
|
|
||||||
|
if (IsShpTS(s))
|
||||||
|
return SpriteType.ShpTS;
|
||||||
|
|
||||||
|
if (IsR8(s))
|
||||||
|
return SpriteType.R8;
|
||||||
|
|
||||||
|
if (IsTmpRA(s))
|
||||||
|
return SpriteType.TmpRA;
|
||||||
|
|
||||||
|
if (IsTmpTD(s))
|
||||||
|
return SpriteType.TmpTD;
|
||||||
|
|
||||||
|
return SpriteType.Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ISpriteSource LoadSpriteSource(Stream s, string filename)
|
||||||
|
{
|
||||||
|
var type = DetectSpriteType(s);
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case SpriteType.ShpTD:
|
||||||
|
return new ShpReader(s);
|
||||||
|
case SpriteType.ShpTS:
|
||||||
|
return new ShpTSReader(s);
|
||||||
|
case SpriteType.R8:
|
||||||
|
return new R8Reader(s);
|
||||||
|
case SpriteType.Unknown:
|
||||||
|
default:
|
||||||
|
throw new InvalidDataException(filename + " is not a valid sprite file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,14 +21,13 @@ namespace OpenRA.FileFormats
|
|||||||
Dictionary<ushort, List<byte[]>> templates;
|
Dictionary<ushort, List<byte[]>> templates;
|
||||||
public Size TileSize;
|
public Size TileSize;
|
||||||
|
|
||||||
List<byte[]> LoadTemplate(string filename, string[] exts, Cache<string, R8Reader> r8cache, int[] frames)
|
List<byte[]> LoadTemplate(string filename, string[] exts, Cache<string, ISpriteFrame[]> r8cache, int[] frames)
|
||||||
{
|
{
|
||||||
if (exts.Contains(".R8") && FileSystem.Exists(filename + ".R8"))
|
if (exts.Contains(".R8") && FileSystem.Exists(filename + ".R8"))
|
||||||
{
|
{
|
||||||
var data = new List<byte[]>();
|
var data = new List<byte[]>();
|
||||||
|
|
||||||
foreach (var f in frames)
|
foreach (var f in frames)
|
||||||
data.Add(f >= 0 ? r8cache[filename][f].Image : null);
|
data.Add(f >= 0 ? r8cache[filename][f].Data : null);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@@ -43,7 +42,7 @@ namespace OpenRA.FileFormats
|
|||||||
this.TileSize = tileSize;
|
this.TileSize = tileSize;
|
||||||
|
|
||||||
templates = new Dictionary<ushort, List<byte[]>>();
|
templates = new Dictionary<ushort, List<byte[]>>();
|
||||||
var r8cache = new Cache<string, R8Reader>(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8")));
|
var r8cache = new Cache<string, ISpriteFrame[]>(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8")).Frames.ToArray());
|
||||||
foreach (var t in TileSet.Templates)
|
foreach (var t in TileSet.Templates)
|
||||||
templates.Add(t.Key, LoadTemplate(t.Value.Image, tileset.Extensions, r8cache, t.Value.Frames));
|
templates.Add(t.Key, LoadTemplate(t.Value.Image, tileset.Extensions, r8cache, t.Value.Frames));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,6 @@
|
|||||||
<Compile Include="Graphics\IInputHandler.cs" />
|
<Compile Include="Graphics\IInputHandler.cs" />
|
||||||
<Compile Include="Graphics\PngLoader.cs" />
|
<Compile Include="Graphics\PngLoader.cs" />
|
||||||
<Compile Include="Graphics\ShpReader.cs" />
|
<Compile Include="Graphics\ShpReader.cs" />
|
||||||
<Compile Include="Graphics\ShpWriter.cs" />
|
|
||||||
<Compile Include="Graphics\Vertex.cs" />
|
<Compile Include="Graphics\Vertex.cs" />
|
||||||
<Compile Include="Graphics\VqaReader.cs" />
|
<Compile Include="Graphics\VqaReader.cs" />
|
||||||
<Compile Include="InstallUtils.cs" />
|
<Compile Include="InstallUtils.cs" />
|
||||||
@@ -153,6 +152,7 @@
|
|||||||
<Compile Include="FileSystem\MixFile.cs" />
|
<Compile Include="FileSystem\MixFile.cs" />
|
||||||
<Compile Include="FileSystem\ZipFile.cs" />
|
<Compile Include="FileSystem\ZipFile.cs" />
|
||||||
<Compile Include="FileSystem\D2kSoundResources.cs" />
|
<Compile Include="FileSystem\D2kSoundResources.cs" />
|
||||||
|
<Compile Include="Graphics\SpriteSource.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.FileFormats.Graphics;
|
using OpenRA.FileFormats.Graphics;
|
||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
@@ -52,6 +53,7 @@ namespace OpenRA.Graphics
|
|||||||
this.allocateSheet = allocateSheet;
|
this.allocateSheet = allocateSheet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Sprite Add(ISpriteFrame frame) { return Add(frame.Data, frame.Size, frame.Offset); }
|
||||||
public Sprite Add(byte[] src, Size size) { return Add(src, size, float2.Zero); }
|
public Sprite Add(byte[] src, Size size) { return Add(src, size, float2.Zero); }
|
||||||
public Sprite Add(byte[] src, Size size, float2 spriteOffset)
|
public Sprite Add(byte[] src, Size size, float2 spriteOffset)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,41 +16,25 @@ namespace OpenRA.Graphics
|
|||||||
{
|
{
|
||||||
public class SpriteLoader
|
public class SpriteLoader
|
||||||
{
|
{
|
||||||
|
readonly SheetBuilder SheetBuilder;
|
||||||
|
readonly Cache<string, Sprite[]> sprites;
|
||||||
|
readonly string[] exts;
|
||||||
|
|
||||||
public SpriteLoader(string[] exts, SheetBuilder sheetBuilder)
|
public SpriteLoader(string[] exts, SheetBuilder sheetBuilder)
|
||||||
{
|
{
|
||||||
SheetBuilder = sheetBuilder;
|
SheetBuilder = sheetBuilder;
|
||||||
|
|
||||||
// Include extension-less version
|
// Include extension-less version
|
||||||
this.exts = exts.Append("").ToArray();
|
this.exts = exts.Append("").ToArray();
|
||||||
sprites = new Cache<string, Sprite[]>(LoadSprites);
|
sprites = new Cache<string, Sprite[]>(CacheSpriteFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly SheetBuilder SheetBuilder;
|
Sprite[] CacheSpriteFrames(string filename)
|
||||||
readonly Cache<string, Sprite[]> sprites;
|
|
||||||
readonly string[] exts;
|
|
||||||
|
|
||||||
Sprite[] LoadSprites(string filename)
|
|
||||||
{
|
{
|
||||||
// TODO: Cleanly abstract file type detection
|
var stream = FileSystem.OpenWithExts(filename, exts);
|
||||||
if (filename.ToLower().EndsWith("r8"))
|
return SpriteSource.LoadSpriteSource(stream, filename).Frames
|
||||||
{
|
.Select(a => SheetBuilder.Add(a))
|
||||||
var r8 = new R8Reader(FileSystem.OpenWithExts(filename, exts));
|
.ToArray();
|
||||||
return r8.Select(a => SheetBuilder.Add(a.Image, a.Size, a.Offset)).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
BinaryReader reader = new BinaryReader(FileSystem.OpenWithExts(filename, exts));
|
|
||||||
|
|
||||||
var ImageCount = reader.ReadUInt16();
|
|
||||||
if (ImageCount == 0)
|
|
||||||
{
|
|
||||||
var shp = new ShpTSReader(FileSystem.OpenWithExts(filename, exts));
|
|
||||||
return shp.Frames.Select(a => SheetBuilder.Add(a.Image, a.Size, a.Offset)).ToArray();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
|
|
||||||
return shp.Frames.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }
|
public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace OpenRA.Graphics
|
|||||||
Dictionary<ushort, Sprite[]> templates;
|
Dictionary<ushort, Sprite[]> templates;
|
||||||
Sprite missingTile;
|
Sprite missingTile;
|
||||||
|
|
||||||
Sprite[] LoadTemplate(string filename, string[] exts, Cache<string, R8Reader> r8Cache, int[] frames)
|
Sprite[] LoadTemplate(string filename, string[] exts, Cache<string, ISpriteFrame[]> r8Cache, int[] frames)
|
||||||
{
|
{
|
||||||
if (exts.Contains(".R8") && FileSystem.Exists(filename+".R8"))
|
if (exts.Contains(".R8") && FileSystem.Exists(filename+".R8"))
|
||||||
{
|
{
|
||||||
@@ -32,7 +32,7 @@ namespace OpenRA.Graphics
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
var image = r8Cache[filename][f];
|
var image = r8Cache[filename][f];
|
||||||
return sheetBuilder.Add(image.Image, new Size(image.Size.Width, image.Size.Height));
|
return sheetBuilder.Add(image.Data, new Size(image.Size.Width, image.Size.Height));
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ namespace OpenRA.Graphics
|
|||||||
return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize));
|
return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize));
|
||||||
};
|
};
|
||||||
|
|
||||||
var r8Cache = new Cache<string, R8Reader>(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8")));
|
var r8Cache = new Cache<string, ISpriteFrame[]>(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8")).Frames.ToArray());
|
||||||
templates = new Dictionary<ushort, Sprite[]>();
|
templates = new Dictionary<ushort, Sprite[]>();
|
||||||
sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate);
|
sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate);
|
||||||
foreach (var t in tileset.Templates)
|
foreach (var t in tileset.Templates)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ namespace OpenRA.Utility
|
|||||||
throw new InvalidOperationException("Bogus width; not a whole number of frames");
|
throw new InvalidOperationException("Bogus width; not a whole number of frames");
|
||||||
|
|
||||||
using (var destStream = File.Create(dest))
|
using (var destStream = File.Create(dest))
|
||||||
ShpWriter.Write(destStream, width, srcImage.Height,
|
ShpReader.Write(destStream, width, srcImage.Height,
|
||||||
srcImage.ToFrames(width));
|
srcImage.ToFrames(width));
|
||||||
|
|
||||||
Console.WriteLine(dest + " saved.");
|
Console.WriteLine(dest + " saved.");
|
||||||
@@ -104,7 +104,7 @@ namespace OpenRA.Utility
|
|||||||
PixelFormat.Format8bppIndexed);
|
PixelFormat.Format8bppIndexed);
|
||||||
|
|
||||||
for (var i = 0; i < bitmap.Height; i++)
|
for (var i = 0; i < bitmap.Height; i++)
|
||||||
Marshal.Copy(frame.Image, i * srcImage.Width,
|
Marshal.Copy(frame.Data, i * srcImage.Width,
|
||||||
new IntPtr(data.Scan0.ToInt64() + i * data.Stride), srcImage.Width);
|
new IntPtr(data.Scan0.ToInt64() + i * data.Stride), srcImage.Width);
|
||||||
|
|
||||||
x += srcImage.Width;
|
x += srcImage.Width;
|
||||||
@@ -133,12 +133,11 @@ namespace OpenRA.Utility
|
|||||||
var filename = args[5];
|
var filename = args[5];
|
||||||
var frameCount = endFrame - startFrame;
|
var frameCount = endFrame - startFrame;
|
||||||
|
|
||||||
var frame = srcImage[startFrame];
|
// TODO: this has always been a hack
|
||||||
|
var frame = srcImage.Frames.ToArray()[startFrame];
|
||||||
var bitmap = new Bitmap(frame.FrameSize.Width * frameCount, frame.FrameSize.Height, PixelFormat.Format8bppIndexed);
|
var bitmap = new Bitmap(frame.FrameSize.Width * frameCount, frame.FrameSize.Height, PixelFormat.Format8bppIndexed);
|
||||||
bitmap.Palette = palette.AsSystemPalette();
|
bitmap.Palette = palette.AsSystemPalette();
|
||||||
|
|
||||||
frame = srcImage[startFrame];
|
|
||||||
|
|
||||||
if (args.Contains("--tileset"))
|
if (args.Contains("--tileset"))
|
||||||
{
|
{
|
||||||
int f = 0;
|
int f = 0;
|
||||||
@@ -152,13 +151,13 @@ namespace OpenRA.Utility
|
|||||||
if (h * 20 + w < frameCount)
|
if (h * 20 + w < frameCount)
|
||||||
{
|
{
|
||||||
Console.WriteLine(f);
|
Console.WriteLine(f);
|
||||||
frame = srcImage[f];
|
frame = srcImage.Frames.ToArray()[startFrame];
|
||||||
|
|
||||||
var data = tileset.LockBits(new Rectangle(w * frame.Size.Width, h * frame.Size.Height, frame.Size.Width, frame.Size.Height),
|
var data = tileset.LockBits(new Rectangle(w * frame.Size.Width, h * frame.Size.Height, frame.Size.Width, frame.Size.Height),
|
||||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||||
|
|
||||||
for (var i = 0; i < frame.Size.Height; i++)
|
for (var i = 0; i < frame.Size.Height; i++)
|
||||||
Marshal.Copy(frame.Image, i * frame.Size.Width,
|
Marshal.Copy(frame.Data, i * frame.Size.Width,
|
||||||
new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Size.Width);
|
new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Size.Width);
|
||||||
|
|
||||||
tileset.UnlockBits(data);
|
tileset.UnlockBits(data);
|
||||||
@@ -219,7 +218,7 @@ namespace OpenRA.Utility
|
|||||||
throw new InvalidOperationException("All the frames must be the same size to convert from Dune2 to RA");
|
throw new InvalidOperationException("All the frames must be the same size to convert from Dune2 to RA");
|
||||||
|
|
||||||
using (var destStream = File.Create(dest))
|
using (var destStream = File.Create(dest))
|
||||||
ShpWriter.Write(destStream, size.Width, size.Height,
|
ShpReader.Write(destStream, size.Width, size.Height,
|
||||||
srcImage.Select(im => im.Image));
|
srcImage.Select(im => im.Image));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,8 +299,8 @@ namespace OpenRA.Utility
|
|||||||
var srcImage = ShpReader.Load(args[3]);
|
var srcImage = ShpReader.Load(args[3]);
|
||||||
|
|
||||||
using (var destStream = File.Create(args[4]))
|
using (var destStream = File.Create(args[4]))
|
||||||
ShpWriter.Write(destStream, srcImage.Width, srcImage.Height,
|
ShpReader.Write(destStream, srcImage.Width, srcImage.Height,
|
||||||
srcImage.Frames.Select(im => im.Image.Select(px => (byte)remap[px]).ToArray()));
|
srcImage.Frames.Select(im => im.Data.Select(px => (byte)remap[px]).ToArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void TransposeShp(string[] args)
|
public static void TransposeShp(string[] args)
|
||||||
@@ -323,8 +322,8 @@ namespace OpenRA.Utility
|
|||||||
}
|
}
|
||||||
|
|
||||||
using (var destStream = File.Create(args[2]))
|
using (var destStream = File.Create(args[2]))
|
||||||
ShpWriter.Write(destStream, srcImage.Width, srcImage.Height,
|
ShpReader.Write(destStream, srcImage.Width, srcImage.Height,
|
||||||
destFrames.Select(f => f.Image));
|
destFrames.Select(f => f.Data));
|
||||||
}
|
}
|
||||||
|
|
||||||
static string FriendlyTypeName(Type t)
|
static string FriendlyTypeName(Type t)
|
||||||
|
|||||||
Reference in New Issue
Block a user