diff --git a/OpenRA.FileFormats/Graphics/R8Reader.cs b/OpenRA.FileFormats/Graphics/R8Reader.cs index f341f92cef..0ecd31c802 100644 --- a/OpenRA.FileFormats/Graphics/R8Reader.cs +++ b/OpenRA.FileFormats/Graphics/R8Reader.cs @@ -5,8 +5,6 @@ * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation. For more information, * see COPYING. - * It also incorporates parts of http://code.google.com/p/dune2000plusone - * which is licensed under the BSD 2-Clause License. */ #endregion @@ -20,102 +18,64 @@ namespace OpenRA.FileFormats { public class R8Image { - public int Width; - public int Height; + public readonly Size Size; + public readonly int2 Offset; + public readonly byte[] Image; - public byte FrameWidth; - public byte FrameHeight; + // Legacy variable. Can be removed when the utility command is made sensible. + public readonly Size FrameSize; - public int ImageHandle; - public int PaletteHandle; - - public byte[] Image; - - public int OffsetX; - public int OffsetY; - - public R8Image(Stream s, int Frame) + public R8Image(Stream s) { - var offset = s.Position; - var ID = s.ReadUInt8(); // 0 = no data, 1 = picture with palette, 2 = picture with current palette - while (ID == 0) - ID = s.ReadUInt8(); - Width = s.ReadInt32(); //Width of picture - Height = s.ReadInt32(); //Height of picture - OffsetX = s.ReadInt32(); //Offset on X axis from left border edge of virtual frame - OffsetY = s.ReadInt32(); //Offset on Y axis from top border edge of virtual frame - ImageHandle = s.ReadInt32(); // 0 = no picture - PaletteHandle = s.ReadInt32(); // 0 = no palette - var Bpp = s.ReadUInt8(); // Bits per Pixel - FrameHeight = s.ReadUInt8(); // Height of virtual frame - FrameWidth = s.ReadUInt8(); // Width of virtual frame - var Align = s.ReadUInt8(); //Alignment on even border + // Scan forward until we find some data + var type = s.ReadUInt8(); + while (type == 0) + type = s.ReadUInt8(); - Console.WriteLine("Offset: {0}",offset); - Console.WriteLine("ID: {0}",ID); - Console.WriteLine("Width: {0}",Width); - Console.WriteLine("Height: {0}",Height); - Console.WriteLine("OffsetX: {0}",OffsetX); - Console.WriteLine("OffsetY: {0}",OffsetY); - Console.WriteLine("ImageHandle: {0}",ImageHandle); - Console.WriteLine("PaletteHandle: {0}",PaletteHandle); - Console.WriteLine("Bpp: {0}",Bpp); - Console.WriteLine("FrameWidth: {0}",FrameWidth); - Console.WriteLine("FrameHeight: {0}",FrameHeight); - Console.WriteLine("Align: {0}",Align); + var width = s.ReadInt32(); + var height = s.ReadInt32(); + var x = s.ReadInt32(); + var y = s.ReadInt32(); - // Load image - if (Bpp == 8) - Image = new byte[Width*Height]; - else - throw new InvalidDataException("Error: {0} bits per pixel are not supported.".F(Bpp)); + Size = new Size(width, height); + Offset = new int2(width/2 - x, height/2 - y); + /*var imageOffset = */s.ReadInt32(); + var paletteOffset = s.ReadInt32(); + var bpp = s.ReadUInt8(); + if (bpp != 8) + throw new InvalidDataException("Error: {0} bits per pixel are not supported.".F(bpp)); - if (ID == 1 && PaletteHandle != 0) - { - // read and ignore custom palette - s.ReadInt32(); //Memory - s.ReadInt32(); //Handle + var frameHeight = s.ReadUInt8(); + var frameWidth = s.ReadUInt8(); + FrameSize = new Size(frameWidth, frameHeight); - for (int i = 0; i < Width*Height; i++) - Image[i] = s.ReadUInt8(); - for (int i = 0; i < 256; i++) - s.ReadUInt16(); - } - else if (ID == 2 && PaletteHandle != 0) // image with custom palette - { - for (int i = 0; i < Width*Height; i++) - Image[i] = s.ReadUInt8(); - } - else //standard palette or 16 Bpp - { - for (int i = 0; i < Width*Height; i++) - Image[i] = s.ReadUInt8(); - } + // Skip alignment byte + s.ReadUInt8(); + + // Ignore palette header + if (type == 1 && paletteOffset != 0) + s.Seek(8, SeekOrigin.Current); + + Image = s.ReadBytes(width*height); + + // Ignore palette data + if (type == 1 && paletteOffset != 0) + s.Seek(512, SeekOrigin.Current); } } public class R8Reader : IEnumerable { - private readonly List headers = new List(); + readonly List headers = new List(); public readonly int Frames; public R8Reader(Stream stream) { - Frames = 0; while (stream.Position < stream.Length) { - try - { - Console.WriteLine("Frame {0}: {1}",Frames, stream.Position); - headers.Add(new R8Image(stream, Frames)); - Frames++; - } - catch (Exception e) - { - Console.WriteLine(e.Message); - break; - } + headers.Add(new R8Image(stream)); + Frames++; } } diff --git a/OpenRA.Game/Graphics/SpriteLoader.cs b/OpenRA.Game/Graphics/SpriteLoader.cs index 9ada3d035e..135eb4934b 100644 --- a/OpenRA.Game/Graphics/SpriteLoader.cs +++ b/OpenRA.Game/Graphics/SpriteLoader.cs @@ -8,6 +8,7 @@ */ #endregion +using System.Drawing; using System.IO; using System.Linq; using OpenRA.FileFormats; @@ -29,6 +30,13 @@ namespace OpenRA.Graphics Sprite[] LoadSprites(string filename) { + // TODO: Cleanly abstract file type detection + if (filename.ToLower().EndsWith("r8")) + { + var r8 = new R8Reader(FileSystem.Open(filename)); + 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(); diff --git a/OpenRA.Utility/Command.cs b/OpenRA.Utility/Command.cs index 15d9611fb6..636c09e174 100644 --- a/OpenRA.Utility/Command.cs +++ b/OpenRA.Utility/Command.cs @@ -132,12 +132,9 @@ namespace OpenRA.Utility var FrameCount = endFrame - startFrame; var frame = srcImage[startFrame]; - var bitmap = new Bitmap(frame.FrameWidth * FrameCount, frame.FrameHeight, PixelFormat.Format8bppIndexed); + var bitmap = new Bitmap(frame.FrameSize.Width * FrameCount, frame.FrameSize.Height, PixelFormat.Format8bppIndexed); bitmap.Palette = palette.AsSystemPalette(); - int OffsetX = 0; - int OffsetY = 0; - int x = 0; frame = srcImage[startFrame]; @@ -150,22 +147,22 @@ namespace OpenRA.Utility for (int f = startFrame+e-1; f > endFrame; f--) { - OffsetX = frame.FrameWidth/2 - frame.Width/2; - OffsetY = frame.FrameHeight/2 - frame.Height/2; + var OffsetX = frame.FrameSize.Width/2 - frame.Size.Width/2; + var OffsetY = frame.FrameSize.Height/2 - frame.Size.Height/2; Console.WriteLine("calculated OffsetX: {0}", OffsetX); Console.WriteLine("calculated OffsetY: {0}", OffsetY); - var data = bitmap.LockBits(new Rectangle(x+OffsetX, 0+OffsetY, frame.Width, frame.Height), ImageLockMode.WriteOnly, + var data = bitmap.LockBits(new Rectangle(x+OffsetX, 0+OffsetY, frame.Size.Width, frame.Size.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); - for (var i = 0; i < frame.Height; i++) - Marshal.Copy(frame.Image, i * frame.Width, - new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Width); + for (var i = 0; i < frame.Size.Height; i++) + Marshal.Copy(frame.Image, i * frame.Size.Width, + new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Size.Width); bitmap.UnlockBits(data); - x += frame.FrameWidth; + x += frame.FrameSize.Width; frame = srcImage[f]; Console.WriteLine("f: {0}", f); @@ -183,22 +180,22 @@ namespace OpenRA.Utility for (int f = endFrame-1; f > startFrame-1; f--) { - OffsetX = frame.FrameWidth/2 - frame.OffsetX; - OffsetY = frame.FrameHeight/2 - frame.OffsetY; + var OffsetX = frame.FrameSize.Width/2 - frame.Offset.X; + var OffsetY = frame.FrameSize.Height/2 - frame.Offset.Y; Console.WriteLine("calculated OffsetX: {0}", OffsetX); Console.WriteLine("calculated OffsetY: {0}", OffsetY); - var data = bitmap.LockBits(new Rectangle(x+OffsetX, 0+OffsetY, frame.Width, frame.Height), ImageLockMode.WriteOnly, + var data = bitmap.LockBits(new Rectangle(x+OffsetX, 0+OffsetY, frame.Size.Width, frame.Size.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); - for (var i = 0; i < frame.Height; i++) - Marshal.Copy(frame.Image, i * frame.Width, - new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Width); + for (var i = 0; i < frame.Size.Height; i++) + Marshal.Copy(frame.Image, i * frame.Size.Width, + new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Size.Width); bitmap.UnlockBits(data); - x += frame.FrameWidth; + x += frame.FrameSize.Width; frame = srcImage[f]; } @@ -209,24 +206,22 @@ namespace OpenRA.Utility for (int f = endFrame-1; f > startFrame-1; f--) { - if (frame.OffsetX < 0) { frame.OffsetX = 0 - frame.OffsetX; } - if (frame.OffsetY < 0) { frame.OffsetY = 0 - frame.OffsetY; } - OffsetX = 0 + frame.OffsetX; - OffsetY = frame.FrameHeight - frame.OffsetY; + var OffsetX = Math.Abs(frame.Offset.X); + var OffsetY = frame.FrameSize.Height - Math.Abs(frame.Offset.Y); Console.WriteLine("calculated OffsetX: {0}", OffsetX); Console.WriteLine("calculated OffsetY: {0}", OffsetY); - var data = bitmap.LockBits(new Rectangle(x+OffsetX, 0+OffsetY, frame.Width, frame.Height), ImageLockMode.WriteOnly, + var data = bitmap.LockBits(new Rectangle(x+OffsetX, 0+OffsetY, frame.Size.Width, frame.Size.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); - for (var i = 0; i < frame.Height; i++) - Marshal.Copy(frame.Image, i * frame.Width, - new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Width); + for (var i = 0; i < frame.Size.Height; i++) + Marshal.Copy(frame.Image, i * frame.Size.Width, + new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Size.Width); bitmap.UnlockBits(data); - x += frame.FrameWidth; + x += frame.FrameSize.Width; frame = srcImage[f]; } @@ -240,29 +235,27 @@ namespace OpenRA.Utility frame = srcImage[f]; - if (frame.OffsetX < 0) { frame.OffsetX = 0 - frame.OffsetX; } - if (frame.OffsetY < 0) { frame.OffsetY = 0 - frame.OffsetY; } - OffsetX = 0 + frame.OffsetX; - OffsetY = frame.FrameHeight - frame.OffsetY; + var OffsetX = Math.Abs(frame.Offset.X); + var OffsetY = frame.FrameSize.Height - Math.Abs(frame.Offset.Y); Console.WriteLine("calculated OffsetX: {0}", OffsetX); Console.WriteLine("calculated OffsetY: {0}", OffsetY); - var data = bitmap.LockBits(new Rectangle(x+OffsetX, 0+OffsetY, frame.Width, frame.Height), ImageLockMode.WriteOnly, + var data = bitmap.LockBits(new Rectangle(x+OffsetX, 0+OffsetY, frame.Size.Width, frame.Size.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); - for (var i = 0; i < frame.Height; i++) - Marshal.Copy(frame.Image, i * frame.Width, - new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Width); + for (var i = 0; i < frame.Size.Height; i++) + Marshal.Copy(frame.Image, i * frame.Size.Width, + new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Size.Width); bitmap.UnlockBits(data); - x += frame.FrameWidth; + x += frame.FrameSize.Width; } } else if (args.Contains("--tileset")) { int f = 0; - var tileset = new Bitmap(frame.FrameWidth * 20, frame.FrameHeight * 40, PixelFormat.Format8bppIndexed); + var tileset = new Bitmap(frame.FrameSize.Width * 20, frame.FrameSize.Height * 40, PixelFormat.Format8bppIndexed); tileset.Palette = palette.AsSystemPalette(); for (int h = 0; h < 40; h++) @@ -274,12 +267,12 @@ namespace OpenRA.Utility Console.WriteLine(f); frame = srcImage[f]; - var data = tileset.LockBits(new Rectangle(w * frame.Width, h * frame.Height, frame.Width, frame.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); - for (var i = 0; i < frame.Height; i++) - Marshal.Copy(frame.Image, i * frame.Width, - new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Width); + for (var i = 0; i < frame.Size.Height; i++) + Marshal.Copy(frame.Image, i * frame.Size.Width, + new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Size.Width); tileset.UnlockBits(data); f++; @@ -293,31 +286,31 @@ namespace OpenRA.Utility for (int f = startFrame; f < endFrame; f++) { frame = srcImage[f]; + int OffsetX = 0; + int OffsetY = 0; if (args.Contains("--infantrydeath")) { - OffsetX = frame.FrameWidth/2 - frame.Width/2; - OffsetY = frame.FrameHeight/2 - frame.Height/2; + OffsetX = frame.FrameSize.Width/2 - frame.Size.Width/2; + OffsetY = frame.FrameSize.Height/2 - frame.Size.Height/2; } else if (args.Contains("--building")) { - if (frame.OffsetX < 0) { frame.OffsetX = 0 - frame.OffsetX; } - if (frame.OffsetY < 0) { frame.OffsetY = 0 - frame.OffsetY; } - OffsetX = 0 + frame.OffsetX; - OffsetY = frame.FrameHeight - frame.OffsetY; + OffsetX = Math.Abs(frame.Offset.X); + OffsetY = frame.FrameSize.Height - Math.Abs(frame.Offset.Y); } Console.WriteLine("calculated OffsetX: {0}", OffsetX); Console.WriteLine("calculated OffsetY: {0}", OffsetY); - var data = bitmap.LockBits(new Rectangle(x+OffsetX, 0+OffsetY, frame.Width, frame.Height), ImageLockMode.WriteOnly, + var data = bitmap.LockBits(new Rectangle(x+OffsetX, 0+OffsetY, frame.Size.Width, frame.Size.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); - for (var i = 0; i < frame.Height; i++) - Marshal.Copy(frame.Image, i * frame.Width, - new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Width); + for (var i = 0; i < frame.Size.Height; i++) + Marshal.Copy(frame.Image, i * frame.Size.Width, + new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Size.Width); bitmap.UnlockBits(data); - x += frame.FrameWidth; + x += frame.FrameSize.Width; } } bitmap.Save(filename+".png");