コード例 #1
0
        /* 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);
        }
コード例 #2
0
        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;
                }
            }
        }
コード例 #3
0
        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;
                }
            }
        }
コード例 #4
0
        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);
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        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);
        }
コード例 #7
0
        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));
        }
コード例 #8
0
 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);
     }
 }
コード例 #9
0
 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);
         }
     }
 }
コード例 #10
0
        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;
            }
        }
コード例 #11
0
        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;
            }
        }
コード例 #12
0
        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);
        }
コード例 #13
0
        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());
            }
        }
コード例 #14
0
        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());
                }
            }
        }
コード例 #15
0
        //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);
        }
コード例 #16
0
ファイル: BlueprintPA.cs プロジェクト: nyaachen/PixelStacker
 public CoordinateMapper(BlueprintPA blueprintPA)
 {
     this.blueprint = blueprintPA;
 }
コード例 #17
0
        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);
        }