Use optimised PixelGetter for heightmap too. Fixes #237.

This commit is contained in:
UnknownShadow200 2017-10-28 12:40:17 +11:00
parent c25e34fb29
commit daca4b946f
3 changed files with 92 additions and 93 deletions

View File

@ -45,7 +45,7 @@ namespace MCGalaxy.Drawing.Ops {
using (PixelGetter getter = new PixelGetter(Source)) { using (PixelGetter getter = new PixelGetter(Source)) {
getter.Init(); getter.Init();
getter.Iterate(output, OutputPixel); OutputPixels(getter, output);
} }
selector = null; selector = null;
@ -106,11 +106,16 @@ namespace MCGalaxy.Drawing.Ops {
return entry; return entry;
} }
void OutputPixel(Pixel P, DrawOpOutput output) { void OutputPixels(PixelGetter pixels, DrawOpOutput output) {
ushort x = (ushort)(Origin.X + dx.X * P.X + dy.X * P.Y); int width = pixels.Width, height = pixels.Height;
ushort y = (ushort)(Origin.Y + dx.Y * P.X + dy.Y * P.Y); for (int yy = 0; yy < height; yy++)
ushort z = (ushort)(Origin.Z + dx.Z * P.X + dy.Z * P.Y); for (int xx = 0; xx < width; xx++)
if (P.A < 20) { output(Place(x, y, z, ExtBlock.Air)); return; } {
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; }
byte raw = 0; byte raw = 0;
if (!DualLayer) { if (!DualLayer) {
@ -118,15 +123,14 @@ namespace MCGalaxy.Drawing.Ops {
} else { } else {
bool backLayer; bool backLayer;
raw = selector.BestMatch(P.R, P.G, P.B, out backLayer); raw = selector.BestMatch(P.R, P.G, P.B, out backLayer);
if (backLayer) { if (backLayer) {
x = (ushort)(x + adj.X); x = (ushort)(x + adj.X);
z = (ushort)(z + adj.Z); 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) { public void CalcState(int dir) {
dx = default(Vec3S32); dy = default(Vec3S32); adj = default(Vec3S32); dx = default(Vec3S32); dy = default(Vec3S32); adj = default(Vec3S32);

View File

@ -22,68 +22,64 @@ using MCGalaxy.Drawing.Ops;
namespace MCGalaxy.Drawing { 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; Bitmap bmp;
BitmapData data; BitmapData data;
byte* scan0;
int stride;
public PixelGet Get;
public readonly int Width, Height;
public PixelGetter(Bitmap bmp) { public PixelGetter(Bitmap bmp) {
this.bmp = bmp; this.bmp = bmp;
Width = bmp.Width; Height = bmp.Height;
} }
public void Init() { public void Init() {
bool fastPath = bmp.PixelFormat == PixelFormat.Format32bppRgb bool fastPath = bmp.PixelFormat == PixelFormat.Format32bppRgb
|| bmp.PixelFormat == PixelFormat.Format32bppArgb || bmp.PixelFormat == PixelFormat.Format32bppArgb
|| bmp.PixelFormat == PixelFormat.Format24bppRgb; || bmp.PixelFormat == PixelFormat.Format24bppRgb;
if (!fastPath) return; if (!fastPath) { Get = GetGenericPixel; return; }
// We can only use the fast path for 24bpp or 32bpp bitmaps // We can only use the fast path for 24bpp or 32bpp bitmaps
Rectangle r = new Rectangle(0, 0, bmp.Width, bmp.Height); Rectangle r = new Rectangle(0, 0, bmp.Width, bmp.Height);
data = bmp.LockBits(r, ImageLockMode.ReadOnly, bmp.PixelFormat); data = bmp.LockBits(r, ImageLockMode.ReadOnly, bmp.PixelFormat);
scan0 = (byte*)data.Scan0;
stride = data.Stride;
if (bmp.PixelFormat == PixelFormat.Format24bppRgb) {
Get = Get24BppPixel;
} else {
Get = Get32BppPixel;
}
} }
public void Iterate(DrawOpOutput output, PixelGetterCallback callback) { public Pixel GetGenericPixel(int x, int y) {
if (data == null) IterateSlow(output, callback);
else IterateFast(output, callback);
}
unsafe void IterateFast(DrawOpOutput output, PixelGetterCallback callback) {
Pixel pixel; 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);
}
}
}
void IterateSlow(DrawOpOutput output, PixelGetterCallback callback) {
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 int argb = bmp.GetPixel(x, y).ToArgb(); // R/G/B properties incur overhead
pixel.A = (byte)(argb >> 24); pixel.A = (byte)(argb >> 24);
pixel.R = (byte)(argb >> 16); pixel.R = (byte)(argb >> 16);
pixel.G = (byte)(argb >> 8); pixel.G = (byte)(argb >> 8);
pixel.B = (byte)argb; pixel.B = (byte)argb;
callback(pixel, output); 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() { public void Dispose() {
@ -92,9 +88,4 @@ namespace MCGalaxy.Drawing {
bmp = null; bmp = null;
} }
} }
public struct Pixel {
public ushort X, Y;
public byte A, R, G, B;
}
} }

View File

@ -20,6 +20,7 @@ using System.Drawing;
using System.IO; using System.IO;
using System.Net; using System.Net;
using MCGalaxy.Network; using MCGalaxy.Network;
using MCGalaxy.Drawing;
namespace MCGalaxy.Generator { namespace MCGalaxy.Generator {
public static class HeightmapGen { public static class HeightmapGen {
@ -86,17 +87,19 @@ namespace MCGalaxy.Generator {
return false; return false;
} }
for (int z = 0; z < bmp.Height; z++) using (PixelGetter pixels = new PixelGetter(bmp)) {
for (int x = 0; x < bmp.Width; x++) pixels.Init();
for (int z = 0; z < pixels.Height; z++)
for (int x = 0; x < pixels.Width; x++)
{ {
int height = bmp.GetPixel(x, z).R; int height = pixels.Get(x, z).R;
byte layer = Block.Dirt, top = Block.Grass; byte layer = Block.Dirt, top = Block.Grass;
if ( if (
IsShorterBy(height, bmp, x - 1, z) || IsShorterBy(height, pixels, x - 1, z) ||
IsShorterBy(height, bmp, x + 1, z) || IsShorterBy(height, pixels, x + 1, z) ||
IsShorterBy(height, bmp, x, z - 1) || IsShorterBy(height, pixels, x, z - 1) ||
IsShorterBy(height, bmp, x, z + 1)) IsShorterBy(height, pixels, x, z + 1))
{ {
layer = Block.Stone; top = Block.Stone; layer = Block.Stone; top = Block.Stone;
} }
@ -109,12 +112,13 @@ namespace MCGalaxy.Generator {
index++; index++;
} }
} }
}
return true; return true;
} }
static bool IsShorterBy(int height, Bitmap bmp, int x, int z) { static bool IsShorterBy(int height, PixelGetter pixels, int x, int z) {
if (x >= bmp.Width || x < 0 || z >= bmp.Height || z < 0) return false; if (x >= pixels.Width || x < 0 || z >= pixels.Height || z < 0) return false;
int neighbourHeight = bmp.GetPixel(x, z).R; int neighbourHeight = pixels.Get(x, z).R;
return height >= neighbourHeight + 2; return height >= neighbourHeight + 2;
} }
} }