public MaterialImage GenerateSeedImageBmp(WorldSystem.Region tregion, int minx, int miny, int maxx, int maxy, int wid) { MaterialImage bmp = new MaterialImage() { Colors = new FastColor[wid * wid], Width = wid, Height = wid }; double one_div_wid = 1.0 / wid; for (int x = 0; x < wid; x++) { for (int y = 0; y < wid; y++) { double h = tregion.Generator.GetHeight(tregion.TheWorld.Seed, tregion.TheWorld.Seed2, tregion.TheWorld.Seed3, tregion.TheWorld.Seed4, tregion.TheWorld.Seed5, minx + (maxx - minx) * x * one_div_wid, miny + (maxy - miny) * y * one_div_wid, 0, out Biome b); Material renderme; if (h > 0) { renderme = b.GetAboveZeromat(); } else { renderme = b.GetZeroOrLowerMat(); } bmp.SetAt(x, y, MaterialImages[(int)renderme].Colors[0]); } } return(bmp); }
public byte[] MatImgToPng(MaterialImage img) { using (Bitmap bmp = new Bitmap(img.Width, img.Height)) { BitmapData bdat = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); int stride = bdat.Stride; // Surely there's a better way to do this! unsafe { byte *ptr = (byte *)bdat.Scan0; for (int x = 0; x < img.Width; x++) { for (int y = 0; y < img.Height; y++) { FastColor tcol = img.GetAt(x, y); ptr[(x * 4) + y * stride + 0] = tcol.B; ptr[(x * 4) + y * stride + 1] = tcol.G; ptr[(x * 4) + y * stride + 2] = tcol.R; ptr[(x * 4) + y * stride + 3] = tcol.A; } } } using (DataStream ds = new DataStream()) { bmp.Save(ds, ImageFormat.Png); return(ds.ToArray()); } } }
public void Init(Server tserver) { // TODO: v0.1.0 texture config update! MaterialImages = new MaterialImage[MaterialHelpers.Textures.Length]; for (int i = 0; i < MaterialImages.Length; i++) { string tex = MaterialHelpers.Textures[i]; string actualtexture = "textures/" + tex.Before(",").Before("&").Before("$").Before("@") + ".png"; try { Bitmap bmp1 = new Bitmap(tserver.Files.ReadToStream(actualtexture)); Bitmap bmp2 = new Bitmap(bmp1, new Size(TexWidth, TexWidth)); bmp1.Dispose(); MaterialImage img = new MaterialImage(); img.Colors = new Color[TexWidth, TexWidth]; for (int x = 0; x < TexWidth; x++) { for (int y = 0; y < TexWidth; y++) { img.Colors[x, y] = bmp2.GetPixel(x, y); } } MaterialImages[i] = img; bmp2.Dispose(); } catch (Exception ex) { Utilities.CheckException(ex); SysConsole.Output("loading texture for " + i + ": '" + actualtexture + "'", ex); } } SysConsole.Output(OutputType.INIT, "Loaded " + MaterialImages.Length + " textures!"); }
void DrawImage(MaterialImage bmp, MaterialImage bmpnew, int xmin, int ymin, Color col) { for (int x = 0; x < TexWidth; x++) { for (int y = 0; y < TexWidth; y++) { Color basepx = bmp.Colors[xmin + x, ymin + y]; bmp.Colors[xmin + x, ymin + y] = Blend(Multiply(bmpnew.Colors[x, y], col), basepx); } } }
public byte[] GetChunkRenderLD(WorldSystem.Region tregion, int tx, int ty, int tz) { int wid = Constants.CHUNK_WIDTH; int divvy = GetDividerForZ(tz) * Constants.CHUNK_WIDTH; MaterialImage bmp = GenerateSeedImageBmp(tregion, tx * divvy, ty * divvy, (tx + 1) * divvy, (ty + 1) * divvy, wid); KeyValuePair <byte[], byte[]> bitters = tregion.ChunkManager.GetTopsHigher(tx, ty, tz); byte[] bits = bitters.Key; byte[] bits_trans = bitters.Value; if (bits == null || bits_trans == null) { return(MatImgToPng(bmp)); } for (int x = 0; x < Constants.CHUNK_WIDTH; x++) { for (int y = 0; y < Constants.CHUNK_WIDTH; y++) { int ind = tregion.TopsHigherBlockIndex(x, y); ushort mat = Utilities.BytesToUshort(Utilities.BytesPartial(bits, ind * 2, 2)); FastColor fc; if (mat == 0) { fc = new FastColor() { A = 0 }; } else { MaterialImage imag = MaterialImages[mat]; fc = imag.GetAt(0, 0); } for (int i = 3; i >= 0; i--) { mat = Utilities.BytesToUshort(Utilities.BytesPartial(bits_trans, ind * 2 * 4, 2)); if (mat != 0) { MaterialImage simag = MaterialImages[mat]; FastColor fc2 = simag.Colors[0]; fc = Blend(fc2, fc); } } fc = Blend(fc, bmp.GetAt(x, y)); bmp.SetAt(x, y, fc); } } // TODO: Add entity icons? (Trees in particular!) return(MatImgToPng(bmp)); }
void RenderChunkInternalAngle(WorldSystem.Region tregion, Vector3i chunkCoords, Chunk chunk) { MaterialImage bmp = new MaterialImage() { Colors = new Color[BmpSize2, BmpSize2] }; for (int z = 0; z < Chunk.CHUNK_SIZE; z++) { for (int x = 0; x < Chunk.CHUNK_SIZE; x++) { for (int y = 0; y < Chunk.CHUNK_SIZE; y++) { // TODO: async chunk read locker? BlockInternal bi = chunk.GetBlockAt(x, y, z); if (bi.Material.RendersAtAll()) { RenderBlockIntoAngle(bi, x, y, z, bmp); } } } } Bitmap tbmp = new Bitmap(BmpSize2, BmpSize2); BitmapData bdat = tbmp.LockBits(new Rectangle(0, 0, tbmp.Width, tbmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); int stride = bdat.Stride; // Surely there's a better way to do this! unsafe { byte *ptr = (byte *)bdat.Scan0; for (int x = 0; x < BmpSize2; x++) { for (int y = 0; y < BmpSize2; y++) { Color tcol = bmp.Colors[x, y]; ptr[(x * 4) + y * stride + 0] = tcol.B; ptr[(x * 4) + y * stride + 1] = tcol.G; ptr[(x * 4) + y * stride + 2] = tcol.R; ptr[(x * 4) + y * stride + 3] = tcol.A; } } } DataStream ds = new DataStream(); tbmp.Save(ds, ImageFormat.Png); tregion.ChunkManager.WriteImageAngle((int)chunkCoords.X, (int)chunkCoords.Y, (int)chunkCoords.Z, ds.ToArray()); }
void DrawImageShiftY(MaterialImage bmp, MaterialImage bmpnew, int xmin, int ymin, Color col) { for (int x = 0; x < TexWidth; x++) { for (int y = 0; y < TexWidth; y++) { int sx = xmin + x; int sy = ymin + y; if (sx < 0 || sy < 0 || sx >= BmpSize2 || sy >= BmpSize2) { continue; } Color basepx = bmp.Colors[sx, sy]; bmp.Colors[sx, sy] = Blend(Multiply(bmpnew.Colors[x, y], col), basepx); } } }
public void Init(Server tserver) { MaterialImages = new MaterialImage[MaterialHelpers.ALL_MATS.Count]; for (int i = 0; i < MaterialImages.Length; i++) { string tex = MaterialHelpers.ALL_MATS[i].Texture[(int)MaterialSide.TOP][0]; string actualtexture = "textures/" + tex.Before(",").Before("&").Before("$").Before("@") + ".png"; try { Bitmap bmp1 = new Bitmap(tserver.Files.ReadToStream(actualtexture)); // TODO: Resize options/control? Bitmap bmp2 = new Bitmap(bmp1, new Size(TexWidth, TexWidth)); bmp1.Dispose(); MaterialImage img = new MaterialImage() { Width = TexWidth, Height = TexWidth, Colors = new FastColor[TexWidth * TexWidth] }; for (int x = 0; x < TexWidth; x++) { for (int y = 0; y < TexWidth; y++) { // TODO: Effic? Color t = bmp2.GetPixel(x, y); img.SetAt(x, y, new FastColor() { R = t.R, G = t.G, B = t.B, A = t.A }); } } MaterialImages[i] = img; bmp2.Dispose(); } catch (Exception ex) { Utilities.CheckException(ex); SysConsole.Output("loading texture for " + i + ": '" + actualtexture + "'", ex); } } SysConsole.Output(OutputType.INIT, "Loaded " + MaterialImages.Length + " textures!"); }
void RenderBlockIntoAngle(BlockInternal bi, int x, int y, int z, MaterialImage bmp) { MaterialImage zmatbmpXP = MaterialImages[bi.Material.TextureID(MaterialSide.XP)]; MaterialImage zmatbmpYP = MaterialImages[bi.Material.TextureID(MaterialSide.YP)]; MaterialImage zmatbmpZP = MaterialImages[bi.Material.TextureID(MaterialSide.TOP)]; if (zmatbmpXP == null || zmatbmpYP == null || zmatbmpZP == null) { return; } Color zcolor = Colors.ForByte(bi.BlockPaint); if (zcolor.A == 0) { zcolor = Color.White; } int x1 = x * TexWidth; int y1 = y * TexWidth; int z1 = z * TexWidth; // int xw = x * TexWidth; // int yw = y * TexWidth; // tileWidth/2*x+tileHeight/2*y, tileWidth/2*x+tileHeight/2*y // int xw = TexWidth * x / 2 + TexWidth * y / 2; // int yw = TexWidth * x / 2 + TexWidth * y / 2; // tempPt.x = pt.x - pt.y; tempPt.y = (pt.x + pt.y) / 2; int xw = x1 - y1; int yw = ((x1 + y1) - (z1)) / 2; // tempPt.x = (2 * pt.y + pt.x) / 2; tempPt.y = (2 * pt.y - pt.x) / 2; // int xw = (2 * y1 + x1) / 2; // int yw = (2 * y1 - x1) / 2; xw += BmpSize2 / 2; yw += BmpSize2 / 2; DrawImageShiftX(bmp, zmatbmpXP, xw, yw, zcolor); DrawImageShiftY(bmp, zmatbmpYP, xw, yw, zcolor); DrawImageShiftZ(bmp, zmatbmpZP, xw, yw, zcolor); }
public void Init(Server tserver) { // TODO: v0.1.0 texture config update! MaterialImages = new MaterialImage[MaterialHelpers.Textures.Length]; for (int i = 0; i < MaterialImages.Length; i++) { string tex = MaterialHelpers.Textures[i]; string actualtexture = "textures/" + tex.Before(",").Before("&").Before("$").Before("@")+ ".png"; try { Bitmap bmp1 = new Bitmap(tserver.Files.ReadToStream(actualtexture)); Bitmap bmp2 = new Bitmap(bmp1, new Size(TexWidth, TexWidth)); bmp1.Dispose(); MaterialImage img = new MaterialImage(); img.Colors = new Color[TexWidth, TexWidth]; for (int x = 0; x < TexWidth; x++) { for (int y = 0; y < TexWidth; y++) { img.Colors[x, y] = bmp2.GetPixel(x, y); } } MaterialImages[i] = img; bmp2.Dispose(); } catch (Exception ex) { Utilities.CheckException(ex); SysConsole.Output("loading texture for " + i + ": '" + actualtexture + "'", ex); } } SysConsole.Output(OutputType.INIT, "Loaded " + MaterialImages.Length + " textures!"); }
void RenderChunkInternalAngle(WorldSystem.Region tregion, Vector3i chunkCoords, Chunk chunk) { MaterialImage bmp = new MaterialImage() { Colors = new Color[BmpSize2, BmpSize2] }; for (int z = 0; z < Chunk.CHUNK_SIZE; z++) { for (int x = 0; x < Chunk.CHUNK_SIZE; x++) { for (int y = 0; y < Chunk.CHUNK_SIZE; y++) { // TODO: async chunk read locker? BlockInternal bi = chunk.GetBlockAt(x, y, z); if (bi.Material.RendersAtAll()) { RenderBlockIntoAngle(bi, x, y, z, bmp); } } } } Bitmap tbmp = new Bitmap(BmpSize2, BmpSize2); BitmapData bdat = tbmp.LockBits(new Rectangle(0, 0, tbmp.Width, tbmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); int stride = bdat.Stride; // Surely there's a better way to do this! unsafe { byte* ptr = (byte*)bdat.Scan0; for (int x = 0; x < BmpSize2; x++) { for (int y = 0; y < BmpSize2; y++) { Color tcol = bmp.Colors[x, y]; ptr[(x * 4) + y * stride + 0] = tcol.B; ptr[(x * 4) + y * stride + 1] = tcol.G; ptr[(x * 4) + y * stride + 2] = tcol.R; ptr[(x * 4) + y * stride + 3] = tcol.A; } } } DataStream ds = new DataStream(); tbmp.Save(ds, ImageFormat.Png); tregion.ChunkManager.WriteImageAngle((int)chunkCoords.X, (int)chunkCoords.Y, (int)chunkCoords.Z, ds.ToArray()); }
void RenderChunkInternal(WorldSystem.Region tregion, Vector3i chunkCoords, Chunk chunk) { Stopwatch sw = new Stopwatch(); sw.Start(); MaterialImage bmp = new MaterialImage() { Colors = new Color[BmpSize, BmpSize] }; for (int x = 0; x < Chunk.CHUNK_SIZE; x++) { for (int y = 0; y < Chunk.CHUNK_SIZE; y++) { // TODO: async chunk read locker? BlockInternal topOpaque = BlockInternal.AIR; int topZ = 0; for (int z = 0; z < Chunk.CHUNK_SIZE; z++) { BlockInternal bi = chunk.GetBlockAt(x, y, z); if (bi.IsOpaque()) { topOpaque = bi; topZ = z; } } if (!topOpaque.Material.RendersAtAll()) { DrawImage(bmp, MaterialImages[0], x * TexWidth, y * TexWidth, Color.Transparent); } for (int z = topZ; z < Chunk.CHUNK_SIZE; z++) { BlockInternal bi = chunk.GetBlockAt(x, y, z); if (bi.Material.RendersAtAll()) { MaterialImage zmatbmp = MaterialImages[bi.Material.TextureID(MaterialSide.TOP)]; if (zmatbmp == null) { continue; } Color zcolor = Colors.ForByte(bi.BlockPaint); if (zcolor.A == 0) { zcolor = Color.White; } DrawImage(bmp, zmatbmp, x * TexWidth, y * TexWidth, zcolor); } } } } sw.Stop(); Timings_A += sw.ElapsedTicks / (double)Stopwatch.Frequency; sw.Reset(); sw.Start(); Bitmap tbmp = new Bitmap(BmpSize2, BmpSize2); BitmapData bdat = tbmp.LockBits(new Rectangle(0, 0, tbmp.Width, tbmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); int stride = bdat.Stride; // Surely there's a better way to do this! unsafe { byte* ptr = (byte*)bdat.Scan0; for (int x = 0; x < BmpSize; x++) { for (int y = 0; y < BmpSize; y++) { Color tcol = bmp.Colors[x, y]; ptr[(x * 4) + y * stride + 0] = tcol.B; ptr[(x * 4) + y * stride + 1] = tcol.G; ptr[(x * 4) + y * stride + 2] = tcol.R; ptr[(x * 4) + y * stride + 3] = tcol.A; } } } tbmp.UnlockBits(bdat); sw.Stop(); Timings_B += sw.ElapsedTicks / (double)Stopwatch.Frequency; sw.Reset(); sw.Start(); DataStream ds = new DataStream(); tbmp.Save(ds, ImageFormat.Png); tbmp.Dispose(); sw.Stop(); Timings_C += sw.ElapsedTicks / (double)Stopwatch.Frequency; sw.Reset(); sw.Start(); lock (OneAtATimePlease) // NOTE: We can probably make this grab off an array of locks to reduce load a little. { KeyValuePair<int, int> maxes = tregion.ChunkManager.GetMaxes((int)chunkCoords.X, (int)chunkCoords.Y); tregion.ChunkManager.SetMaxes((int)chunkCoords.X, (int)chunkCoords.Y, Math.Min(maxes.Key, (int)chunkCoords.Z), Math.Max(maxes.Value, (int)chunkCoords.Z)); } tregion.ChunkManager.WriteImage((int)chunkCoords.X, (int)chunkCoords.Y, (int)chunkCoords.Z, ds.ToArray()); sw.Stop(); Timings_D += sw.ElapsedTicks / (double)Stopwatch.Frequency; }
void DrawImageShiftZ(MaterialImage bmp, MaterialImage bmpnew, int xmin, int ymin, Color col) { ymin -= TexWidth; xmin += TexWidth; for (int x = 0; x < TexWidth; x++) { for (int y = 0; y < TexWidth; y++) { int sx = xmin + x - y; int sy = ymin + y; if (sx < 0 || sy < 0 || sx >= BmpSize2 || sy >= BmpSize2) { continue; } Color basepx = bmp.Colors[sx, sy]; bmp.Colors[sx, sy] = Blend(Multiply(bmpnew.Colors[x, y], col), basepx); } } }
void RenderChunkInternal(WorldSystem.Region tregion, Vector3i chunkCoords, Chunk chunk) { Stopwatch sw = new Stopwatch(); sw.Start(); MaterialImage bmp = new MaterialImage() { Colors = new Color[BmpSize, BmpSize] }; for (int x = 0; x < Chunk.CHUNK_SIZE; x++) { for (int y = 0; y < Chunk.CHUNK_SIZE; y++) { // TODO: async chunk read locker? BlockInternal topOpaque = BlockInternal.AIR; int topZ = 0; for (int z = 0; z < Chunk.CHUNK_SIZE; z++) { BlockInternal bi = chunk.GetBlockAt(x, y, z); if (bi.IsOpaque()) { topOpaque = bi; topZ = z; } } if (!topOpaque.Material.RendersAtAll()) { DrawImage(bmp, MaterialImages[0], x * TexWidth, y * TexWidth, Color.Transparent); } for (int z = topZ; z < Chunk.CHUNK_SIZE; z++) { BlockInternal bi = chunk.GetBlockAt(x, y, z); if (bi.Material.RendersAtAll()) { MaterialImage zmatbmp = MaterialImages[bi.Material.TextureID(MaterialSide.TOP)]; if (zmatbmp == null) { continue; } Color zcolor = Colors.ForByte(bi.BlockPaint); if (zcolor.A == 0) { zcolor = Color.White; } DrawImage(bmp, zmatbmp, x * TexWidth, y * TexWidth, zcolor); } } } } sw.Stop(); Timings_A += sw.ElapsedTicks / (double)Stopwatch.Frequency; sw.Reset(); sw.Start(); Bitmap tbmp = new Bitmap(BmpSize2, BmpSize2); BitmapData bdat = tbmp.LockBits(new Rectangle(0, 0, tbmp.Width, tbmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); int stride = bdat.Stride; // Surely there's a better way to do this! unsafe { byte *ptr = (byte *)bdat.Scan0; for (int x = 0; x < BmpSize; x++) { for (int y = 0; y < BmpSize; y++) { Color tcol = bmp.Colors[x, y]; ptr[(x * 4) + y * stride + 0] = tcol.B; ptr[(x * 4) + y * stride + 1] = tcol.G; ptr[(x * 4) + y * stride + 2] = tcol.R; ptr[(x * 4) + y * stride + 3] = tcol.A; } } } tbmp.UnlockBits(bdat); sw.Stop(); Timings_B += sw.ElapsedTicks / (double)Stopwatch.Frequency; sw.Reset(); sw.Start(); DataStream ds = new DataStream(); tbmp.Save(ds, ImageFormat.Png); tbmp.Dispose(); sw.Stop(); Timings_C += sw.ElapsedTicks / (double)Stopwatch.Frequency; sw.Reset(); sw.Start(); lock (OneAtATimePlease) // NOTE: We can probably make this grab off an array of locks to reduce load a little. { KeyValuePair <int, int> maxes = tregion.ChunkManager.GetMaxes((int)chunkCoords.X, (int)chunkCoords.Y); tregion.ChunkManager.SetMaxes((int)chunkCoords.X, (int)chunkCoords.Y, Math.Min(maxes.Key, (int)chunkCoords.Z), Math.Max(maxes.Value, (int)chunkCoords.Z)); } tregion.ChunkManager.WriteImage((int)chunkCoords.X, (int)chunkCoords.Y, (int)chunkCoords.Z, ds.ToArray()); sw.Stop(); Timings_D += sw.ElapsedTicks / (double)Stopwatch.Frequency; }
public byte[] GetChunkRenderHD(WorldSystem.Region tregion, int tx, int ty, bool fullzoom) { const int wid = TexWidth * Constants.CHUNK_WIDTH; MaterialImage bmp = new MaterialImage() { Colors = new FastColor[wid * wid], Width = wid, Height = wid }; KeyValuePair <byte[], byte[]> bitters = tregion.ChunkManager.GetTops(tx, ty); byte[] xp = null; byte[] xm = null; byte[] yp = null; byte[] ym = null; if (!fullzoom) { xp = tregion.ChunkManager.GetTops(tx + 1, ty).Key; xm = tregion.ChunkManager.GetTops(tx - 1, ty).Key; yp = tregion.ChunkManager.GetTops(tx, ty + 1).Key; ym = tregion.ChunkManager.GetTops(tx, ty - 1).Key; } byte[] bits = bitters.Key; byte[] bits_trans = bitters.Value; if (bits == null || bits_trans == null) { return(null); } for (int x = 0; x < Constants.CHUNK_WIDTH; x++) { for (int y = 0; y < Constants.CHUNK_WIDTH; y++) { int ind = tregion.TopsHigherBlockIndex(x, y); ushort mat = Utilities.BytesToUshort(Utilities.BytesPartial(bits, ind * 2, 2)); MaterialImage imag = MaterialImages[mat]; if (fullzoom) { for (int sx = 0; sx < TexWidth; sx++) { for (int sy = 0; sy < TexWidth; sy++) { FastColor fc = imag.GetAt(sx, sy); fc.A = 255; for (int i = 3; i >= 0; i--) { ushort smat = Utilities.BytesToUshort(Utilities.BytesPartial(bits_trans, (ind * 4 + i) * 2, 2)); if (smat != 0) { MaterialImage simag = MaterialImages[smat]; FastColor fc2 = simag.GetAt(sx, sy); fc = Blend(fc2, fc); } } bmp.SetAt(x * TexWidth + sx, y * TexWidth + sy, fc); } } } else { int height = Utilities.BytesToInt(Utilities.BytesPartial(bits, CWCW2 + ind * 4, 4)); FastColor fc = imag.GetAt(0, 0); fc.A = 255; for (int i = 3; i >= 0; i--) { ushort smat = Utilities.BytesToUshort(Utilities.BytesPartial(bits_trans, ind * 2 * 4, 2)); if (smat != 0) { MaterialImage simag = MaterialImages[smat]; FastColor fc2 = simag.Colors[0]; fc = Blend(fc2, fc); } } FastColor lightened = fc; lightened.R = (byte)Math.Min(lightened.R + 20, 255); lightened.G = (byte)Math.Min(lightened.G + 20, 255); lightened.B = (byte)Math.Min(lightened.B + 20, 255); FastColor darkened = fc; darkened.R = (byte)Math.Max(darkened.R - 20, 0); darkened.G = (byte)Math.Max(darkened.G - 20, 0); darkened.B = (byte)Math.Max(darkened.B - 20, 0); FastColor doublelightened = fc; doublelightened.R = (byte)Math.Min(doublelightened.R + 40, 255); doublelightened.G = (byte)Math.Min(doublelightened.G + 40, 255); doublelightened.B = (byte)Math.Min(doublelightened.B + 40, 255); FastColor doubledarkened = fc; doubledarkened.R = (byte)Math.Max(doubledarkened.R - 40, 0); doubledarkened.G = (byte)Math.Max(doubledarkened.G - 40, 0); doubledarkened.B = (byte)Math.Max(doubledarkened.B - 40, 0); int relxp = x + 1 < Constants.CHUNK_WIDTH ? Utilities.BytesToInt(Utilities.BytesPartial(bits, CWCW2 + tregion.TopsHigherBlockIndex(x + 1, y) * 4, 4)) : (xp == null ? height : Utilities.BytesToInt(Utilities.BytesPartial(xp, CWCW2 + tregion.TopsHigherBlockIndex(0, y) * 4, 4))); int relyp = y + 1 < Constants.CHUNK_WIDTH ? Utilities.BytesToInt(Utilities.BytesPartial(bits, CWCW2 + tregion.TopsHigherBlockIndex(x, y + 1) * 4, 4)) : (yp == null ? height : Utilities.BytesToInt(Utilities.BytesPartial(yp, CWCW2 + tregion.TopsHigherBlockIndex(x, 0) * 4, 4))); int relxm = x - 1 >= 0 ? Utilities.BytesToInt(Utilities.BytesPartial(bits, CWCW2 + tregion.TopsHigherBlockIndex(x - 1, y) * 4, 4)) : (xm == null ? height : Utilities.BytesToInt(Utilities.BytesPartial(xm, CWCW2 + tregion.TopsHigherBlockIndex(Constants.CHUNK_WIDTH - 1, y) * 4, 4))); int relym = y - 1 >= 0 ? Utilities.BytesToInt(Utilities.BytesPartial(bits, CWCW2 + tregion.TopsHigherBlockIndex(x, y - 1) * 4, 4)) : (ym == null ? height : Utilities.BytesToInt(Utilities.BytesPartial(ym, CWCW2 + tregion.TopsHigherBlockIndex(x, Constants.CHUNK_WIDTH - 1) * 4, 4))); bmp.SetAt(x * 4 + 0, y * 4 + 0, ((relym < height) ? ((relxm < height) ? doublelightened : (relxm > height ? fc : lightened)) : ((relym > height) ? ((relxm < height) ? fc : ((relxm > height) ? doubledarkened : darkened)) : ((relxm < height) ? lightened : ((relxm > height) ? darkened : fc))))); bmp.SetAt(x * 4 + 1, y * 4 + 0, (relym < height) ? lightened : ((relym > height) ? darkened : fc)); bmp.SetAt(x * 4 + 2, y * 4 + 0, (relym < height) ? lightened : ((relym > height) ? darkened : fc)); bmp.SetAt(x * 4 + 3, y * 4 + 0, (relym < height) ? ((relxp < height) ? doublelightened : ((relxp > height) ? fc : lightened)) : ((relym > height) ? ((relxp < height) ? fc : ((relxp > height) ? doubledarkened : darkened)) : ((relxp < height) ? lightened : ((relxp > height) ? darkened : fc)))); bmp.SetAt(x * 4 + 0, y * 4 + 1, (relxm < height) ? lightened : ((relxm > height) ? darkened : fc)); bmp.SetAt(x * 4 + 1, y * 4 + 1, fc); bmp.SetAt(x * 4 + 2, y * 4 + 1, fc); bmp.SetAt(x * 4 + 3, y * 4 + 1, (relxp < height) ? lightened : ((relxp > height) ? darkened : fc)); bmp.SetAt(x * 4 + 0, y * 4 + 2, (relxm < height) ? lightened : ((relxm > height) ? darkened : fc)); bmp.SetAt(x * 4 + 1, y * 4 + 2, fc); bmp.SetAt(x * 4 + 2, y * 4 + 2, fc); bmp.SetAt(x * 4 + 3, y * 4 + 2, (relxp < height) ? lightened : ((relxp > height) ? darkened : fc)); bmp.SetAt(x * 4 + 0, y * 4 + 3, (relxm < height) ? ((relyp < height) ? doublelightened : ((relyp > height) ? fc : lightened)) : ((relxm > height) ? ((relyp < height) ? lightened : ((relyp > height) ? doubledarkened : darkened)) : ((relyp < height) ? lightened : ((relyp > height) ? darkened : fc)))); bmp.SetAt(x * 4 + 1, y * 4 + 3, (relyp < height) ? lightened : ((relyp > height) ? darkened : fc)); bmp.SetAt(x * 4 + 2, y * 4 + 3, (relyp < height) ? lightened : ((relyp > height) ? darkened : fc)); bmp.SetAt(x * 4 + 3, y * 4 + 3, (relxp < height) ? ((relyp < height) ? doublelightened : ((relyp > height) ? fc : lightened)) : ((relxp > height) ? ((relyp < height) ? fc : ((relyp > height) ? doubledarkened : darkened)) : ((relyp < height) ? lightened : ((relyp > height) ? darkened : fc)))); } } } // TODO: Add entity icons? (Trees in particular!) return(MatImgToPng(bmp)); }