/* Phases: * 1 - Load image * 2 - Quantize/Prerender image * 3 - Generate blueprint/ map to colors * 4 - Generate PNG image (layer 1) * 4b - Generate layer 2 * 4c - Shadows * 4d - WorldEdit Origin * 4e - Grid * 4f - Border * 5 - Save to file */ public static async Task writePNG(System.Threading.CancellationToken _worker, string filePath, Bitmap inputImage) { Console.WriteLine("Resizing image..."); Bitmap resized = PngFormatter.ResizeAndFormatRawImage(inputImage); //inputImage.DisposeSafely(); Console.WriteLine("Quantizing image..."); PngFormatter.QuantizeImage(_worker, ref resized); Console.WriteLine("Converting pixels to Minecraft materials..."); BlueprintPA blueprint = await BlueprintPA.GetBluePrintAsync(_worker, resized); resized.DisposeSafely(); Console.WriteLine("Rendering to bitmap..."); Bitmap rendered = RenderBitmapFromBlueprint(_worker, blueprint, out int?textureSize); if (File.Exists(filePath)) { File.Delete(filePath); } rendered.Save(filePath, ImageFormat.Png); }
private static void renderCompactGraph(string filePath, BlueprintPA blueprint) { #region Settings int blockWidth = 1; int numHueFragments = 18; // How many buckets should we split out color wheel into? #endregion HashSet <Color> colors = GetColorsList(blueprint); var grayscale = colors.Where(x => x.GetSaturation() <= 0.20 || x.GetBrightness() <= 0.15 || x.GetBrightness() >= 0.85) .OrderBy(x => x.GetBrightness()); var grayscaleDark = grayscale.Where(x => x.GetBrightness() < 0.50).ToList(); var grayscaleLight = grayscale.Where(x => x.GetBrightness() >= 0.50).ToList(); var saturated = colors.Except(grayscale).ToList(); var allColorBuckets = new List <IGrouping <int, Color> >(); allColorBuckets.Add(new Grouping <int, Color>(-2, grayscaleLight)); allColorBuckets.Add(new Grouping <int, Color>(-1, grayscaleDark)); allColorBuckets.AddRange(saturated.GroupBy(x => ((int)Math.Round(x.GetHue())) / numHueFragments).OrderBy(x => x.Key).ToList()); int wGraph = allColorBuckets.Count * blockWidth; int hGraph = allColorBuckets.Count == 0 ? blockWidth : allColorBuckets.Where(x => x.Any()).Max(x => x.Count()) * blockWidth; using (Bitmap bm = new Bitmap(wGraph, hGraph, PixelFormat.Format32bppArgb)) { using (Graphics g = Graphics.FromImage(bm)) { g.InterpolationMode = InterpolationMode.NearestNeighbor; g.SmoothingMode = SmoothingMode.None; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None; using (SolidBrush brush = new SolidBrush(Color.Transparent)) { g.FillRectangle(brush, 0, 0, wGraph, hGraph); int xi = 0; foreach (var bucket in allColorBuckets) { var sortedBucket = bucket.OrderBy(x => x.GetBrightness()); for (int yi = 0; yi < sortedBucket.Count(); yi++) { brush.Color = sortedBucket.ElementAt(yi); g.FillRectangle(brush, xi * blockWidth, yi * blockWidth, blockWidth, blockWidth); } xi++; } } bm.Save(filePath, ImageFormat.Png); return; } } }
private static void renderCompactBrick(string filePath, BlueprintPA blueprint) { int blockWidth = 1; var colorsInOrder = GetColorsList(blueprint).OrderByColor(c => c).ToList(); const int MAX_BRICK_H = 9; int wBrick = (int)(Math.Ceiling((double)colorsInOrder.Count() / MAX_BRICK_H)) * blockWidth; int hBrick = MAX_BRICK_H * blockWidth; using (Bitmap bm = new Bitmap(wBrick, hBrick, PixelFormat.Format32bppArgb)) { using (Graphics g = Graphics.FromImage(bm)) { g.InterpolationMode = InterpolationMode.NearestNeighbor; g.SmoothingMode = SmoothingMode.None; g.PixelOffsetMode = PixelOffsetMode.None; using (SolidBrush brush = new SolidBrush(Color.Transparent)) { g.FillRectangle(brush, 0, 0, wBrick, hBrick); int xBrick = 0; int yBrick = 0; int incrementAmount = 1; foreach (Color c in colorsInOrder) { brush.Color = c; g.FillRectangle(brush, xBrick * blockWidth, yBrick * blockWidth, blockWidth, blockWidth); yBrick += incrementAmount; if (yBrick > MAX_BRICK_H - 1) { yBrick = MAX_BRICK_H - 1; incrementAmount = -1; xBrick++; } else if (yBrick < 0) { yBrick = 0; incrementAmount = 1; xBrick++; } } } bm.Save(filePath, ImageFormat.Png); return; } } }
public static void writeBlueprint(string filePath, BlueprintPA blueprint) { var nbt = new NbtCompound("Schematic"); bool isv = Options.Get.IsSideView; nbt.Add(new NbtShort("Width", (short)blueprint.Mapper.GetXLength(isv))); nbt.Add(new NbtShort("Height", (short)blueprint.Mapper.GetYLength(isv))); nbt.Add(new NbtShort("Length", (short)blueprint.Mapper.GetZLength(isv))); if (Options.Get.IsSideView) { //-z = + y nbt.Add(new NbtString("Materials", "Alpha")); WriteBlockDataAndIDs(nbt, blueprint, Options.Get.IsSideView); nbt.Add(new NbtList("Entities", NbtTagType.End)); nbt.Add(new NbtList("TileEntities", NbtTagType.End)); if (blueprint.WorldEditOrigin != null) { nbt.Add(new NbtInt("WEOriginX", 1)); nbt.Add(new NbtInt("WEOriginY", 1)); nbt.Add(new NbtInt("WEOriginZ", 1)); nbt.Add(new NbtInt("WEOffsetX", -blueprint.WorldEditOrigin.X)); nbt.Add(new NbtInt("WEOffsetY", blueprint.WorldEditOrigin.Y - blueprint.Height)); nbt.Add(new NbtInt("WEOffsetZ", Options.Get.IsMultiLayer ? -3 : -1)); } } else { nbt.Add(new NbtString("Materials", "Alpha")); WriteBlockDataAndIDs(nbt, blueprint, Options.Get.IsSideView); nbt.Add(new NbtList("Entities", NbtTagType.End)); nbt.Add(new NbtList("TileEntities", NbtTagType.End)); if (blueprint.WorldEditOrigin != null) { nbt.Add(new NbtInt("WEOriginX", 1)); nbt.Add(new NbtInt("WEOriginY", 1)); nbt.Add(new NbtInt("WEOriginZ", 1)); nbt.Add(new NbtInt("WEOffsetX", -blueprint.WorldEditOrigin.X)); nbt.Add(new NbtInt("WEOffsetY", 0)); nbt.Add(new NbtInt("WEOffsetZ", -blueprint.WorldEditOrigin.Y)); } } var serverFile = new NbtFile(nbt); serverFile.SaveToFile(filePath, NbtCompression.GZip); }
public static async Task writeSchemFromImage(System.Threading.CancellationToken _worker, string filePath, Bitmap inputImage) { Console.WriteLine("Resizing image..."); Bitmap resized = PngFormatter.ResizeAndFormatRawImage(inputImage); //inputImage.DisposeSafely(); Console.WriteLine("Quantizing image..."); PngFormatter.QuantizeImage(_worker, ref resized); Console.WriteLine("Converting pixels to Minecraft materials..."); BlueprintPA blueprint = await BlueprintPA.GetBluePrintAsync(_worker, resized); resized.DisposeSafely(); Schem2Formatter.writeBlueprint(filePath, blueprint); }
private static HashSet <Color> GetColorsList(BlueprintPA blueprint) { HashSet <Color> colors = new HashSet <Color>(); for (int x = 0; x < blueprint.BlocksMap.GetLength(0); x++) { for (int y = 0; y < blueprint.BlocksMap.GetLength(1); y++) { var row = Color.FromArgb(blueprint.BlocksMap[x, y]); if (!colors.Contains(row)) { colors.Add(row); } } } return(colors); }
private static void WriteBlockDataAndIDs(NbtCompound nbt, BlueprintPA blueprint, bool isSideView) { Dictionary <string, short> schematicaDic = new Dictionary <string, short>(); //int depth = Options.Get.IsMultiLayer ? 3 : 1; byte[] bs = new byte[blueprint.Mapper.GetXLength(isSideView) * blueprint.Mapper.GetYLength(isSideView) * blueprint.Mapper.GetZLength(isSideView)]; byte[] bsD = new byte[blueprint.Mapper.GetXLength(isSideView) * blueprint.Mapper.GetYLength(isSideView) * blueprint.Mapper.GetZLength(isSideView)]; int ti = 0; //-z = + y for (int y = blueprint.Mapper.GetYLength(isSideView) - 1; y >= 0; y--) { for (int z = 0; z < blueprint.Mapper.GetZLength(isSideView); z++) { for (int x = 0; x < blueprint.Mapper.GetXLength(isSideView); x++) { Material ma = blueprint.Mapper.GetMaterialAt(isSideView, x, y, z); schematicaDic[ma.SchematicaMaterialName ?? "minecraft:barrier"] = Convert.ToInt16(ma.BlockID); bsD[ti] = Convert.ToByte(ma?.Data ?? 0); bs[ti++] = Convert.ToByte(ma?.BlockID ?? 0); } } } var schematicaIcon = new NbtCompound("Icon", new List <NbtTag>() { new NbtByte("Count", 1), new NbtShort("Damage", 0), new NbtString("id", "minecraft:white_wool") }); nbt.Add(schematicaIcon); var schematicaMapping = new NbtCompound("SchematicaMapping"); schematicaDic.ToList().ForEach(kvp => { schematicaMapping.Add(new NbtShort(kvp.Key, kvp.Value)); }); nbt.Add(schematicaMapping); nbt.Add(new NbtByteArray("Blocks", bs)); nbt.Add(new NbtByteArray("Data", bsD)); }
public static void writeBlueprint(string filePath, BlueprintPA blueprint, ColorPaletteStyle style) { if (ColorPaletteStyle.CompactBrick == style) { renderCompactBrick(filePath, blueprint); } else if (ColorPaletteStyle.CompactGraph == style) { renderCompactGraph(filePath, blueprint); } else if (ColorPaletteStyle.DetailedGrid == style) { renderDetailedGrid(filePath, blueprint, true); } else if (ColorPaletteStyle.CompactGrid == style) { renderDetailedGrid(filePath, blueprint, false); } }
public static void WriteBlueprint(string filePath, BlueprintPA blueprint, ColorPaletteStyle style) { if (ColorPaletteStyle.CompactBrick == style) { using (var img = RenderCompactBrick(blueprint)) { img.Save(filePath); } } else if (ColorPaletteStyle.CompactGraph == style) { using (var img = RenderCompactGraph(blueprint, false)) { img.Save(filePath); } } else if (ColorPaletteStyle.CompactSquare == style) { using (var img = RenderCompactGraph(blueprint, true)) { img.Save(filePath); } } else if (ColorPaletteStyle.DetailedGrid == style) { using (var img = RenderDetailedGrid(blueprint, true)) { img.Save(filePath); } } else if (ColorPaletteStyle.CompactGrid == style) { using (var img = RenderDetailedGrid(blueprint, false)) { img.Save(filePath); } } }
private static void renderDetailedGrid2(string filePath, BlueprintPA blueprint) { #region Settings int blockWidth = 16; int gapBetweenColumns = 2; int gapBetweenRows = 2; int gapOnBorder = 1; int numColumns = 2; int numRows = 7; bool isSide = Options.Get.IsSideView; #endregion List <Material> glasses = Materials.List.Where(m => m.Category == "Glass").ToList(); List <IGrouping <string, Material> > materialGroups = Materials.List.Where(m => m.Category != "Glass" && m.Label != "Air").GroupBy(m => m.Category).ToList(); int numGroups = materialGroups.Count; int numBlocksPerRow = 1 + glasses.Count; // 16 glass + 1 regular int numBlocksPerColumn = 1 + materialGroups.Max(mg => mg.Count()); // 16 glass + 1 regular int wGrid = blockWidth * ( (2 * gapOnBorder) + (numColumns * numBlocksPerRow) + ((numColumns - 1) * gapBetweenRows) ); int hGrid = blockWidth * ( (2 * gapOnBorder) + (numRows * numBlocksPerColumn) + ((numRows - 1) * gapBetweenColumns) ); // total groups CURRENTLY is... 14, plus glass. using (Bitmap bm = new Bitmap(wGrid, hGrid, PixelFormat.Format32bppArgb)) { using (Graphics g = Graphics.FromImage(bm)) { g.InterpolationMode = InterpolationMode.NearestNeighbor; g.SmoothingMode = SmoothingMode.None; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None; int row = 0; int col = 0; foreach (var materialGroup in materialGroups) { int materialIndex = 0; foreach (var material in materialGroup) { int xOffsetMaterials = blockWidth * (1 + gapOnBorder + (col * gapBetweenColumns) + (col * numBlocksPerColumn) ); int yOffsetMaterials = blockWidth * (1 + gapOnBorder + (row * gapBetweenRows) + (row * numBlocksPerRow) + (materialIndex++) // should go all the way up to 17 or whatever it is ); var img = material.getImage(isSide); for (int glassIndex = 0; glassIndex <= glasses.Count; glassIndex++) { int xOffsetMaterialsWithGlassIndex = xOffsetMaterials + (glassIndex * blockWidth) - blockWidth; g.DrawImage(img, xOffsetMaterialsWithGlassIndex, yOffsetMaterials, blockWidth, blockWidth); } } for (int glassIndex = 0; glassIndex < glasses.Count; glassIndex++) { int xOffsetGlass = blockWidth * (1 + gapOnBorder + (col * gapBetweenColumns) + (col * numBlocksPerColumn) + (glassIndex) ); var imgGlass = glasses[glassIndex].getImage(isSide); for (int materialItemIndex = 0; materialItemIndex <= materialGroup.Count(); materialItemIndex++) { int yOffsetGlass = blockWidth * (gapOnBorder + (row * gapBetweenRows) + (row * numBlocksPerRow) + (materialItemIndex) // should go all the way up to 17 or whatever it is ); g.DrawImage(imgGlass, xOffsetGlass, yOffsetGlass, blockWidth, blockWidth ); } } col++; if (col >= numColumns) { col = 0; row++; } } } //for (int y = 0; y < numGroups; y++) //{ // int columnOff // var materialGroup = materialGroups[y].ToList(); // for (int mi = 0; mi < materialGroup.Count; mi++) // { // var material = materialGroup[mi]; // var img = material.getImage(isSide); // for (int x = 0; x < numBlocksPerRow; x++) // { // int xImg = (x + gapOnBorder) * blockWidth; // int yImg = (mi + gapOnBorder) * blockWidth; // g.DrawImage(img, xImg, yImg, blockWidth, blockWidth); // } // } //} //using (SolidBrush brush = new SolidBrush(Color.Transparent)) //{ // g.FillRectangle(brush, 0, 0, wGraph, hGraph); // int xi = 0; // foreach (var bucket in allColorBuckets) // { // var sortedBucket = bucket.OrderBy(x => x.GetBrightness()); // for (int yi = 0; yi < sortedBucket.Count(); yi++) // { // brush.Color = sortedBucket.ElementAt(yi); // g.FillRectangle(brush, xi * blockWidth, yi * blockWidth, blockWidth, blockWidth); // } // xi++; // } //} bm.Save(filePath, ImageFormat.Png); return; } }
private static void renderDetailedGrid(string filePath, BlueprintPA blueprint, bool isDetailed) { #region Settings bool isImageMode = isDetailed; int gapBetweenColumns = 1; int gapBetweenRows = 1; int gapOnBorder = 1; bool isSide = Options.Get.IsSideView; #endregion #region GROUPINGS OF MATERIALS List <Material> glasses = Materials.List.Where(m => m.Category == "Glass") .OrderByColor(m => m.getAverageColor(isSide)).ToList(); List <IGrouping <string, Material> > materialGroups = Materials.List .Where(m => m.Category != "Glass" && m.Label != "Air") .GroupBy(m => m.Category) .OrderByDescending(m => m.Count()) .ToList(); List <List <Material> > leftSide = new List <List <Material> >(); List <List <Material> > rightSide = new List <List <Material> >(); for (int i = 0; i < materialGroups.Count; i++) { if (i % 2 == 0) { leftSide.Add(materialGroups[i].OrderByColor(m => m.getAverageColor(isSide)).ToList()); } else { rightSide.Add(materialGroups[i].OrderByColor(m => m.getAverageColor(isSide)).ToList()); } } #endregion #region GROUPINGS OF SIZES int blockWidth = isImageMode ? 16 : 1; int totalWidth = blockWidth * ( +(gapBetweenColumns) + (gapOnBorder * 2) // 1 border each side + (17 * 2)); // two palettes int totalHeight = blockWidth * Math.Max( leftSide.Sum(mg => mg.Count() + 1) /* materials + glass index */ + (gapOnBorder * 2) // top/bottom borders + (leftSide.Count - 1), // gaps between rows rightSide.Sum(mg => mg.Count() + 1) /* materials + glass index*/ + (gapOnBorder * 2) // top/bottom borders + (leftSide.Count - 1) // gaps between rows ); #endregion int xOffset = blockWidth; int yOffset = 0; using (Bitmap bm = new Bitmap(totalWidth, totalHeight, PixelFormat.Format32bppArgb)) { using (Graphics g = Graphics.FromImage(bm)) { g.InterpolationMode = InterpolationMode.NearestNeighbor; g.SmoothingMode = SmoothingMode.None; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None; using (SolidBrush b = new SolidBrush(Color.Black)) { foreach (var left in rightSide) { for (int mi = -1; mi < left.Count; mi++) { for (int z = 0; z < 17; z++) { if (mi != -1) { Material mat = left[mi]; if (isImageMode) { var img = mat.getImage(isSide); g.DrawImage(img, xOffset + (z * blockWidth), yOffset + blockWidth, blockWidth, blockWidth); } else { b.Color = mat.getAverageColor(isSide); g.FillRectangle(b, xOffset + (z * blockWidth), yOffset + blockWidth, blockWidth, blockWidth); } } if (z != 0) // < 17 { if (isImageMode) { var imgGlass = glasses[z - 1].getImage(isSide); g.DrawImage(imgGlass, xOffset + (z * blockWidth), yOffset + blockWidth, blockWidth, blockWidth); } else { b.Color = glasses[z - 1].getAverageColor(isSide); g.FillRectangle(b, xOffset + (z * blockWidth), yOffset + blockWidth, blockWidth, blockWidth); } } } yOffset += blockWidth; } yOffset += gapBetweenRows * blockWidth;// GAP between the sections } xOffset += (17 + gapBetweenColumns) * blockWidth; yOffset = 0; foreach (var left in leftSide) { for (int mi = -1; mi < left.Count; mi++) { for (int z = 0; z < 17; z++) { if (mi != -1) { Material mat = left[mi]; if (isImageMode) { var img = mat.getImage(isSide); g.DrawImage(img, xOffset + (z * blockWidth), yOffset + blockWidth, blockWidth, blockWidth); } else { b.Color = mat.getAverageColor(isSide); g.FillRectangle(b, xOffset + (z * blockWidth), yOffset + blockWidth, blockWidth, blockWidth); } } if (z != 0) // < 17 { if (isImageMode) { var imgGlass = glasses[z - 1].getImage(isSide); g.DrawImage(imgGlass, xOffset + (z * blockWidth), yOffset + blockWidth, blockWidth, blockWidth); } else { b.Color = glasses[z - 1].getAverageColor(isSide); g.FillRectangle(b, xOffset + (z * blockWidth), yOffset + blockWidth, blockWidth, blockWidth); } } } yOffset += blockWidth; } yOffset += gapBetweenRows * blockWidth;// GAP between the sections } } } bm.Save(filePath, ImageFormat.Png); return; } }
public static void writeBlueprint(string filePath, BlueprintPA blueprint) { bool isv = Options.Get.IsSideView; #region metadata var metadata = new NbtCompound("Metadata"); metadata.Add(new NbtString("Name", "NameOfSchematic")); metadata.Add(new NbtString("Author", "Taylor Love")); metadata.Add(new NbtString("Generator", "PixelStacker (" + Constants.Version + ")")); metadata.Add(new NbtString("Generator Website", Constants.Website)); metadata.Add(new NbtList("RequiredMods", new List <NbtTag>(), NbtTagType.String)); metadata.Add(new NbtInt("WEOriginX", 1)); metadata.Add(new NbtInt("WEOriginY", 1)); metadata.Add(new NbtInt("WEOriginZ", 1)); if (blueprint.WorldEditOrigin != null) { metadata.Add(new NbtInt("WEOffsetX", -blueprint.WorldEditOrigin.X)); if (isv) { metadata.Add(new NbtInt("WEOffsetY", blueprint.WorldEditOrigin.Y - blueprint.Mapper.GetYLength(isv))); metadata.Add(new NbtInt("WEOffsetZ", -blueprint.Mapper.GetZLength(isv))); // Options.Get.IsMultiLayer ? -3 : -1 } else { metadata.Add(new NbtInt("WEOffsetY", 0)); metadata.Add(new NbtInt("WEOffsetZ", -blueprint.WorldEditOrigin.Y)); } } #endregion var nbt = new NbtCompound("Schematic"); // Missing "Offset" which defaults to [0,0,0]. Basically the world offset. Coordinates. nbt.Add(new NbtInt("Version", 1)); nbt.Add(new NbtShort("Width", (short)blueprint.Mapper.GetXLength(isv))); nbt.Add(new NbtShort("Height", (short)blueprint.Mapper.GetYLength(isv))); nbt.Add(new NbtShort("Length", (short)blueprint.Mapper.GetZLength(isv))); nbt.Add(new NbtIntArray("Offset", new int[] { 0, 0, 0 })); nbt.Add(metadata); //PaletteMax integer Specifies the size of the block palette in number of bytes needed for the maximum palette index.Implementations may use this as a hint for the case that the palette data fits within a datatype smaller than a 32 - bit integer that they may allocate a smaller sized array. //Palette Palette Object Specifies the block palette.This is a mapping of block states to indices which are local to this schematic.These indices are used to reference the block states from within the BlockData array.It is recommeneded for maximum data compression that your indices start at zero and skip no values.The maximum index cannot be greater than PaletteMax - 1.While not required it is highly recommended that you include a palette in order to tightly pack the block ids included in the data array. //BlockData varint[] Required.Specifies the main storage array which contains Width * Height * Length entries.Each entry is specified as a varint and refers to an index within the Palette.The entries are indexed by x + z * Width + y * Width * Length. //TileEntities TileEntity Object[] Specifies additional data for blocks which require extra data.If no additional data is provided for a block which normally requires extra data then it is assumed that the TileEntity for the block is initialized to its default state. var palette = new Dictionary <string, int>(); var tileEntities = new List <NbtCompound>(); //Required.Specifies the main storage array which contains Width *Height * Length entries.Each entry is specified //as a varint and refers to an index within the Palette.The entries are indexed by //x +z * Width + y * Width * Length. using (MemoryStream ms = new MemoryStream()) { using (BinaryWriter buffer = new BinaryWriter(ms)) { int xMax = blueprint.Mapper.GetXLength(isv); int yMax = blueprint.Mapper.GetYLength(isv); int zMax = blueprint.Mapper.GetZLength(isv); for (int y = yMax - 1; y >= 0; y--) { for (int z = 0; z < zMax; z++) { for (int x = 0; x < xMax; x++) { Material m = blueprint.Mapper.GetMaterialAt(isv, x, y, z); string key = m.GetBlockNameAndData(isv); if (!palette.ContainsKey(key)) { palette.Add(key, palette.Count); } int blockId = palette[key]; if (blockId <= Byte.MaxValue) { buffer.Write((byte)blockId); } else if (blockId <= short.MaxValue) { buffer.Write((short)blockId); } else if (blockId <= int.MaxValue) { buffer.Write((int)blockId); } //while ((blockId & -128) != 0) //{ // byte b = (byte)(blockId & 127 | 128); // buffer.Write(b); // blockId >>= 7; // //blockId >>> = 7; //} //byte b2 = (byte)(blockId & 127 | 128); //buffer.Write(b2); //buffer.Write((short)blockId); //buffer.Write((byte)blockId); } } } } // size of block palette in number of bytes needed for the maximum palette index. Implementations may use // this as a hint for the case that the palette data fits within a datatype smaller than a 32 - bit integer // that they may allocate a smaller sized array. nbt.Add(new NbtInt("PaletteMax", palette.Count)); var paletteTag = new NbtCompound("Palette"); foreach (var kvp in palette) { paletteTag.Add(new NbtInt(kvp.Key, kvp.Value)); } nbt.Add(paletteTag); var blockData = ms.ToArray(); nbt.Add(new NbtByteArray("BlockData", blockData)); } nbt.Add(new NbtList("TileEntities", NbtTagType.End)); var serverFile = new NbtFile(nbt); serverFile.SaveToFile(filePath, NbtCompression.GZip); }
public static Bitmap RenderDetailedGrid2(BlueprintPA blueprint) { #region Settings int blockWidth = 16; int gapBetweenColumns = 2; int gapBetweenRows = 2; int gapOnBorder = 1; int numColumns = 2; int numRows = 7; bool isSide = Options.Get.IsSideView; #endregion List <Material> glasses = Materials.List.Where(m => m.Category == "Glass").ToList(); List <IGrouping <string, Material> > materialGroups = Materials.List.Where(m => m.Category != "Glass" && m.PixelStackerID != "AIR").GroupBy(m => m.Category).ToList(); int numGroups = materialGroups.Count; int numBlocksPerRow = 1 + glasses.Count; // 16 glass + 1 regular int numBlocksPerColumn = 1 + materialGroups.Max(mg => mg.Count()); // 16 glass + 1 regular int wGrid = blockWidth * ( (2 * gapOnBorder) + (numColumns * numBlocksPerRow) + ((numColumns - 1) * gapBetweenRows) ); int hGrid = blockWidth * ( (2 * gapOnBorder) + (numRows * numBlocksPerColumn) + ((numRows - 1) * gapBetweenColumns) ); // total groups CURRENTLY is... 14, plus glass. using (Bitmap bm = new Bitmap(wGrid, hGrid, PixelFormat.Format32bppArgb)) { using (Graphics g = Graphics.FromImage(bm)) { g.InterpolationMode = InterpolationMode.NearestNeighbor; g.SmoothingMode = SmoothingMode.None; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None; int row = 0; int col = 0; foreach (var materialGroup in materialGroups) { int materialIndex = 0; foreach (var material in materialGroup) { int xOffsetMaterials = blockWidth * (1 + gapOnBorder + (col * gapBetweenColumns) + (col * numBlocksPerColumn) ); int yOffsetMaterials = blockWidth * (1 + gapOnBorder + (row * gapBetweenRows) + (row * numBlocksPerRow) + (materialIndex++) // should go all the way up to 17 or whatever it is ); var img = material.getImage(isSide); for (int glassIndex = 0; glassIndex <= glasses.Count; glassIndex++) { int xOffsetMaterialsWithGlassIndex = xOffsetMaterials + (glassIndex * blockWidth) - blockWidth; g.DrawImage(img, xOffsetMaterialsWithGlassIndex, yOffsetMaterials, blockWidth, blockWidth); } } for (int glassIndex = 0; glassIndex < glasses.Count; glassIndex++) { int xOffsetGlass = blockWidth * (1 + gapOnBorder + (col * gapBetweenColumns) + (col * numBlocksPerColumn) + (glassIndex) ); var imgGlass = glasses[glassIndex].getImage(isSide); for (int materialItemIndex = 0; materialItemIndex <= materialGroup.Count(); materialItemIndex++) { int yOffsetGlass = blockWidth * (gapOnBorder + (row * gapBetweenRows) + (row * numBlocksPerRow) + (materialItemIndex) // should go all the way up to 17 or whatever it is ); g.DrawImage(imgGlass, xOffsetGlass, yOffsetGlass, blockWidth, blockWidth ); } } col++; if (col >= numColumns) { col = 0; row++; } } } return(bm.To32bppBitmap()); } }
public static Bitmap RenderCompactGraph(BlueprintPA blueprint, bool isNormalized) { #region Settings int blockWidth = 1; #endregion HashSet <Color> colors = GetColorsList(blueprint); var grayscale = colors.Where(x => x.GetSaturation() <= 0.20 || x.GetBrightness() <= 0.15 || x.GetBrightness() >= 0.85) .OrderBy(x => x.GetBrightness()); var grayscaleDark = grayscale.Where(x => x.GetBrightness() < 0.50).ToList(); var grayscaleLight = grayscale.Where(x => x.GetBrightness() >= 0.50).ToList(); var saturated = colors.Except(grayscale).ToList(); var allColorBuckets = new List <IGrouping <int, Color> >(); if (isNormalized) { allColorBuckets.AddRange(SplitColors(colors)); } else { const int MIN_COLORS_IN_BUCKET = 5; var outputColorBuckets = new List <List <Color> >(); var inputColorBuckets = new List <List <Color> >(); inputColorBuckets.Add(grayscaleLight); inputColorBuckets.Add(grayscaleDark); inputColorBuckets.AddRange(saturated.GroupBy(x => ((int)Math.Round(x.GetHue())) / 9).OrderBy(x => x.Key).Select(x => x.ToList()).ToList()); var carry = new List <Color>(); for (int iBucket = 0; iBucket < inputColorBuckets.Count; iBucket++) { var cBucket = inputColorBuckets[iBucket]; cBucket.AddRange(carry); carry.Clear(); if (cBucket.Count() < MIN_COLORS_IN_BUCKET) { if (iBucket < inputColorBuckets.Count - 1) { carry.AddRange(cBucket); } else { outputColorBuckets.Add(cBucket); } } else { outputColorBuckets.Add(cBucket); } } int nBucket = 0; allColorBuckets.AddRange(outputColorBuckets.Select(xBucket => new Grouping <int, Color>(nBucket++, xBucket))); } int wGraph = allColorBuckets.Count * blockWidth; int hGraph = allColorBuckets.Count == 0 ? blockWidth : allColorBuckets.Where(x => x.Any()).Max(x => x.Count()) * blockWidth; using (Bitmap bm = new Bitmap(wGraph, hGraph, PixelFormat.Format32bppArgb)) { using (Graphics g = Graphics.FromImage(bm)) { g.InterpolationMode = InterpolationMode.NearestNeighbor; g.SmoothingMode = SmoothingMode.None; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None; using (SolidBrush brush = new SolidBrush(Color.Transparent)) { g.FillRectangle(brush, 0, 0, wGraph, hGraph); int xi = 0; foreach (var bucket in allColorBuckets) { var sortedBucket = bucket.OrderBy(x => x.GetBrightness()); for (int yi = 0; yi < sortedBucket.Count(); yi++) { brush.Color = sortedBucket.ElementAt(yi); g.FillRectangle(brush, xi * blockWidth, yi * blockWidth, blockWidth, blockWidth); } xi++; } } return(bm.To32bppBitmap()); } } }
//public static Material[][][] XYZ_to_YZX(Material[][][] xyz) //{ // int xD = xyz.Length; // int yD = xyz[0].Length; // int zD = xyz[0][0].Length; // Material[][][] yzx = new Material[yD][][]; // for (int y = 0; y < yD; y++) // { // yzx[y] = new Material[zD][]; // for (int z = 0; z < zD; z++) // { // yzx[y][z] = new Material[xD]; // for (int x = 0; x < xD; x++) // { // yzx[y][z][x] = xyz[x][y][z]; // } // } // } // return yzx; //} public static void writeBlueprint(string filePath, BlueprintPA blueprint) { bool isv = Options.Get.IsSideView; bool isMultiLayer = Options.Get.IsMultiLayer; Material[][][] region; var details = new Schem2Details(); int xD, yD, zD; if (isv) { xD = blueprint.BlocksMap.GetLength(0); yD = blueprint.BlocksMap.GetLength(1); zD = isMultiLayer ? 3 : 1; if (blueprint.WorldEditOrigin != null) { details.MetaData.WEOffsetX = -blueprint.WorldEditOrigin.X; details.MetaData.WEOffsetY = blueprint.WorldEditOrigin.Y - yD; details.MetaData.WEOffsetZ = -zD; } } else { xD = blueprint.BlocksMap.GetLength(0); yD = isMultiLayer ? 2 : 1; zD = blueprint.BlocksMap.GetLength(1); if (blueprint.WorldEditOrigin != null) { details.MetaData.WEOffsetX = -blueprint.WorldEditOrigin.X; details.MetaData.WEOffsetY = 0; details.MetaData.WEOffsetZ = -blueprint.WorldEditOrigin.Y; } } region = new Material[xD][][]; for (int xi = 0; xi < xD; xi++) { region[xi] = new Material[yD][]; for (int yi = 0; yi < yD; yi++) { region[xi][yi] = new Material[zD]; } } details.RegionXYZ = region; details.WidthX = xD; details.HeightY = yD; details.LengthZ = zD; // TODO: Populate based on ISV if (isv) { for (int xr = 0; xr < xD; xr++) { for (int yr = 0; yr < yD; yr++) { int ci = blueprint.BlocksMap[xr, yD - 1 - yr]; Color c = Color.FromArgb(ci); var mm = (ColorMatcher.Get.ColorToMaterialMap.TryGetValue(c, out Material[] found) ? found : null) ?? new Material[] { Materials.Air }; if (isMultiLayer) { region[xr][yr][0] = mm.Last(); region[xr][yr][1] = mm.First(); region[xr][yr][2] = mm.Last(); } else { region[xr][yD - yr - 1][0] = mm.First(); } } } } else { for (int xr = 0; xr < xD; xr++) { for (int zr = 0; zr < zD; zr++) { int ci = blueprint.BlocksMap[xr, zr]; // WARN: Maybe this needs to be zD - 1 - zr Color c = Color.FromArgb(ci); var mm = (ColorMatcher.Get.ColorToMaterialMap.TryGetValue(c, out Material[] found) ? found : null) ?? new Material[] { Materials.Air }; if (isMultiLayer) { region[xr][0][zr] = mm.First(); // If this turns out inside-out, then swap First with Last calls. region[xr][1][zr] = mm.Last(); } else { region[xr][0][zr] = mm.First(); } } } } writeBlueprintDirect(filePath, details); }
public CoordinateMapper(BlueprintPA blueprintPA) { this.blueprint = blueprintPA; }
public static Bitmap RenderBitmapFromBlueprint(CancellationToken?worker, BlueprintPA blueprint, out int?textureSize) { // TODO: Make sure this value is saved to the render panel instance somehow or else there will be horrible issues textureSize = RenderedImagePanel.CalculateTextureSize(blueprint); if (textureSize == null) { return(null); } if (blueprint != null) { try { TaskManager.SafeReport(0, "Preparing canvas for textures"); bool isSelectiveLayerViewEnabled = Options.Get.IsEnabled(Constants.RenderedZIndexFilter, false); bool isMaterialFilterViewEnabled = Options.Get.SelectedMaterialFilter.Any(); bool isSide = Options.Get.IsSideView; double origW = blueprint.Width; double origH = blueprint.Height; //int w = (int) (origW * MainForm.PanZoomSettings.zoomLevel); //int h = (int) (origH * MainForm.PanZoomSettings.zoomLevel); //int zoom = (int) (MainForm.PanZoomSettings.zoomLevel); SolidBrush brush = new SolidBrush(Color.Black); Pen pen = new Pen(brush); bool isMaterialIncludedInFilter = true; int mWidth = blueprint.Width; int mHeight = blueprint.Height; int mDepth = Options.Get.IsMultiLayer ? 2 : 1; int calcW = mWidth * textureSize.Value; int calcH = mHeight * textureSize.Value; TaskManager.SafeReport(20, "Preparing canvas for textures"); Bitmap bm = new Bitmap( width: calcW, height: calcH, format: PixelFormat.Format32bppArgb); TaskManager.SafeReport(50, "Preparing canvas for textures"); var selectedMaterials = Options.Get.SelectedMaterialFilter.AsEnumerable().ToList(); // clone bool _IsSolidColors = Options.Get.Rendered_IsSolidColors; bool _IsColorPalette = Options.Get.Rendered_IsColorPalette; bool _IsMultiLayer = Options.Get.IsMultiLayer; bool _isSkipShadowRendering = Options.Get.IsShadowRenderingSkipped; int _RenderedZIndexToShow = Options.Get.Rendered_RenderedZIndexToShow; bool _isFrugalAesthetic = Options.Get.IsExtraShadowDepthEnabled && !selectedMaterials.Any(); using (Graphics gImg = Graphics.FromImage(bm)) { gImg.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; gImg.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; gImg.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; #region Regular for (int z = 0; z < mDepth; z++) { TaskManager.SafeReport(0, "Applying textures... (Layer " + z + ")"); if (isSelectiveLayerViewEnabled) { if (z != _RenderedZIndexToShow) { continue; } } for (int x = 0; x < mWidth; x++) { TaskManager.SafeReport(100 * x / mWidth); worker?.SafeThrowIfCancellationRequested(); for (int y = 0; y < mHeight; y++) { int xi = x * textureSize.Value; int yi = y * textureSize.Value; //if (xi + MainForm.PanZoomSettings.zoomLevel >= 0 && yi + MainForm.PanZoomSettings.zoomLevel >= 0) { Material m = blueprint.GetMaterialAt(x, y, z, !_isFrugalAesthetic); if (isMaterialFilterViewEnabled) { string blockId = m.PixelStackerID; isMaterialIncludedInFilter = Options.Get.SelectedMaterialFilter.Any(xm => xm == blockId); } if (m.BlockID != 0) { if (_IsSolidColors) { if (isMaterialIncludedInFilter) { brush.Color = blueprint.GetColor(x, y); gImg.FillRectangle(brush, xi, yi, textureSize.Value, textureSize.Value); } } else if (_IsColorPalette) { if (isMaterialIncludedInFilter) { brush.Color = blueprint.GetColor(x, y); gImg.DrawImage(m.getImage(isSide), xi, yi, textureSize.Value, textureSize.Value); gImg.FillRectangle(brush, xi, yi, textureSize.Value / 2, textureSize.Value / 2); brush.Color = Color.Black; gImg.DrawRectangle(pen, xi, yi, textureSize.Value / 2, textureSize.Value / 2); } } else { if (isMaterialIncludedInFilter) { gImg .DrawImage(m.getImage(isSide), xi, yi, textureSize.Value, textureSize.Value); } } } } } } } #endregion #region SHADOW_NEW if (!_isSkipShadowRendering) { Bitmap bmShadeSprites = ShadowHelper.GetSpriteSheet(Constants.TextureSize); Bitmap bmShadow = new Bitmap( width: calcW, height: calcH, format: PixelFormat.Format32bppArgb); byte[,] shadowMap = new byte[mWidth, mHeight]; { #region Initialize shadow map (booleans basically) TaskManager.SafeReport(0, "Calculating shadow placement map"); for (int xShadeMap = 0; xShadeMap < mWidth; xShadeMap++) { TaskManager.SafeReport(100 * xShadeMap / mWidth); worker?.SafeThrowIfCancellationRequested(); for (int yShadeMap = 0; yShadeMap < mHeight; yShadeMap++) { Material mBottom = blueprint.GetMaterialAt(xShadeMap, yShadeMap, 0, true); bool isBottomShown = mBottom.BlockID != 0 && (selectedMaterials.Count == 0 || selectedMaterials.Any(xm => xm == mBottom.PixelStackerID)); Material mTop = blueprint.GetMaterialAt(xShadeMap, yShadeMap, 1, !_isFrugalAesthetic); bool isTopShown = mTop.BlockID != 0 && (selectedMaterials.Count == 0 || selectedMaterials.Any(xm => xm == mTop.PixelStackerID)); if (isTopShown && isBottomShown) { shadowMap[xShadeMap, yShadeMap] = SHOWN_TOP_AND_BOTTOM; } else if (isTopShown) { shadowMap[xShadeMap, yShadeMap] = SHOWN_TOP; } else if (isBottomShown) { shadowMap[xShadeMap, yShadeMap] = SHOWN_BOTTOM; } else { shadowMap[xShadeMap, yShadeMap] = SHOWN_NONE; } } } #endregion using (Graphics gShadow = Graphics.FromImage(bmShadow)) { gShadow.CompositingMode = CompositingMode.SourceOver; // over is slower but better... gShadow.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; gShadow.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; gShadow.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; var brushTransparentCover = new SolidBrush(Color.FromArgb(40, 127, 127, 127)); { TaskManager.SafeReport(0, "Rendering shadows"); for (int x = 0; x < mWidth; x++) { TaskManager.SafeReport(100 * x / mWidth); worker?.SafeThrowIfCancellationRequested(); for (int y = 0; y < mHeight; y++) { int xi = x * textureSize.Value; int yi = y * textureSize.Value; bool isTopShown = shadowMap[x, y] == SHOWN_TOP || shadowMap[x, y] == SHOWN_TOP_AND_BOTTOM; bool isBottomShown = shadowMap[x, y] == SHOWN_BOTTOM || shadowMap[x, y] == SHOWN_TOP_AND_BOTTOM; bool isBottomCoveredByInvisibleTop = isBottomShown && !isTopShown; // The thing that makes it slightly less saturated on bottom layer if (isBottomCoveredByInvisibleTop && _IsMultiLayer) { gShadow.FillRectangle(brushTransparentCover, xi, yi, textureSize.Value, textureSize.Value); } if (isTopShown && isBottomShown) { continue; // No shade required } // AIR block (or block we aint rendering) if (!isTopShown) { ShadeFrom sFrom = ShadeFrom.EMPTY; bool isBlockTop = y > 0 && isShaded(shadowMap[x, y], shadowMap[x, y - 1]); bool isBlockLeft = x > 0 && isShaded(shadowMap[x, y], shadowMap[x - 1, y]); bool isBlockRight = x < mWidth - 1 && isShaded(shadowMap[x, y], shadowMap[x + 1, y]); bool isBlockBottom = (y < mHeight - 1 && isShaded(shadowMap[x, y], shadowMap[x, y + 1])); bool isBlockTopLeft = (y > 0 && x > 0 && isShaded(shadowMap[x, y], shadowMap[x - 1, y - 1])); bool isBlockTopRight = (y > 0 && x < mWidth - 1 && isShaded(shadowMap[x, y], shadowMap[x + 1, y - 1])); bool isBlockBottomLeft = (y < mHeight - 1 && x > 0 && isShaded(shadowMap[x, y], shadowMap[x - 1, y + 1])); bool isBlockBottomRight = (y < mHeight - 1 && x < mWidth - 1 && isShaded(shadowMap[x, y], shadowMap[x + 1, y + 1])); if (isBlockTop) { sFrom |= ShadeFrom.T; } if (isBlockLeft) { sFrom |= ShadeFrom.L; } if (isBlockRight) { sFrom |= ShadeFrom.R; } if (isBlockBottom) { sFrom |= ShadeFrom.B; } if (isBlockTopLeft) { sFrom |= ShadeFrom.TL; } if (isBlockTopRight) { sFrom |= ShadeFrom.TR; } if (isBlockBottomLeft) { sFrom |= ShadeFrom.BL; } if (isBlockBottomRight) { sFrom |= ShadeFrom.BR; } var shadeImg = ShadowHelper.GetSpriteIndividual(Constants.TextureSize, sFrom); gShadow.DrawImage(image: shadeImg, xi, yi, textureSize.Value, textureSize.Value); } } } } brushTransparentCover.Dispose(); } gImg.CompositingMode = CompositingMode.SourceOver; gImg.DrawImage(bmShadow, 0, 0, calcW, calcH); } } #endregion brush.DisposeSafely(); pen.DisposeSafely(); } return(bm); } catch (Exception ex) { Console.WriteLine(ex); blueprint = null; } } return(null); }