public static Sprite MapDPLCToBmp(byte[] artfile, byte[] mapfile, EngineVersion mapversion, byte[] dplc, EngineVersion dplcversion, int frame, int startpal, bool priority = false) { if (mapversion == EngineVersion.Invalid) { mapversion = LevelData.Game.MappingsVersion; } if (dplcversion == EngineVersion.Invalid) { dplcversion = LevelData.Game.DPLCVersion; } return(LevelData.MapFrameToBmp(artfile, MappingsFrame.Load(mapfile, mapversion)[frame], DPLCFrame.Load(dplc, dplcversion)[frame], startpal, priority)); }
private void backgroundLevelLoader_DoWork(object sender, DoWorkEventArgs e) { #if !DEBUG try { #endif LevelData.littleendian = false; MultiFileIndexer <byte> art = new MultiFileIndexer <byte>(); foreach (SonicRetro.SonLVL.API.FileInfo file in animInfo.Art) { art.AddFile(new List <byte>(Compression.Decompress(file.Filename, animInfo.ArtCompression)), file.Offset); } tiles = art.ToArray(); art.Clear(); byte[] tmp = null; using (Bitmap bmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed)) palette = bmp.Palette; for (int i = 0; i < 256; i++) { palette.Entries[i] = Color.Black; } foreach (PaletteInfo palent in animInfo.Palette) { tmp = File.ReadAllBytes(palent.Filename); SonLVLColor[] palfile; palfile = new SonLVLColor[tmp.Length / 2]; for (int pi = 0; pi < tmp.Length; pi += 2) { palfile[pi / 2] = new SonLVLColor(SonicRetro.SonLVL.API.ByteConverter.ToUInt16(tmp, pi)); } for (int pa = 0; pa < palent.Length; pa++) { palette.Entries[pa + palent.Destination] = palfile[pa + palent.Source].RGBColor; } } palette.Entries[0] = Color.Transparent; Dictionary <string, int> labels = new Dictionary <string, int>(); tmp = null; switch (animInfo.MappingsFormat) { case MappingsFormat.Binary: tmp = File.ReadAllBytes(animInfo.MappingsFile); break; case MappingsFormat.ASM: case MappingsFormat.Macro: tmp = LevelData.ASMToBin(animInfo.MappingsFile, animInfo.MappingsGame, out labels); break; } mappings = MappingsFrame.Load(tmp, animInfo.MappingsGame, labels); if (!string.IsNullOrEmpty(animInfo.DPLCFile)) { labels = new Dictionary <string, int>(); tmp = null; switch (animInfo.DPLCFormat) { case MappingsFormat.Binary: tmp = File.ReadAllBytes(animInfo.DPLCFile); break; case MappingsFormat.ASM: case MappingsFormat.Macro: tmp = LevelData.ASMToBin(animInfo.DPLCFile, animInfo.DPLCGame, out labels); break; } dplc = DPLCFrame.Load(tmp, animInfo.DPLCGame, labels); } else { dplc = null; } labels = new Dictionary <string, int>(); tmp = null; switch (animInfo.AnimationFormat) { case MappingsFormat.Binary: tmp = File.ReadAllBytes(animInfo.AnimationFile); break; case MappingsFormat.ASM: case MappingsFormat.Macro: tmp = LevelData.ASMToBin(animInfo.AnimationFile, project.Game, out labels); break; } animations = Animation.Load(tmp, labels); animlabel = Path.GetFileNameWithoutExtension(animInfo.AnimationFile).MakeIdentifier(); foreach (KeyValuePair <string, int> label in labels) { if (label.Value == 0) { animlabel = label.Key; break; } } sprites = new List <Sprite>(mappings.Count); for (int i = 0; i < mappings.Count; i++) { if (dplc == null) { sprites.Add(new Sprite(LevelData.MapFrameToBmp(tiles, mappings[i], animInfo.StartPalette))); } else { sprites.Add(new Sprite(LevelData.MapFrameToBmp(tiles, mappings[i], dplc[i], animInfo.StartPalette))); } } #if !DEBUG } catch (Exception ex) { initerror = ex; } #endif }
static void Main(string[] args) { LongOpt[] opts = new[] { new LongOpt("help", Argument.No, null, 'h'), new LongOpt("padding", Argument.Required, null, 'p'), new LongOpt("startpal", Argument.Required, null, 's'), new LongOpt("nullfirst", Argument.No, null, 'n'), new LongOpt("twoplayer", Argument.No, null, '2'), new LongOpt("format", Argument.Required, null, 'f'), new LongOpt("game", Argument.Required, null, 'g'), new LongOpt("artcmp", Argument.Required, null, 'c'), new LongOpt("lowplane", Argument.Required, null, 0), new LongOpt("highplane", Argument.Required, null, 0), new LongOpt("palette", Argument.Required, null, 0), new LongOpt("center", Argument.Required, null, 0), new LongOpt("artfile", Argument.Required, null, 0), new LongOpt("mapfile", Argument.Required, null, 0), new LongOpt("dplcfile", Argument.Required, null, 0), new LongOpt("palfile", Argument.Required, null, 0) }; if (args.Length == 0) { args = new string[] { "-h" } } ; Getopt getopt = new Getopt("SpritePlotter.NET", args, Getopt.digest(opts), opts); int padding = 2; byte startpal = 0; bool nullfirst = false; bool twoplayer = false; MappingsFormat mapfmt = MappingsFormat.Binary; EngineVersion mapgame = EngineVersion.Invalid; bool s3kp = false; CompressionType artcmp = CompressionType.Uncompressed; Bitmap lowplanefile = null; Bitmap highplanefile = null; Color[] palette = null; Bitmap centerfile = null; string artfile = null; string mapfile = null; string dplcfile = null; string palfile = null; int opt = getopt.getopt(); while (opt != -1) { switch (opt) { case 'h': Console.Write(Properties.Resources.HelpText); return; case 'p': padding = int.Parse(getopt.Optarg); break; case 's': startpal = byte.Parse(getopt.Optarg); break; case 'n': nullfirst = true; break; case '2': twoplayer = true; break; case 'f': mapfmt = (MappingsFormat)Enum.Parse(typeof(MappingsFormat), getopt.Optarg, true); break; case 'g': if (getopt.Optarg.Equals("s3kp", StringComparison.OrdinalIgnoreCase)) { mapgame = EngineVersion.S3K; s3kp = true; } else { mapgame = (EngineVersion)Enum.Parse(typeof(EngineVersion), getopt.Optarg, true); } break; case 'c': artcmp = (CompressionType)Enum.Parse(typeof(CompressionType), getopt.Optarg, true); break; case 0: switch (opts[getopt.Longind].Name) { case "lowplane": lowplanefile = new Bitmap(getopt.Optarg); if (palette == null && (lowplanefile.PixelFormat & PixelFormat.Indexed) == PixelFormat.Indexed) { palette = lowplanefile.Palette.Entries; } break; case "highplane": highplanefile = new Bitmap(getopt.Optarg); if (palette == null && (highplanefile.PixelFormat & PixelFormat.Indexed) == PixelFormat.Indexed) { palette = highplanefile.Palette.Entries; } break; case "palette": switch (System.IO.Path.GetExtension(getopt.Optarg)) { case ".bin": palette = SonLVLColor.Load(getopt.Optarg, EngineVersion.S2).Select(a => a.RGBColor).ToArray(); break; case ".bmp": case ".png": case ".jpg": case ".gif": using (Bitmap bmp = new Bitmap(getopt.Optarg)) { if ((bmp.PixelFormat & PixelFormat.Indexed) == PixelFormat.Indexed) { palette = bmp.Palette.Entries; } else { List <Color> pal = new List <Color>(); for (int y = 0; y < bmp.Height; y += 8) { for (int x = 0; x < bmp.Width; x += 8) { pal.Add(bmp.GetPixel(x, y)); } } palette = pal.ToArray(); } } break; } break; case "center": centerfile = new Bitmap(getopt.Optarg); break; case "artfile": artfile = getopt.Optarg; break; case "mapfile": mapfile = getopt.Optarg; break; case "dplcfile": dplcfile = getopt.Optarg; break; case "palfile": palfile = getopt.Optarg; break; } break; } opt = getopt.getopt(); } if (mapgame == EngineVersion.Invalid) { Console.Error.WriteLine("No game specified."); return; } if (lowplanefile == null && highplanefile == null) { Console.Error.WriteLine("No image file specified."); return; } if (palette == null) { Console.Error.WriteLine("No palette specified, and image(s) did not contain palette."); return; } if (artfile == null) { Console.Error.WriteLine("No output art file specified."); return; } if (mapfile == null) { Console.Error.WriteLine("No output mappings file specified."); return; } if (palette.Length > 64) { palette = palette.Take(64).ToArray(); // lazy } BitmapBits lowplane = null, highplane = null, combinedplanes = null; if (lowplanefile != null) { if ((lowplanefile.PixelFormat & PixelFormat.Indexed) == PixelFormat.Indexed) { lowplane = new BitmapBits(lowplanefile); } else { using (Bitmap bmp = lowplanefile.To32bpp()) lowplane = LoadBitmap32BppArgb(bmp, palette); } lowplanefile.Dispose(); if (highplanefile == null) { combinedplanes = lowplane; } } if (highplanefile != null) { if ((highplanefile.PixelFormat & PixelFormat.Indexed) == PixelFormat.Indexed) { highplane = new BitmapBits(highplanefile); } else { using (Bitmap bmp = highplanefile.To32bpp()) highplane = LoadBitmap32BppArgb(bmp, palette); } highplanefile.Dispose(); if (lowplanefile == null) { combinedplanes = highplane; } } if (combinedplanes == null) { combinedplanes = new BitmapBits(Math.Max(lowplane.Width, highplane.Width), Math.Max(lowplane.Height, highplane.Height)); combinedplanes.DrawBitmap(lowplane, 0, 0); combinedplanes.DrawBitmapComposited(highplane, 0, 0); } List <Point> centers = null; if (centerfile != null) { centers = new List <Point>(); BitmapBits cntr; if ((centerfile.PixelFormat & PixelFormat.Indexed) == PixelFormat.Indexed) { cntr = new BitmapBits(centerfile); } else { using (Bitmap bmp = centerfile.To32bpp()) cntr = LoadBitmap32BppArgb(bmp, Color.Black, Color.White); } centerfile.Dispose(); for (int y = 0; y < cntr.Height; y++) { for (int x = 0; x < cntr.Width; x++) { if (cntr[x, y] != 0) { centers.Add(new Point(x, y)); } } } } List <Rectangle> sprites = new List <Rectangle>(); for (int y = 0; y < combinedplanes.Height; y++) { for (int x = 0; x < combinedplanes.Width; x++) { if (combinedplanes[x, y] % 16 != 0) { Rectangle newrect = new Rectangle(x - padding, y - padding, (padding * 2) + 1, (padding * 2) + 1); for (int i = 0; i < sprites.Count; i++) { if (newrect.IntersectsWith(sprites[i])) { newrect = Rectangle.Union(newrect, sprites[i]); sprites.RemoveAt(i); i = -1; } } sprites.Add(newrect); } } } List <Rectangle> rows = new List <Rectangle>(); for (int i = 0; i < sprites.Count; i++) { Rectangle rect = sprites[i]; rect.Inflate(-padding, -padding); sprites[i] = rect; if (rows.Count > 0 && sprites[i].IntersectsWith(rows[rows.Count - 1])) { rows[rows.Count - 1] = Rectangle.Union(sprites[i], rows[rows.Count - 1]); } else { rows.Add(new Rectangle(0, sprites[i].Y, combinedplanes.Width, sprites[i].Height)); } } List <Rectangle> newsprites = new List <Rectangle>(sprites.Count); foreach (Rectangle rect in rows) { newsprites.AddRange(sprites.Where(a => a.IntersectsWith(rect)).OrderBy(a => a.X)); } sprites = newsprites; List <byte[]> tiles = new List <byte[]>(); NamedList <MappingsFrame> map = new NamedList <MappingsFrame>("Map_" + Path.GetFileNameWithoutExtension(mapfile), sprites.Count); NamedList <DPLCFrame> dplc = null; if (dplcfile != null) { dplc = new NamedList <DPLCFrame>("DPLC_" + Path.GetFileNameWithoutExtension(dplcfile), sprites.Count); } if (nullfirst) { map.Add(new MappingsFrame(map.Name + "_Null")); if (dplc != null) { dplc.Add(new DPLCFrame(dplc.Name + "_Null")); } } for (int i = 0; i < sprites.Count; i++) { Point center = new Point(sprites[i].Width / 2, sprites[i].Height / 2); if (centers != null) { foreach (Point item in centers) { if (sprites[i].Contains(item)) { center = new Point(item.X - sprites[i].Left, item.Y - sprites[i].Top); break; } } } MappingsFrame mapframe = new MappingsFrame(map.Name + "_" + i); map.Add(mapframe); DPLCFrame dplcframe = null; if (dplc != null) { dplcframe = new DPLCFrame(dplc.Name + "_" + i); dplc.Add(dplcframe); } if (lowplane != null) { SpriteToMap(sprites[i], center, lowplane, tiles, mapframe, dplcframe, startpal, false, twoplayer); } if (highplane != null) { SpriteToMap(sprites[i], center, highplane, tiles, mapframe, dplcframe, startpal, true, twoplayer); } } using (MemoryStream ms = new MemoryStream(tiles.Count * 32)) { using (BinaryWriter bw = new BinaryWriter(ms)) foreach (byte[] b in tiles) { bw.Write(b); } Compression.Compress(ms.ToArray(), artfile, artcmp); } if (mapfmt == MappingsFormat.Binary) { File.WriteAllBytes(mapfile, MappingsFrame.GetBytes(map, mapgame)); if (dplc != null) { File.WriteAllBytes(dplcfile, DPLCFrame.GetBytes(dplc, s3kp ? EngineVersion.S2 : mapgame)); } } else { MappingsFrame.ToASM(mapfile, map, mapgame, mapfmt == MappingsFormat.Macro); if (dplc != null) { DPLCFrame.ToASM(dplcfile, dplc, mapgame, mapfmt == MappingsFormat.Macro, s3kp); } } if (palfile != null) { using (FileStream fs = File.Create(palfile)) using (BinaryWriter bw = new BinaryWriter(fs)) foreach (Color c in palette) { bw.Write(ByteConverter.GetBytes(new SonLVLColor(c).MDColor)); } } }
private static void SpriteToMap(Rectangle sprite, Point center, BitmapBits plane, List <byte[]> tiles, MappingsFrame mapframe, DPLCFrame dplcframe, byte startpal, bool pri, bool twoplayer) { BitmapBits bmp = plane.GetSection(sprite); if (bmp.Width % 8 != 0 || bmp.Height % 8 != 0) { int w = bmp.Width; if (w % 8 != 0) { w = (w & ~7) + 8; } int h = bmp.Height; if (h % 8 != 0) { h = (h & ~7) + 8; } BitmapBits tmp = new BitmapBits(w, h); tmp.DrawBitmapBounded(bmp, 0, 0); bmp = tmp; } int tw = bmp.Width / 8; int th = bmp.Height / 8; byte[,] tilepals = new byte[tw, th]; for (int ty = 0; ty < th; ty++) { for (int tx = 0; tx < tw; tx++) { tilepals[tx, ty] = 0xFF; int[] palcnt = new int[4]; for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) { if (bmp[tx * 8 + x, ty * 8 + y] % 16 != 0) { palcnt[bmp[tx * 8 + x, ty * 8 + y] / 16]++; } } } if (!palcnt.FastArrayEqual(0)) { tilepals[tx, ty] = 0; for (int i = 1; i < 4; i++) { if (palcnt[i] > palcnt[tilepals[tx, ty]]) { tilepals[tx, ty] = (byte)i; } } } } } int numtiles = 0; for (int ty = 0; ty < th; ty++) { for (int tx = 0; tx < tw; tx++) { if (tilepals[tx, ty] != 0xFF) { int w = Math.Min(4, (tw) - tx); for (int x = 1; x < w; x++) { if (tilepals[tx + x, ty] != tilepals[tx, ty]) { w = x; } } int h = Math.Min(4, (th) - ty); for (int y = 1; y < h; y++) { for (int x = 0; x < w; x++) { if (tilepals[tx + x, ty + y] != tilepals[tx, ty]) { h = y; } } } if (twoplayer && h % 2 == 1) { h++; } if (dplcframe != null) { mapframe.Tiles.Add(new MappingsTile((short)((tx * 8) - center.X), (short)((ty * 8) - center.Y), (byte)w, (byte)h, (ushort)numtiles, false, false, startpal, pri)); dplcframe.Tiles.Add(new DPLCEntry((byte)(w * h), (ushort)tiles.Count)); } else { mapframe.Tiles.Add(new MappingsTile((short)((tx * 8) - center.X), (short)((ty * 8) - center.Y), (byte)w, (byte)h, (ushort)tiles.Count, false, false, startpal, pri)); } for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { if (ty + y < th) { tiles.Add(bmp.ToTile((tx + x) * 8, (ty + y) * 8)); tilepals[tx + x, ty + y] = 0xFF; } else { tiles.Add(new byte[32]); } } } numtiles += w * h; tx += w - 1; } } } }
static void Main(string[] args) { byte[] art; ColorPalette palette; List <MappingsFrame> map; List <DPLCFrame> dplc; SpriteInfo spriteInfo; LevelData.littleendian = false; LongOpt[] opts = new[] { new LongOpt("help", Argument.No, null, 'h'), new LongOpt("padding", Argument.Required, null, 'p'), new LongOpt("columns", Argument.Required, null, 'c'), new LongOpt("width", Argument.Required, null, 'w'), new LongOpt("background", Argument.Required, null, 'b'), new LongOpt("grid", Argument.No, null, 'g') }; Getopt getopt = new Getopt("SpriteSheetGen", args, Getopt.digest(opts), opts); int padding = 2; int columns = 8; int width = 0; bool fixedwidth = false; int gridsize = -1; Color background = Color.Transparent; int opt = getopt.getopt(); while (opt != -1) { switch (opt) { case 'h': Console.Write(Properties.Resources.HelpText); return; case 'p': padding = int.Parse(getopt.Optarg); break; case 'c': columns = int.Parse(getopt.Optarg); break; case 'w': width = int.Parse(getopt.Optarg); columns = -1; fixedwidth = true; break; case 'g': gridsize = 0; break; case 'b': if (getopt.Optarg.StartsWith("#")) { background = Color.FromArgb((int)(0xFF000000 | uint.Parse(getopt.Optarg.Substring(1), System.Globalization.NumberStyles.HexNumber))); } else { background = Color.FromName(getopt.Optarg.Replace(" ", "")); } break; } opt = getopt.getopt(); } string filename; Console.Write("File: "); if (getopt.Optind == args.Length) { filename = Console.ReadLine(); } else { filename = args[getopt.Optind]; Console.WriteLine(filename); } filename = Path.GetFullPath(filename); Environment.CurrentDirectory = Path.GetDirectoryName(filename); spriteInfo = IniSerializer.Deserialize <SpriteInfo>(filename); if (spriteInfo.MappingsGame == EngineVersion.Invalid) { spriteInfo.MappingsGame = spriteInfo.Game; } if (spriteInfo.DPLCGame == EngineVersion.Invalid) { spriteInfo.DPLCGame = spriteInfo.Game; } MultiFileIndexer <byte> tiles = new MultiFileIndexer <byte>(); foreach (SonicRetro.SonLVL.API.FileInfo file in spriteInfo.Art) { tiles.AddFile(new List <byte>(Compression.Decompress(file.Filename, spriteInfo.ArtCompression)), file.Offset); } art = tiles.ToArray(); tiles.Clear(); byte[] tmp = null; using (Bitmap palbmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed)) palette = palbmp.Palette; for (int i = 0; i < 256; i++) { palette.Entries[i] = Color.Black; } foreach (PaletteInfo palent in spriteInfo.Palette) { tmp = File.ReadAllBytes(palent.Filename); SonLVLColor[] palfile; palfile = new SonLVLColor[tmp.Length / 2]; for (int pi = 0; pi < tmp.Length; pi += 2) { palfile[pi / 2] = new SonLVLColor(SonicRetro.SonLVL.API.ByteConverter.ToUInt16(tmp, pi)); } for (int pa = 0; pa < palent.Length; pa++) { palette.Entries[pa + palent.Destination] = palfile[pa + palent.Source].RGBColor; } } palette.Entries[0] = background; Dictionary <string, int> labels = new Dictionary <string, int>(); tmp = null; switch (spriteInfo.MappingsFormat) { case MappingsFormat.Binary: tmp = File.ReadAllBytes(spriteInfo.MappingsFile); break; case MappingsFormat.ASM: case MappingsFormat.Macro: tmp = LevelData.ASMToBin(spriteInfo.MappingsFile, spriteInfo.MappingsGame, out labels); break; } map = MappingsFrame.Load(tmp, spriteInfo.MappingsGame, labels); if (!string.IsNullOrEmpty(spriteInfo.DPLCFile)) { labels = new Dictionary <string, int>(); tmp = null; switch (spriteInfo.DPLCFormat) { case MappingsFormat.Binary: tmp = File.ReadAllBytes(spriteInfo.DPLCFile); break; case MappingsFormat.ASM: case MappingsFormat.Macro: tmp = LevelData.ASMToBin(spriteInfo.DPLCFile, spriteInfo.DPLCGame, out labels); break; } dplc = DPLCFrame.Load(tmp, spriteInfo.DPLCGame, labels); } else { dplc = null; } List <BitmapBits> spritesLow = new List <BitmapBits>(map.Count); List <BitmapBits> spritesHigh = new List <BitmapBits>(map.Count); List <BitmapBits> spritesMerged = new List <BitmapBits>(map.Count); List <Point> offsets = new List <Point>(map.Count); List <Point> centers = new List <Point>(map.Count); for (int i = 0; i < map.Count; i++) { if (map[i].TileCount == 0) { //File.AppendAllText("log.txt", "Frame " + i + " empty.\r\n"); continue; } Sprite spr; if (dplc != null) { spr = LevelData.MapFrameToBmp(art, map[i], dplc[i], spriteInfo.StartPalette); } else { spr = LevelData.MapFrameToBmp(art, map[i], spriteInfo.StartPalette); } BitmapBits sprLow = spr.GetBitmapLow(); BitmapBits sprHigh = spr.GetBitmapHigh(); BitmapBits sprMerged = spr.GetBitmap(); int cx = -spr.X; int cy = -spr.Y; for (int _x = 0; _x < sprMerged.Width; _x++) { for (int _y = 0; _y < sprMerged.Height; _y++) { if (sprMerged[_x, _y] != 0) { sprMerged = sprMerged.GetSection(_x, 0, sprMerged.Width - _x, sprMerged.Height); sprLow = sprLow.GetSection(_x, 0, sprLow.Width - _x, sprLow.Height); sprHigh = sprHigh.GetSection(_x, 0, sprHigh.Width - _x, sprHigh.Height); cx -= _x; goto checkright; } } } checkright: for (int _x = sprMerged.Width - 1; _x >= 0; _x--) { for (int _y = 0; _y < sprMerged.Height; _y++) { if (sprMerged[_x, _y] != 0) { sprMerged = sprMerged.GetSection(0, 0, _x + 1, sprMerged.Height); sprLow = sprLow.GetSection(0, 0, _x + 1, sprLow.Height); sprHigh = sprHigh.GetSection(0, 0, _x + 1, sprHigh.Height); goto checktop; } } } checktop: for (int _y = 0; _y < sprMerged.Height; _y++) { for (int _x = 0; _x < sprMerged.Width; _x++) { if (sprMerged[_x, _y] != 0) { sprMerged = sprMerged.GetSection(0, _y, sprMerged.Width, sprMerged.Height - _y); sprLow = sprLow.GetSection(0, _y, sprLow.Width, sprLow.Height - _y); sprHigh = sprHigh.GetSection(0, _y, sprHigh.Width, sprHigh.Height - _y); cy -= _y; goto checkbottom; } } } checkbottom: for (int _y = sprMerged.Height - 1; _y >= 0; _y--) { for (int _x = 0; _x < sprMerged.Width; _x++) { if (sprMerged[_x, _y] != 0) { sprMerged = sprMerged.GetSection(0, 0, sprMerged.Width, _y + 1); sprLow = sprLow.GetSection(0, 0, sprLow.Width, _y + 1); sprHigh = sprHigh.GetSection(0, 0, sprHigh.Width, _y + 1); goto checkdone; } } } checkdone: spritesMerged.Add(sprMerged); spritesLow.Add(sprLow); spritesHigh.Add(sprHigh); centers.Add(new Point(cx, cy)); } if (gridsize == 0) { for (int i = 0; i < spritesMerged.Count; i++) { gridsize = Math.Max(gridsize, Math.Max(spritesMerged[i].Width, spritesMerged[i].Height)); } if (!fixedwidth) { width = (padding * 2 + gridsize) * columns; } } int x = padding; int y = padding; int height = 0; int rowcnt = 0; int rowheight = 0; for (int i = 0; i < spritesMerged.Count; i++) { BitmapBits spr = spritesMerged[i]; Point off; if (gridsize == -1) { if (fixedwidth && x + spr.Width + padding > width) { x = padding; y += rowheight; rowheight = 0; } off = new System.Drawing.Point(x, y); centers[i] = new Point(centers[i].X + off.X, centers[i].Y + off.Y); if (!fixedwidth) { width = Math.Max(width, x + spr.Width + padding); } height = Math.Max(height, y + spr.Height + padding); if (spr.Height + 2 * padding > rowheight) { rowheight = spr.Height + 2 * padding; } if (!fixedwidth && ++rowcnt == columns) { x = padding; y += rowheight; rowcnt = 0; rowheight = 0; } else { x += spr.Width + 2 * padding; } } else { if (fixedwidth && x + gridsize + padding > width) { x = padding; y += gridsize + 2 * padding; } off = new Point(x + (gridsize - spr.Width) / 2, y + (gridsize - spr.Height) / 2); centers[i] = new Point(centers[i].X + off.X, centers[i].Y + off.Y); height = Math.Max(height, y + gridsize + padding); if (!fixedwidth && ++rowcnt == columns) { x = padding; y += gridsize + 2 * padding; rowcnt = 0; } else { x += gridsize + 2 * padding; } } offsets.Add(off); } BitmapBits bmpMerged = new BitmapBits(width, height); for (int i = 0; i < spritesMerged.Count; i++) { bmpMerged.DrawBitmap(spritesMerged[i], offsets[i]); } BitmapBits bmpLow = new BitmapBits(width, height); for (int i = 0; i < spritesLow.Count; i++) { bmpLow.DrawBitmap(spritesLow[i], offsets[i]); } BitmapBits bmpHigh = new BitmapBits(width, height); for (int i = 0; i < spritesHigh.Count; i++) { bmpHigh.DrawBitmap(spritesHigh[i], offsets[i]); } BitmapBits bmpCenter = new BitmapBits(width, height); for (int i = 0; i < centers.Count; i++) { bmpCenter[centers[i].X, centers[i].Y] = 1; } Console.Write("Save as: "); if (getopt.Optind + 1 >= args.Length) { filename = Console.ReadLine(); } else { filename = args[getopt.Optind + 1]; Console.WriteLine(filename); } filename = Path.GetFullPath(filename); bmpMerged.ToBitmap(palette).Save(filename); if (!bmpLow.Bits.FastArrayEqual(0) && !bmpHigh.Bits.FastArrayEqual(0)) { bmpLow.ToBitmap(palette).Save(Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename) + "_low" + Path.GetExtension(filename))); bmpHigh.ToBitmap(palette).Save(Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename) + "_high" + Path.GetExtension(filename))); } bmpCenter.ToBitmap1bpp(Color.Black, Color.White).Save(Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename) + "_center" + Path.GetExtension(filename))); }