diff --git a/MCGalaxy/Drawing/Image/ImagePrintDrawOp.cs b/MCGalaxy/Drawing/Image/ImagePrintDrawOp.cs index 8233ab247..a5989a652 100644 --- a/MCGalaxy/Drawing/Image/ImagePrintDrawOp.cs +++ b/MCGalaxy/Drawing/Image/ImagePrintDrawOp.cs @@ -45,7 +45,7 @@ namespace MCGalaxy.Drawing.Ops { using (PixelGetter getter = new PixelGetter(Source)) { getter.Init(); - getter.Iterate(output, OutputPixel); + OutputPixels(getter, output); } selector = null; @@ -106,26 +106,30 @@ namespace MCGalaxy.Drawing.Ops { return entry; } - void OutputPixel(Pixel P, DrawOpOutput output) { - ushort x = (ushort)(Origin.X + dx.X * P.X + dy.X * P.Y); - ushort y = (ushort)(Origin.Y + dx.Y * P.X + dy.Y * P.Y); - ushort z = (ushort)(Origin.Z + dx.Z * P.X + dy.Z * P.Y); - if (P.A < 20) { output(Place(x, y, z, ExtBlock.Air)); return; } - - byte raw = 0; - if (!DualLayer) { - raw = selector.BestMatch(P.R, P.G, P.B); - } else { - bool backLayer; - raw = selector.BestMatch(P.R, P.G, P.B, out backLayer); + void OutputPixels(PixelGetter pixels, DrawOpOutput output) { + int width = pixels.Width, height = pixels.Height; + for (int yy = 0; yy < height; yy++) + for (int xx = 0; xx < width; xx++) + { + Pixel P = pixels.Get(xx, yy); + ushort x = (ushort)(Origin.X + dx.X * xx + dy.X * yy); + ushort y = (ushort)(Origin.Y + dx.Y * xx + dy.Y * yy); + ushort z = (ushort)(Origin.Z + dx.Z * xx + dy.Z * yy); + if (P.A < 20) { output(Place(x, y, z, ExtBlock.Air)); continue; } - if (backLayer) { - x = (ushort)(x + adj.X); - z = (ushort)(z + adj.Z); + byte raw = 0; + if (!DualLayer) { + raw = selector.BestMatch(P.R, P.G, P.B); + } else { + bool backLayer; + raw = selector.BestMatch(P.R, P.G, P.B, out backLayer); + if (backLayer) { + x = (ushort)(x + adj.X); + z = (ushort)(z + adj.Z); + } } + output(Place(x, y, z, ExtBlock.FromRaw(raw))); } - - output(Place(x, y, z, ExtBlock.FromRaw(raw))); } public void CalcState(int dir) { diff --git a/MCGalaxy/Drawing/Image/PixelGetter.cs b/MCGalaxy/Drawing/Image/PixelGetter.cs index 0251cd30f..4eaa13679 100644 --- a/MCGalaxy/Drawing/Image/PixelGetter.cs +++ b/MCGalaxy/Drawing/Image/PixelGetter.cs @@ -22,79 +22,70 @@ using MCGalaxy.Drawing.Ops; namespace MCGalaxy.Drawing { - public delegate void PixelGetterCallback(Pixel pixel, DrawOpOutput output); + public delegate Pixel PixelGet(int x, int y); + public struct Pixel { public byte A, R, G, B; } - public sealed class PixelGetter : IDisposable { + public unsafe sealed class PixelGetter : IDisposable { Bitmap bmp; BitmapData data; - public PixelGetter(Bitmap bmp) { - this.bmp = bmp; + byte* scan0; + int stride; + public PixelGet Get; + public readonly int Width, Height; + + public PixelGetter(Bitmap bmp) { + this.bmp = bmp; + Width = bmp.Width; Height = bmp.Height; } public void Init() { bool fastPath = bmp.PixelFormat == PixelFormat.Format32bppRgb - || bmp.PixelFormat == PixelFormat.Format32bppArgb - || bmp.PixelFormat == PixelFormat.Format24bppRgb; - if (!fastPath) return; + || bmp.PixelFormat == PixelFormat.Format32bppArgb + || bmp.PixelFormat == PixelFormat.Format24bppRgb; + if (!fastPath) { Get = GetGenericPixel; return; } // We can only use the fast path for 24bpp or 32bpp bitmaps Rectangle r = new Rectangle(0, 0, bmp.Width, bmp.Height); data = bmp.LockBits(r, ImageLockMode.ReadOnly, bmp.PixelFormat); - } - - public void Iterate(DrawOpOutput output, PixelGetterCallback callback) { - if (data == null) IterateSlow(output, callback); - else IterateFast(output, callback); - } - - unsafe void IterateFast(DrawOpOutput output, PixelGetterCallback callback) { - Pixel pixel; - int width = bmp.Width, height = bmp.Height; - byte* scan0 = (byte*)data.Scan0; - pixel.A = 255; - bool hasA = bmp.PixelFormat != PixelFormat.Format24bppRgb; - - for (int y = 0; y < height; y++) { - pixel.Y = (ushort)y; - byte* row = (scan0 + y * data.Stride); - for (int x = 0; x < width; x++) { - pixel.X = (ushort)x; - pixel.B = *row; row++; - pixel.G = *row; row++; - pixel.R = *row; row++; - if (hasA) { pixel.A = *row; row++; } - callback(pixel, output); - } + scan0 = (byte*)data.Scan0; + stride = data.Stride; + + if (bmp.PixelFormat == PixelFormat.Format24bppRgb) { + Get = Get24BppPixel; + } else { + Get = Get32BppPixel; } } - void IterateSlow(DrawOpOutput output, PixelGetterCallback callback) { + public Pixel GetGenericPixel(int x, int y) { Pixel pixel; - int width = bmp.Width, height = bmp.Height; - for (int y = 0; y < height; y++) - for (int x = 0; x < width; x++) - { - pixel.X = (ushort)x; pixel.Y = (ushort)y; - int argb = bmp.GetPixel(x, y).ToArgb(); // R/G/B properties incur overhead - - pixel.A = (byte)(argb >> 24); - pixel.R = (byte)(argb >> 16); - pixel.G = (byte)(argb >> 8); - pixel.B = (byte)argb; - callback(pixel, output); - } + int argb = bmp.GetPixel(x, y).ToArgb(); // R/G/B properties incur overhead + pixel.A = (byte)(argb >> 24); + pixel.R = (byte)(argb >> 16); + pixel.G = (byte)(argb >> 8); + pixel.B = (byte)argb; + return pixel; } + public Pixel Get24BppPixel(int x, int y) { + Pixel pixel; + byte* ptr = (scan0 + y * data.Stride) + (x * 3); + pixel.B = ptr[0]; pixel.G = ptr[1]; pixel.R = ptr[2]; pixel.A = 255; + return pixel; + } + + public Pixel Get32BppPixel(int x, int y) { + Pixel pixel; + byte* ptr = (scan0 + y * data.Stride) + (x * 4); + pixel.B = ptr[0]; pixel.G = ptr[1]; pixel.R = ptr[2]; pixel.A = ptr[3]; + return pixel; + } + public void Dispose() { if (data != null) bmp.UnlockBits(data); data = null; bmp = null; } } - - public struct Pixel { - public ushort X, Y; - public byte A, R, G, B; - } } diff --git a/MCGalaxy/Generator/HeightmapGen.cs b/MCGalaxy/Generator/HeightmapGen.cs index db24e3993..0f80647c7 100644 --- a/MCGalaxy/Generator/HeightmapGen.cs +++ b/MCGalaxy/Generator/HeightmapGen.cs @@ -20,6 +20,7 @@ using System.Drawing; using System.IO; using System.Net; using MCGalaxy.Network; +using MCGalaxy.Drawing; namespace MCGalaxy.Generator { public static class HeightmapGen { @@ -73,12 +74,12 @@ namespace MCGalaxy.Generator { Level lvl = args.Level; if (args.Args.Length == 0) { Player.Message(p, "You need to provide a url for the image."); return false; } - if (!DownloadImage(args.Args, "extra/heightmap/", p )) return false; + if (!DownloadImage(args.Args, "extra/heightmap/", p )) return false; string user = p == null ? "(console)" : p.name; Bitmap bmp = ReadBitmap("tempImage_" + user, "extra/heightmap/", p); if (bmp == null) return false; - int index = 0, oneY = lvl.Width * lvl.Length; + int index = 0, oneY = lvl.Width * lvl.Length; using (bmp) { if (lvl.Width != bmp.Width || lvl.Length != bmp.Height) { Player.Message(p, "The size of the heightmap is {0} by {1}.", bmp.Width, bmp.Height); @@ -86,35 +87,38 @@ namespace MCGalaxy.Generator { return false; } - for (int z = 0; z < bmp.Height; z++) - for (int x = 0; x < bmp.Width; x++) - { - int height = bmp.GetPixel(x, z).R; - byte layer = Block.Dirt, top = Block.Grass; - - if ( - IsShorterBy(height, bmp, x - 1, z) || - IsShorterBy(height, bmp, x + 1, z) || - IsShorterBy(height, bmp, x, z - 1) || - IsShorterBy(height, bmp, x, z + 1)) + using (PixelGetter pixels = new PixelGetter(bmp)) { + pixels.Init(); + for (int z = 0; z < pixels.Height; z++) + for (int x = 0; x < pixels.Width; x++) { - layer = Block.Stone; top = Block.Stone; + int height = pixels.Get(x, z).R; + byte layer = Block.Dirt, top = Block.Grass; + + if ( + IsShorterBy(height, pixels, x - 1, z) || + IsShorterBy(height, pixels, x + 1, z) || + IsShorterBy(height, pixels, x, z - 1) || + IsShorterBy(height, pixels, x, z + 1)) + { + layer = Block.Stone; top = Block.Stone; + } + + height = height * lvl.Height / 255; + for (int y = 0; y < height - 1; y++) + lvl.blocks[index + oneY * y] = layer; + if (height > 0) + lvl.blocks[index + oneY * (height - 1)] = top; + index++; } - - height = height * lvl.Height / 255; - for (int y = 0; y < height - 1; y++) - lvl.blocks[index + oneY * y] = layer; - if (height > 0) - lvl.blocks[index + oneY * (height - 1)] = top; - index++; } } return true; } - static bool IsShorterBy(int height, Bitmap bmp, int x, int z) { - if (x >= bmp.Width || x < 0 || z >= bmp.Height || z < 0) return false; - int neighbourHeight = bmp.GetPixel(x, z).R; + static bool IsShorterBy(int height, PixelGetter pixels, int x, int z) { + if (x >= pixels.Width || x < 0 || z >= pixels.Height || z < 0) return false; + int neighbourHeight = pixels.Get(x, z).R; return height >= neighbourHeight + 2; } }