From 2bf19084f7158e6f609ccaa92fa896e809cc1f92 Mon Sep 17 00:00:00 2001 From: Lucas Scharenbroich Date: Mon, 5 Dec 2016 23:17:31 -0600 Subject: [PATCH] Add more tests and allow images to be loaded from the comomand line --- SpriteCompiler/Problem/CodeSequence.cs | 2 +- SpriteCompiler/Program.cs | 187 +++++++++++++++--------- SpriteCompiler/Samples/Mario_000.png | Bin 0 -> 361 bytes SpriteCompiler/Samples/SpriteX1_000.png | Bin 0 -> 626 bytes SpriteCompiler/SpriteCompiler.csproj | 2 + 5 files changed, 123 insertions(+), 68 deletions(-) create mode 100644 SpriteCompiler/Samples/Mario_000.png create mode 100644 SpriteCompiler/Samples/SpriteX1_000.png diff --git a/SpriteCompiler/Problem/CodeSequence.cs b/SpriteCompiler/Problem/CodeSequence.cs index 395e632..873ecb2 100644 --- a/SpriteCompiler/Problem/CodeSequence.cs +++ b/SpriteCompiler/Problem/CodeSequence.cs @@ -53,7 +53,7 @@ namespace SpriteCompiler.Problem public override string ToString() { - return (offset == 0) ? "TSC" : ("ADC #" + offset.ToString() + " / TSC"); + return (offset == 0) ? "TCS" : ("ADC #" + offset.ToString() + " / TCS"); } public override string Emit() diff --git a/SpriteCompiler/Program.cs b/SpriteCompiler/Program.cs index f63d6d8..020cfc7 100644 --- a/SpriteCompiler/Program.cs +++ b/SpriteCompiler/Program.cs @@ -7,6 +7,24 @@ using System.Drawing; using System.Linq; + public static class ExtensionMethods + { + public static void Dump(this int[,] array) + { + var rows = array.GetLength(1); + var cols = array.GetLength(0); + + for (int r = 0; r < rows; r++) + { + for (int c = 0; c < cols; c++) + { + Console.Write(array[c, r].ToString("X1")); + } + Console.Write(Environment.NewLine); + } + } + + } public class ApplicationArguments { public List Data { get; set; } @@ -27,84 +45,119 @@ static void Main(string[] args) { - IEnumerable data = null; + var data = new List(); + var mask = new List(); + var filename = (string)null; + Color? maskColor = null; + var sprite = new List(); - try - { - data = args.Select((s, i) => new SpriteByte(Convert.ToByte(s, 16), (ushort)i)); - } - catch (FormatException e) - { - // If there is only one or two arguments, them marybe the user passed in a file - if (args.Length <= 2) - { - var palette = new Dictionary(); - int nextIndex = 1; + var p = new FluentCommandLineParser(); - // Convert the image / mask to a paletted image - var bitmap = new Bitmap(args[0]); - int[,] buffer = new int[bitmap.Width, bitmap.Height]; + p.Setup>('d', "data") + .Callback(_ => data = _.Select(s => Convert.ToByte(s, 16)).ToList()); - for (int r = 0; r < bitmap.Height; r++) - { - for (int w = 0; w < bitmap.Width; w++) - { - var rgb = bitmap.GetPixel(w, r); + p.Setup>('m', "mask") + .Callback(_ => data = _.Select(s => Convert.ToByte(s, 16)).ToList()); - if (!palette.ContainsKey(rgb)) - { - if (palette.Count >= 15) - { - throw new Exception("Image cannot have more than 15 unique colors"); - } - palette[rgb] = nextIndex++; - } + p.Setup('i', "image") + .Callback(_ => filename = _); - buffer[w, r] = palette[rgb]; - } - } - - // Pair up pixles to build bytes - var sprite = new List(); - - for (int r = 0; r < bitmap.Height; r++) - { - for (int w = 0; w < bitmap.Width; w += 2) - { - sprite.Add(new SpriteByte((byte)((buffer[w, r] << 4) + buffer[w + 1, r]), (ushort)(r * 160 + (w / 2)))); - } - } - - data = sprite; - } - } - /* - return; - - var p = new FluentCommandLineParser(); - - // specify which property the value will be assigned too. - p.Setup>(arg => arg.Data) - .As('d', "data") // define the short and long option name - .Required() // using the standard fluent Api to declare this Option as required. - .Callback(d => d.Select(s => Convert.ToByte(s, 16)).ToArray()); - - p.Setup>(arg => arg.Mask) - .As('m', "mask"); + p.Setup("bg-color") + .Callback(_ => maskColor = Color.FromArgb(0xFF, Color.FromArgb(Convert.ToInt32(_, 16)))); - var result = p.Parse(args); + p.Parse(args); - if (!result.HasErrors) + Console.WriteLine("Manual data has " + data.Count + " bytes"); + Console.WriteLine("Manual mask has " + mask.Count + " bytes"); + Console.WriteLine("Input filename is " + filename); + Console.WriteLine("Image mask color is " + (maskColor.HasValue ? maskColor.ToString() : "(none)")); + + if (!String.IsNullOrEmpty(filename)) { - */ + var palette = new Dictionary(); + int nextIndex = 1; - var problem = SpriteGeneratorSearchProblem.CreateSearchProblem(); - var search = SpriteGeneratorSearchProblem.Create(); + // Convert the image / mask to a paletted image + var bitmap = new Bitmap(filename); + int[,] data_buffer = new int[bitmap.Width, bitmap.Height]; + int[,] mask_buffer = new int[bitmap.Width, bitmap.Height]; - var solution = search.Search(problem, new SpriteGeneratorState(data)); + Console.WriteLine(String.Format(" Image is {0} x {1}", bitmap.Width, bitmap.Height)); - WriteOutSolution(solution); - //} + if (maskColor.HasValue) + { + palette[maskColor.Value] = 0; + } + + for (int r = 0; r < bitmap.Height; r++) + { + for (int w = 0; w < bitmap.Width; w++) + { + var rgb = bitmap.GetPixel(w, r); + + if (!palette.ContainsKey(rgb)) + { + if (palette.Count >= 15) + { + throw new Exception("Image cannot have more than 15 unique colors"); + } + palette[rgb] = nextIndex++; + } + + data_buffer[w, r] = palette[rgb]; + + if (maskColor.HasValue) + { + if (rgb.Equals(maskColor.Value)) + { + data_buffer[w, r] = 0x0; + mask_buffer[w, r] = 0xF; + } + else + { + data_buffer[w, r] = palette[rgb]; + mask_buffer[w, r] = 0x0; + } + } + else + { + data_buffer[w, r] = palette[rgb]; + } + } + } + + data_buffer.Dump(); + Console.WriteLine(); + mask_buffer.Dump(); + + // Pair up pixels to build bytes + for (int r = 0; r < bitmap.Height; r++) + { + for (int w = 0; w < bitmap.Width; w += 2) + { + var mask_byte = (byte)((mask_buffer[w, r] << 4) + mask_buffer[w + 1, r]); + var data_byte = (byte)((data_buffer[w, r] << 4) + data_buffer[w + 1, r]); + var offset = (ushort)(r * 160 + (w / 2)); + + // Skip fully transparent bytes + if (mask_byte == 0xFF) + { + continue; + } + + Console.WriteLine(String.Format("Adding ({0:X2}, {1:X2}, {2})", data_byte, mask_byte, offset)); + + sprite.Add(new SpriteByte(data_byte, mask_byte, offset)); + } + } + } + + var problem = SpriteGeneratorSearchProblem.CreateSearchProblem(); + var search = SpriteGeneratorSearchProblem.Create(); + + var solution = search.Search(problem, new SpriteGeneratorState(sprite)); + + WriteOutSolution(solution); } } } diff --git a/SpriteCompiler/Samples/Mario_000.png b/SpriteCompiler/Samples/Mario_000.png new file mode 100644 index 0000000000000000000000000000000000000000..21b7aadeb3024e414373dfa2a35219caf86b78cd GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^0zj<5!2~3yyw0Buq!^2X+?^QKos)S9a~60+7BevL9R^{>~HJJ;!nK^B+9RS)p0NoCtw|5H%5?OgMH zFN@Po+xTO@gG6pGyBYFfXM8Awu7T)*d)z$ya_)+I3S(|KXI-e4nw*(1FNk@n&V~vB z7MqZSWejU(iwVq&5^lN1)G$3a?v90r@wJQ}8ixX9|9c%~XbD?iwOBq{z&$~bfq%n0 zW?RcyF-`psBZ!Sjq&@yhjG+dR1%*0x`;vCm;l zE0<*7;<^8qHp8#$A5zNp$-fZfl)l0BgD31@;J#Cr?HLpl;>v-ZWbkzLb6Mw<&;$T0 C$$-xQ literal 0 HcmV?d00001 diff --git a/SpriteCompiler/Samples/SpriteX1_000.png b/SpriteCompiler/Samples/SpriteX1_000.png new file mode 100644 index 0000000000000000000000000000000000000000..9d8ed9a68941d325341f3f4f5775302148483272 GIT binary patch literal 626 zcmV-&0*(ENP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^Ag1Z(U700H7jL_t(oN41vGal zK^;~g;GQINv(Ty)!0GV?J{@?!+5fUYFu%Sp3UnWU!KbH9hHM2&7hOC)qCMX!5bhNS z>(|J=f|zdT$f1jRfjtP_*igeD-9~W%xIB-)rHjqs=TVme02^|>$XQfUAfyEl`M1Ki z%QZS3{HmaR4KyB~z~NuLxgz})iL+OnAWooHa~9PK)Y?HDp}USZS9BJ{tQ2pqND~pg zDCq49MXa?c=z)r#P|8BMZ%~|pTo2|HG?U)Vg7hiSD@q-kf^-hBwV;_+1;T6&dc~&W zT;p1;0}KtFIxx48sLO5^VOyY!flMqRiVIS|u(rQ$DZJa{tES`xjQ#mR+i)SJ((DQ*zQYYqmG(QvV3;cms&pe^6 zX;rXx`hPVR|7~mv{Fd}(0pYi)wjF1LKQ-BQq4oWyKx79qt&ZQHA00vh@IhhozW@LL M07*qoM6N<$f+3IzR{#J2 literal 0 HcmV?d00001 diff --git a/SpriteCompiler/SpriteCompiler.csproj b/SpriteCompiler/SpriteCompiler.csproj index dc24373..4a37303 100644 --- a/SpriteCompiler/SpriteCompiler.csproj +++ b/SpriteCompiler/SpriteCompiler.csproj @@ -94,6 +94,8 @@ + +