예제 #1
0
        void placeRooms()
        {
            var packer = new RectanglePacker();

            for (int roomIndex = 0; roomIndex < rooms.Count; roomIndex++)
            {
                var roomData     = rooms[roomIndex];
                var roomTiledMap = roomData.roomPrefab.GetComponent <Tiled2Unity.TiledMap>();
                roomData.size = myMath.getTiledMapSize(roomTiledMap);
            }
            rooms.Sort((a, b) => b.Area.CompareTo(a.Area));

            for (int roomIndex = 0; roomIndex < rooms.Count; roomIndex++)
            {
                var   roomData = rooms[roomIndex];
                float newx;
                float newy;

                if (!packer.Pack(roomData.size.x, roomData.size.y, out newx, out newy))
                {
                    throw new Exception("Uh oh, we couldn't pack the rectangle :(");
                }

                //This rectangle is now packed into position!
                roomData.position = new Vector3(newx, newy);

                roomData.roomGameObject = Instantiate(roomData.roomPrefab, roomData.position, Quaternion.identity);
            }
        }
예제 #2
0
        public void PackerTexture1()
        {
            Texture2D[] packerTexs = _texMap.Values.ToArray();
            _texMap.Clear();

            _mainTex          = new Texture2D(_defaultWh, _defaultWh, TextureFormat.ARGB32, false);
            _mainTex.wrapMode = TextureWrapMode.Clamp;

            const int       padding = 0;
            RectanglePacker packer  = new RectanglePacker(_mainTex.width, _mainTex.height, padding);

            for (int i = 0; i < packerTexs.Length; i++)
            {
                packer.insertRectangle(packerTexs[i].width, packerTexs[i].height, i);
            }
            packer.packRectangles();

            IntegerRectangle rect = new IntegerRectangle();

            for (int i = 0; i < packer.rectangleCount; i++)
            {
                rect = packer.getRectangle(i, rect);
                int index = packer.getRectangleId(i);

                _mainTex.SetPixels32(rect.x, rect.y, rect.width, rect.height, packerTexs[index].GetPixels32());
                Sprite sprite = Sprite.Create(_mainTex, new Rect(rect.x, rect.y, rect.width, rect.height),
                                              Vector2.zero, _pixelsPerUnit, 0, SpriteMeshType.FullRect);
                _spriteMap.Add(packerTexs[i].name, sprite);
            }
            _mainTex.Apply();
        }
예제 #3
0
        static void Main(string[] args)
        {
            Stopwatch stopwatch = new Stopwatch();

            PackingRectangle[] rectangles = GetRectangles();
            Console.WriteLine("Packing " + rectangles.Length + " rectangles...");

            stopwatch.Restart();
            RectanglePacker.Pack(rectangles, out PackingRectangle bounds);
            stopwatch.Stop();

            Console.WriteLine("Took ~" + stopwatch.Elapsed.TotalMilliseconds.ToString() + "ms");

            if (RectanglePacker.AnyIntersects(rectangles))
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Some rectangles intersect!");
            }
            else
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("No rectangles intersect.");
            }

            Console.ResetColor();

            string filename = GetImageName();

            Console.WriteLine("Saving as " + filename);
            SaveAsImage(rectangles, bounds, filename);
        }
예제 #4
0
        static void Main(string[] args)
        {
            List <Rectangle> rectangles = new List <Rectangle>();

            for (int i = 0; i < 5; i++)
            {
                rectangles.Add(new Rectangle(5, 5));
            }
            int Hight;
            int Width;

            Console.WriteLine("Write Hight");
            Hight = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine("Write Width");
            Width = Convert.ToInt32(Console.ReadLine());
            RectanglePacker rectanglePacker = new RectanglePacker(Hight, Width);

            if (rectanglePacker.PackRectangleWithNFDH(rectangles))
            {
                Console.WriteLine("Its fit");
            }
            else
            {
                Console.WriteLine("Cant fit");
            }
            Console.ReadKey();
        }
예제 #5
0
        public FreetypeFont(byte[] FontFile, int Size = 12, int AtlasW = 512, int AtlasH = 512)
        {
            GlyphTexture = new Dictionary <uint, Glyph>();
            Fnt          = Msdfgen.LoadFontMemory(FontFile);
            FontSize     = Size;

            TextureAtlas = Texture.Empty(AtlasW, AtlasH);
            Packer       = new RectanglePacker(AtlasW, AtlasH);
        }
        public Texture2D SetupTextureAtlas(GraphicsDevice graphicsDevice)
        {
            var triangles = Models.SelectMany(m => m.ModelTriangles).ToList();
            var dict      = new Dictionary <KeyValuePair <string, Rectangle>, TrianglesWithCroppedTexture>();

            foreach (var triangle in triangles)
            {
                if (!dict.ContainsKey(triangle.TextureKey))
                {
                    if (!TextureHandler.HasCroppedTexture(triangle.TextureKey))
                    {
                        TextureHandler.AddCroppedTexture(triangle.TextureKey, TextureHandler.CropTexture(triangle.OriginalTexture, triangle.OriginalTextureRectangle));
                    }

                    dict.Add(triangle.TextureKey, new TrianglesWithCroppedTexture()
                    {
                        CroppedTexture       = TextureHandler.GetCroppedTexture(triangle.TextureKey).Key,
                        HasTransparentPixels = TextureHandler.GetCroppedTexture(triangle.TextureKey).Value
                    });
                }

                dict[triangle.TextureKey].ModelTriangles.Add(triangle);
            }

            var packer = new RectanglePacker(4096, 4096);

            foreach (var pair in dict)
            {
                var rect = pair.Value.CroppedTexture.Bounds;
                if (!packer.Pack(rect.Width, rect.Height, out rect.X, out rect.Y))
                {
                    throw new Exception("Uh oh, we couldn't pack the rectangles");
                }
                pair.Value.AtlasRectangle = rect;
            }

            foreach (var pair in dict)
            {
                foreach (var triangle in pair.Value.ModelTriangles)
                {
                    triangle.AtlasTextureRectangle = pair.Value.AtlasRectangle;
                    triangle.HasTransparentPixels  = pair.Value.HasTransparentPixels;
                }
            }

            var atlas = new Texture2D(graphicsDevice, 4096, 4096);

            foreach (var pair in dict)
            {
                var data = new Color[pair.Value.CroppedTexture.Width * pair.Value.CroppedTexture.Height];
                pair.Value.CroppedTexture.GetData(0, pair.Value.CroppedTexture.Bounds, data, 0, data.Length);
                atlas.SetData(0, pair.Value.AtlasRectangle, data, 0, data.Length);
                pair.Value.CroppedTexture = null;
            }

            return(atlas);
        }
예제 #7
0
        public static Dictionary <string, object> PackRectangles(
            List <Rectangle> items,
            List <Rectangle> containers,
            [DefaultArgument("RectanglePackingStrategy.BestAreaFits")] RectanglePackingStrategy strategy)
        {
            var packer  = new RectanglePacker();
            var results = packer.PackMultipleContainers(items, containers, strategy);

            return(results.ToDictionary());
        }
예제 #8
0
        private static void Main(string[] args)
        {
            Application.Run(() =>
            {
                var window = new Window("Atlas Thrashing", vsync: false)
                {
                    Size = (1280, 720)
                };
                window.Graphics.Performance.OverlayMode = PerformanceOverlayMode.Simple;
                window.MoveToCenter();

                var xcount = window.Size.Width / 64;
                var ycount = window.Size.Height / 64;

                // Using the shelf packer here for fast visualization sake.
                // The skyline is the actual packer used by the texture atlas system.
                var packer = new RectanglePacker <Image>(window.Surface.Size, PackingAlgorithm.Skyline);

                // Create the main loop
                var loop = GameLoop.Create(window.Graphics, (gfx, dt) =>
                {
                    packer.Clear();

                    window.Graphics.Clear(Color.White);

                    while (true)
                    {
                        var w = Calc.Random.Next(8, 128);
                        var h = Calc.Random.Next(8, 128);

                        var r = Calc.Random.NextFloat();
                        var g = Calc.Random.NextFloat();
                        var b = Calc.Random.NextFloat();

                        // Attempt to pack image, if unable break
                        var image = Image.CreateColor(w, h, new Color(r, g, b));
                        if (!packer.TryAdd(image, image.Size))
                        {
                            break;
                        }

                        var packed = packer.GetRectangle(image);
                        window.Graphics.DrawImage(image, packed.Position);
                    }
                });

                // Begin main loop
                loop.Start();
            });
        }
예제 #9
0
        private bool TryPacking(int width, int height, Packable[] packables)
        {
            var packer = new RectanglePacker(width, height, 2048, 2048);

            foreach (var face in packables)
            {
                int x, y;
                if (!packer.Pack(face.Width, face.Height, out x, out y))
                {
                    return(false);
                }
                _packing[face.Index] = new IntRect(x + 1, y + 1, face.Width - 2, face.Height - 2);
            }

            SetBoundingSize(packer.Width, packer.Height);
            return(true);
        }
예제 #10
0
        public DynamicAtlas(string atlas, int width, int height, int padding, bool compress = true)
        {
            this.atlas = atlas;

            this.width = width;

            this.height = height;

            this.padding = padding;

            this.compress = compress;

            m_packer = new RectanglePacker(width, height, padding);

            m_texture = new Texture2D(width, height, TextureFormat.RGBA32, false);

            m_color = m_texture.GetPixels32();
        }
예제 #11
0
    public static void sort_rects(List <PackerRect> rects, int dx = 0, int dy = 0, float mx = 1.0f, float my = 1.0f)
    {
        rects.Sort((a, b) => b.Area.CompareTo(a.Area));
        var packer = new RectanglePacker();

        for (int i = 0; i < rects.Count; ++i)
        {
            var rect = rects[i];
            int x, y;
            if (!packer.Pack((int)rect.w, (int)rect.h, out x, out y))
            {
                throw new Exception("Uh oh, we couldn't pack the rectangle :(");
            }
            rect.x = x;
            rect.y = y;

            var       p   = currentPackage.QueryComponent(rect.ID);
            int []    m   = { 1024, 0, 0, 1024, (int)((x + dx) * 16 * mx), (int)((y + dy) * 16 * my) };
            Matrix4x4 mat = Matrix.ToMatrix4x4(m);
            Matrix.SetTransformFromMatrix(p.transform, ref mat);
        }
    }
    private void updateRectangles()
    {
        DateTime  start   = DateTime.Now;
        const int padding = 1;

        if (mPacker == null)
        {
            mPacker = new RectanglePacker((int)sliderWidth.value, (int)sliderHeight.value, padding);
        }
        else
        {
            mPacker.reset((int)sliderWidth.value, (int)sliderHeight.value, padding);
        }

        for (int i = 0; i < RECTANGLE_COUNT; i++)
        {
            mPacker.insertRectangle((int)mRectangles[i].width, (int)mRectangles[i].height, i);
        }

        mPacker.packRectangles();
        Clear();
        DateTime end = DateTime.Now;

        if (mPacker.rectangleCount > 0)
        {
            packingTimeText.text = mPacker.rectangleCount + " rectangles packed in " + (end - start).Milliseconds + "ms";
            IntegerRectangle rect = new IntegerRectangle();
            for (int j = 0; j < mPacker.rectangleCount; j++)
            {
                rect = mPacker.getRectangle(j, rect);
                int       index   = mPacker.getRectangleId(j);
                Texture2D texture = textures[index];
                SetTexture(texture, IntegerRectangle2Rect(rect));
            }
        }
    }
예제 #13
0
        public void InitRectPacker(int typeIndex)
        {
            int binaryNum1 = this.GetBinaryNum(this.maxWidth);
            int binaryNum2 = this.GetBinaryNum(this.maxHeight);

            switch (typeIndex)
            {
            case 0:
                this.rectPacker = (RectanglePacker) new SimpleRectanglePacker(binaryNum1, binaryNum2);
                break;

            case 1:
                this.rectPacker = (RectanglePacker) new CygonRectanglePacker(binaryNum1, binaryNum2);
                break;

            case 2:
                this.rectPacker = (RectanglePacker) new ArevaloRectanglePacker(binaryNum1, binaryNum2);
                break;

            default:
                this.rectPacker = (RectanglePacker) new ArevaloRectanglePacker(binaryNum1, binaryNum2);
                break;
            }
        }
예제 #14
0
        protected IEnumerator createPack(string savePath = "")
        {
            if (savePath != "")
            {
                if (deletePreviousCacheVersion && Directory.Exists(Application.persistentDataPath + "/AssetPacker/" + cacheName + "/"))
                {
                    foreach (string dirPath in Directory.GetDirectories(Application.persistentDataPath + "/AssetPacker/" + cacheName + "/", "*", SearchOption.AllDirectories))
                    {
                        Directory.Delete(dirPath, true);
                    }
                }

                Directory.CreateDirectory(savePath);
            }

            List <Texture2D> textures = new List <Texture2D>();
            List <string>    images   = new List <string>();

            foreach (TextureToPack itemToRaster in itemsToRaster)
            {
                WWW loader = new WWW("file:///" + itemToRaster.file);

                yield return(loader);

                textures.Add(loader.texture);
                images.Add(itemToRaster.id);
            }

            int textureSize = allow4096Textures ? 4096 : 2048;

            List <Rect> rectangles = new List <Rect>();

            for (int i = 0; i < textures.Count; i++)
            {
                if (textures[i].width > textureSize || textures[i].height > textureSize)
                {
                    throw new Exception("A texture size is bigger than the sprite sheet size!");
                }
                else
                {
                    rectangles.Add(new Rect(0, 0, textures[i].width, textures[i].height));
                }
            }

            const int padding = 1;

            int numSpriteSheet = 0;

            while (rectangles.Count > 0)
            {
                Texture2D texture   = new Texture2D(textureSize, textureSize, TextureFormat.ARGB32, false);
                Color32[] fillColor = texture.GetPixels32();
                for (int i = 0; i < fillColor.Length; ++i)
                {
                    fillColor[i] = Color.clear;
                }

                RectanglePacker packer = new RectanglePacker(texture.width, texture.height, padding);

                for (int i = 0; i < rectangles.Count; i++)
                {
                    packer.insertRectangle((int)rectangles[i].width, (int)rectangles[i].height, i);
                }

                packer.packRectangles();

                if (packer.rectangleCount > 0)
                {
                    texture.SetPixels32(fillColor);
                    IntegerRectangle    rect          = new IntegerRectangle();
                    List <TextureAsset> textureAssets = new List <TextureAsset>();

                    List <Rect>      garbageRect    = new List <Rect>();
                    List <Texture2D> garabeTextures = new List <Texture2D>();
                    List <string>    garbageImages  = new List <string>();

                    for (int j = 0; j < packer.rectangleCount; j++)
                    {
                        rect = packer.getRectangle(j, rect);

                        int index = packer.getRectangleId(j);

                        texture.SetPixels32(rect.x, rect.y, rect.width, rect.height, textures[index].GetPixels32());

                        TextureAsset textureAsset = new TextureAsset();
                        textureAsset.x      = rect.x;
                        textureAsset.y      = rect.y;
                        textureAsset.width  = rect.width;
                        textureAsset.height = rect.height;
                        textureAsset.name   = images[index];

                        textureAssets.Add(textureAsset);

                        garbageRect.Add(rectangles[index]);
                        garabeTextures.Add(textures[index]);
                        garbageImages.Add(images[index]);
                    }

                    foreach (Rect garbage in garbageRect)
                    {
                        rectangles.Remove(garbage);
                    }

                    foreach (Texture2D garbage in garabeTextures)
                    {
                        textures.Remove(garbage);
                    }

                    foreach (string garbage in garbageImages)
                    {
                        images.Remove(garbage);
                    }

                    texture.Apply();

                    if (savePath != "")
                    {
                        File.WriteAllBytes(savePath + "/data" + numSpriteSheet + ".png", texture.EncodeToPNG());
                        File.WriteAllText(savePath + "/data" + numSpriteSheet + ".json", JsonUtility.ToJson(new TextureAssets(textureAssets.ToArray())));
                        ++numSpriteSheet;
                    }

                    foreach (TextureAsset textureAsset in textureAssets)
                    {
                        mSprites.Add(textureAsset.name, Sprite.Create(texture, new Rect(textureAsset.x, textureAsset.y, textureAsset.width, textureAsset.height), Vector2.zero, pixelsPerUnit, 0, SpriteMeshType.FullRect));
                    }
                }
            }

            OnProcessCompleted.Invoke();
        }
예제 #15
0
        // example args: -input.path=D:\some\path\to\images\here -filter=*.jpg -prefix=team -output.extension=jpg -output.path= -output.resize=240
        static void Main(string[] args)
        {
            string folder         = null;
            string filter         = "*.*";
            string atlasPath      = Directory.GetCurrentDirectory();
            string cssPath        = null;
            string jsonPath       = null;
            string xmlPath        = null;
            string csvPath        = null;
            string atlasExtension = "jpg";
            string prefix         = null;
            int    resize         = 0;

            var  globalMargin = new Margin();
            bool normalize    = false;

            foreach (var entry in args)
            {
                var arg = entry;

                if (!arg.StartsWith("-"))
                {
                    Console.WriteLine("Invalid argument: " + arg);
                    return;
                }

                arg = arg.Substring(1);

                var temp = arg.Split(new char[] { '=' }, 2);

                var key = temp[0].ToLower();
                var val = temp.Length == 2 ? temp[1] : null;

                switch (key)
                {
                case "input.path": folder = val; break;

                case "input.filter": filter = val; break;

                case "prefix": prefix = val; break;

                case "atlas.extension": atlasExtension = val.Replace(".", ""); break;

                case "atlas.path": atlasPath = val; break;

                case "resize": resize = int.Parse(val); break;

                case "css.path": cssPath = val; break;

                case "json.path": jsonPath = val; break;

                case "xml.path": xmlPath = val; break;

                case "csv.path": csvPath = val; break;

                case "margin.X": globalMargin.X = int.Parse(val); break;

                case "margin.Y": globalMargin.Y = int.Parse(val); break;

                case "margin": globalMargin.X = int.Parse(val); globalMargin.Y = globalMargin.X; break;

                case "normalize": normalize = bool.Parse(val); break;
                }
            }

            if (normalize && resize > 0)
            {
                Console.WriteLine("Normalize and resize options are mutually exclusive.");
                return;
            }

            FixPath(ref atlasPath);
            FixPath(ref cssPath);
            FixPath(ref jsonPath);
            FixPath(ref xmlPath);
            FixPath(ref csvPath);

            if (folder == null)
            {
                Console.WriteLine("Please specify a folder. Eg: -input.path=some_path");
                return;
            }

            if (prefix == null)
            {
                Console.WriteLine("Please specify a atlas prefix. Eg: --prefix=something");
                return;
            }

            var outPicName = prefix + "." + atlasExtension;
            var outCSSName = prefix + ".css";

            var files = Directory.GetFiles(folder, filter);

            var images = new Dictionary <string, Bitmap>();

            int count = 0;

            int avgWidth  = 0;
            int avgHeight = 0;

            int maxWidth  = 0;
            int maxHeight = 0;

            foreach (var file in files)
            {
                var img = new Bitmap(Bitmap.FromFile(file));

                if (resize != 0)
                {
                    img = new Bitmap(img, new Size(resize, resize));
                }

                images[file] = img;
                count++;

                maxWidth  = Math.Max(maxWidth, img.Width);
                maxHeight = Math.Max(maxHeight, img.Height);

                avgWidth  += img.Width;
                avgHeight += img.Height;
            }

            int maxSize = Math.Max(maxHeight, maxWidth);

            avgWidth  /= count;
            avgHeight /= count;

            int side = (int)Math.Ceiling(Math.Sqrt(count));

            int atlasWidth  = avgWidth * side;
            int atlasHeight = avgHeight * side;

            int tot;

            int tries = 0;
            RectanglePacker <string> packer;

            var margins = new Dictionary <string, Margin>();

            if (normalize)
            {
                foreach (var file in files)
                {
                    var img    = images[file];
                    var margin = new Margin()
                    {
                        X = (maxSize - img.Width) / 2 + globalMargin.X,
                        Y = (maxSize - img.Height) / 2 + globalMargin.Y,
                    };
                    margins[file] = margin;
                }
            }
            else
            {
                foreach (var file in files)
                {
                    margins[file] = globalMargin;
                }
            }

            do
            {
                packer = new RectanglePacker <string>();


                foreach (var entry in images)
                {
                    var margin = margins[entry.Key];
                    packer.AddRect(entry.Value.Width + margin.X * 2, entry.Value.Height + margin.Y * 2, entry.Key);
                }

                tot = packer.Pack(0, 0, atlasWidth, atlasHeight);
                if (tot == 0)
                {
                    break;
                }

                if (tries % 2 == 0)
                {
                    atlasWidth *= 2;
                }
                else
                {
                    atlasHeight *= 2;
                }

                tries++;
                if (tries > 5)
                {
                    break;
                }
            } while (true);

            if (tot == 0)
            {
                var output = new Bitmap(atlasWidth, atlasHeight);

                using (Graphics g = Graphics.FromImage(output))
                {
                    foreach (var file in files)
                    {
                        int x, y;
                        packer.GetRect(file, out x, out y);

                        var margin = margins[file];
                        x += margin.X;
                        y += margin.Y;

                        var img = images[file];
                        g.DrawImage(img, x, y, img.Width, img.Height);

                        Console.WriteLine("Merged " + file);
                    }
                }

                output.Save(atlasPath + outPicName);

                Console.WriteLine("Generated " + atlasPath + outPicName);

                if (cssPath != null)
                {
                    var sb = new StringBuilder();

                    int index = 0;
                    foreach (var file in files)
                    {
                        var name = Path.GetFileNameWithoutExtension(file).ToLower();

                        if (index > 0)
                        {
                            sb.Append(", ");
                        }

                        if (index % side == side - 1)
                        {
                            sb.AppendLine();
                        }

                        sb.Append($".{prefix}-{name}");

                        index++;
                    }

                    sb.Append('{');
                    sb.AppendLine();
                    sb.AppendLine($"\tbackground-image: url('{outPicName}');");
                    sb.AppendLine("\tbackground-repeat: no-repeat;");
                    sb.Append('}');
                    sb.AppendLine();

                    foreach (var file in files)
                    {
                        int x, y;
                        packer.GetRect(file, out x, out y);

                        var margin = margins[file];
                        x += margin.X;
                        y += margin.Y;

                        var name = Path.GetFileNameWithoutExtension(file).ToLower();
                        var img  = images[file];

                        sb.AppendLine();
                        sb.AppendLine("." + prefix + "-" + name + " {");
                        sb.AppendLine($"\twidth: {img.Width}px;");
                        sb.AppendLine($"\theight: {img.Height}px;");
                        sb.AppendLine($"\tbackground-position: -{x}px -{y}px;");
                        sb.Append('}');
                        sb.AppendLine();
                    }

                    File.WriteAllText(cssPath + outCSSName, sb.ToString());

                    Console.WriteLine("Generated " + cssPath + outCSSName);
                }

                if (xmlPath != null || csvPath != null || jsonPath != null)
                {
                    if (jsonPath != null)
                    {
                        var node = ExportToNode(files, images, margins, packer, false);
                        var json = JSONWriter.WriteToString(node);
                        File.WriteAllText(jsonPath + prefix + ".json", json);
                    }

                    if (xmlPath != null)
                    {
                        var node = ExportToNode(files, images, margins, packer, true);
                        var xml  = XMLWriter.WriteToString(node);
                        File.WriteAllText(xmlPath + prefix + ".xml", xml);
                    }

                    if (csvPath != null)
                    {
                        var node = ExportToNode(files, images, margins, packer, false);
                        var csv  = CSVWriter.WriteToString(node);
                        File.WriteAllText(csvPath + prefix + ".csv", csv);
                    }
                }
            }
            else
            {
                Console.WriteLine("Failed packing...");
            }
        }
예제 #16
0
        private void Button_Calculate_Click(object sender, RoutedEventArgs e)
        {
            Drowing.Children.Clear();
            try
            {
                boxHight = Convert.ToInt32(MainHight.Text);
                boxWidth = Convert.ToInt32(MainWidth.Text);


                rectanglePacker = new RectanglePacker(boxHight, boxWidth);

                bool result;



                //result = rectanglePacker.PackRectangleWithNFDH(rectangles);
                result = rectanglePacker.PackRectangleWithFFDH(rectangles);

                if (!result)
                {
                    MassageBox.Text = "Cant fit";
                }
                if (result)
                {
                    MassageBox.Text = "successfully fited";

                    int h = rectanglePacker.Hight;
                    int w = rectanglePacker.Width;
                    RectangleGeometry rectangle = new RectangleGeometry(new Rect(0, 0, w, h));

                    Path myPath = new Path();
                    myPath.HorizontalAlignment = HorizontalAlignment.Left;
                    myPath.VerticalAlignment   = VerticalAlignment.Bottom;


                    myPath.Stroke          = Brushes.Black;
                    myPath.StrokeThickness = 3;

                    GeometryGroup geometryGroup = new GeometryGroup();
                    geometryGroup.Children.Add(rectangle);



                    foreach (var item in rectanglePacker.PackedRectengles)
                    {
                        var cord       = item.Key;
                        var rect       = item.Value;
                        var rectangle2 = new RectangleGeometry(new Rect(cord.X, cord.Y, rect.Width, rect.Hight));



                        geometryGroup.Children.Add(rectangle2);
                    }
                    myPath.Data = geometryGroup;
                    Drowing.Children.Add(myPath);
                }
            }
            catch (Exception ex)
            {
                MassageBox.Text = ex.Message;
            }
        }
예제 #17
0
        public static void Main(string[] args)
        {
            //Create a list of random rectangles, sorted by size
            var rand = new Random();
            var rects = new List<Rect>();
            for (int i = 0; i < 50; ++i)
                rects.Add(new Rect(0, 0, rand.Next(2, 10), rand.Next(2, 10)));
            for (int i = 0; i < 50; ++i)
                rects.Add(new Rect(0, 0, rand.Next(7, 10), rand.Next(1, 4)));
            for (int i = 0; i < 50; ++i)
                rects.Add(new Rect(0, 0, rand.Next(1, 4), rand.Next(7, 10)));
            for (int i = 0; i < 50; ++i)
                rects.Add(new Rect(0, 0, rand.Next(1, 4), rand.Next(1, 4)));

            rects.Sort((a, b) => b.Area.CompareTo(a.Area));

            var watch = Stopwatch.StartNew();

            //Pack the rectangles
            var packer = new RectanglePacker();
            for (int i = 0; i < rects.Count; ++i)
            {
                var rect = rects[i];

                //Pad the rectangles by 1px so there is a gap between them
                if (!packer.Pack(rect.W + 1, rect.H + 1, out rect.X, out rect.Y))
                {
                    Console.WriteLine("Packing failed");
                    return;
                }

                rects[i] = rect;
            }

            int packTime = (int)watch.ElapsedMilliseconds;
            int totalArea = packer.Width * packer.Height;
            int usedArea = 0;

            //Create a 2D grid of "pixels" and fill them where rectangles are
            var grid = new bool[packer.Width, packer.Height];
            foreach (var rect in rects)
            {
                usedArea += (rect.W + 1) * (rect.H + 1);

                for (int y = 0; y < rect.H; ++y)
                    for (int x = 0; x < rect.W; ++x)
                        grid[rect.X + x, rect.Y + y] = true;
            }

            //Print out the results to a text file
            using (var writer = new StreamWriter("results.txt"))
            {
                int percent = (int)(((float)usedArea / totalArea) * 100f);
                writer.WriteLine("Packed: " + rects.Count + " rectangles");
                writer.WriteLine("Size: " + packer.Width + " x " + packer.Height);
                writer.WriteLine("Usage: " + usedArea + " / " + totalArea + " (" + percent + "%)");
                writer.WriteLine("Pack Time: " + packTime + " ms");
                writer.WriteLine();

                for (int y = 0; y < packer.Height; ++y)
                {
                    for (int x = 0; x < packer.Width; ++x)
                        writer.Write(grid[x, y] ? '#' : ' ');
                    writer.WriteLine();
                }
            }

            Console.WriteLine("Finished successfully. See results.txt");
        }
예제 #18
0
        /// <summary>
        /// Creates a <see cref="TrippyFontFile"/> holding information for multiple fonts.
        /// </summary>
        /// <param name="glyphSources">The <see cref="IGlyphSource"/>-s for getting the information of each font.</param>
        /// <param name="backgroundColor">The background color of the generated image. Null for transparent.</param>
        public static TrippyFontFile CreateFontFile(ReadOnlySpan <IGlyphSource> glyphSources, Color?backgroundColor = null)
        {
            // We create all the TextureFontData-s and query their basic information from the glyph sources.
            TextureFontData[] fontDatas = new TextureFontData[glyphSources.Length];
            for (int i = 0; i < fontDatas.Length; i++)
            {
                fontDatas[i] = new TextureFontData()
                {
                    Size      = glyphSources[i].Size,
                    FirstChar = glyphSources[i].FirstChar,
                    LastChar  = glyphSources[i].LastChar,
                    Ascender  = glyphSources[i].Ascender,
                    Descender = glyphSources[i].Descender,
                    LineGap   = glyphSources[i].LineGap,
                    Name      = glyphSources[i].Name
                };
            }

            // We count the total amount of characters in all glyph sources combined.
            int charCount = 0;

            for (int i = 0; i < glyphSources.Length; i++)
            {
                charCount += fontDatas[i].CharCount;
            }

            // We need to find a way to pack all the characters into a single texture.
            // For this we use the included Rectpack library in TrippyGL.Fonts.Rectpack.
            PackingRectangle[] packingRects = new PackingRectangle[charCount];

            // The way we identify the PackingRectangles is with their rect.Id property.
            // Since we have multiple fonts, we can't set these to the characters they represent
            // because there can be collisions. So the way we assign IDs will be basically like this:
            // The IDs for the characters of the first font start at 0 and go up to font.CharCount
            // inclusive. These are, of course, in order of character.
            // The second font then gets the range that starts right after where the first font's
            // range ends and gets enough range for all it's characters, etc etc.

            // So we need to know where the range of IDs for each font starts and end. We'll store it here:
            Span <int> idsStart = glyphSources.Length <= 96 ? stackalloc int[glyphSources.Length] : new int[glyphSources.Length];

            int packingRectCount = 0;

            for (int i = 0; i < fontDatas.Length; i++)
            {
                // We calculate the starting ID for the current glyph source.
                int idStart = i == 0 ? 0 : idsStart[i - 1] + fontDatas[i - 1].CharCount;
                idsStart[i] = idStart;

                // We go through all the characters in the current glyph source.
                for (int c = fontDatas[i].FirstChar; c <= fontDatas[i].LastChar; c++)
                {
                    // We get the size. If it is positive, we add a PackingRectangle to represent it.
                    System.Drawing.Point size = glyphSources[i].GetGlyphSize(c);
                    if (size.X > 0 && size.Y > 0)
                    {
                        // We add 2 to the width and height of the rectangle so chars have an empty border.
                        int id = idStart + c - fontDatas[i].FirstChar;
                        packingRects[packingRectCount++] = new PackingRectangle(0, 0, (uint)size.X + 2, (uint)size.Y + 2, id);
                    }
                }
            }

            // We trim extra elements off the packingRects array.
            if (packingRects.Length != packingRectCount)
            {
                Array.Resize(ref packingRects, packingRectCount);
            }

            // We use RectanglePacker to find a bin for all the rectangles.
            RectanglePacker.Pack(packingRects, out PackingRectangle bounds);

            Image <Rgba32> image = new Image <Rgba32>((int)bounds.Width, (int)bounds.Height);

            try
            {
                // First we clear the image to the specified background color, or transparent.
                Color bgColor = backgroundColor ?? Color.Transparent;
                image.Mutate(x => x.BackgroundColor(bgColor));

                // We create the source rectangles arrays for all the fontDatas.
                for (int i = 0; i < fontDatas.Length; i++)
                {
                    fontDatas[i].SourceRectangles = new System.Drawing.Rectangle[fontDatas[i].CharCount];
                }

                // We go through all the packing rectangles.
                for (int i = 0; i < packingRects.Length; i++)
                {
                    PackingRectangle rect = packingRects[i];

                    // We find which glyph source this rectangle belongs to.
                    int glyphSourceIndex = 0;
                    while (glyphSourceIndex + 1 < idsStart.Length && idsStart[glyphSourceIndex + 1] < rect.Id)
                    {
                        glyphSourceIndex++;
                    }

                    // We find which character this rectangle represents.
                    int charIndex = rect.Id - idsStart[glyphSourceIndex];
                    int charCode  = charIndex + fontDatas[glyphSourceIndex].FirstChar;

                    // We draw the glyph onto the image at this rectangle's location.
                    glyphSources[glyphSourceIndex].DrawGlyphToImage(charCode, new System.Drawing.Point((int)rect.X + 1, (int)rect.Y + 1), image);

                    // We set the glyph's source to match this rectangle.
                    fontDatas[glyphSourceIndex].SourceRectangles[charIndex] = new System.Drawing.Rectangle((int)rect.X + 1, (int)rect.Y + 1, (int)rect.Width - 2, (int)rect.Height - 2);
                }

                // We go through all the fontDatas and set the remaining information.
                for (int i = 0; i < fontDatas.Length; i++)
                {
                    fontDatas[i].RenderOffsets = glyphSources[i].GetRenderOffsets();

                    glyphSources[i].GetAdvances(out fontDatas[i].Advances);

                    if (!glyphSources[i].TryGetKerning(out fontDatas[i].KerningOffsets))
                    {
                        fontDatas[i].KerningOffsets = null;
                    }
                }

                // Done!
                return(new TrippyFontFile(fontDatas, image));
            }
            catch
            {
                // If anything failed, we dispose the image and re-throw the exception.
                image.Dispose();
                throw;
            }
        }
예제 #19
0
        public unsafe FontAtlas(FontFamily fontFamily, int fontSize, IEnumerable <int> characters)
        {
            Stopwatch watch = new Stopwatch();

            watch.Start();

            Size = fontSize;
            Font  font   = new Font(fontFamily, fontSize);
            float factor = (float)fontSize / font.EmSize;
            List <PackingRectangle> glyphRectangles = new List <PackingRectangle>();

            foreach (int character in characters)
            {
                GlyphInstance glyph = font.GetGlyph(character).Instance;
                glyphRectangles.Add(new PackingRectangle(0, 0, (uint)((glyph.LeftSideBearing + glyph.AdvanceWidth) * factor), (uint)(glyph.Height * factor), character));
            }

            PackingRectangle[] rectArray = glyphRectangles.ToArray();
            RectanglePacker.Pack(rectArray, out PackingRectangle bounds);

            Image <A8> image = new Image <A8>((int)bounds.Width, (int)bounds.Height);

            Characters = new Dictionary <char, CharacterData>();
            image.Mutate(x =>
            {
                foreach (PackingRectangle glyphRectangle in rectArray)
                {
                    GlyphInstance glyph = font.GetGlyph(glyphRectangle.Id).Instance;
                    Characters.Add((char)glyphRectangle.Id, new CharacterData()
                    {
                        uvX1     = glyphRectangle.X / (float)image.Width,
                        uvX2     = (glyphRectangle.X + glyphRectangle.Width) / (float)image.Width,
                        uvY1     = glyphRectangle.Y / (float)image.Height,
                        uvY2     = (glyphRectangle.Y + glyphRectangle.Height) / (float)image.Height,
                        xAdvance = glyph.AdvanceWidth * factor,
                        height   = glyph.Height * factor
                    });
                    x.DrawText(((char)glyphRectangle.Id).ToString(), font, Color.White,
                               new PointF(glyphRectangle.X, glyphRectangle.Y));
                }
            });

            image.TryGetSinglePixelSpan(out Span <A8> pixels);

            TextureId = GL.GenTexture();
            GL.ActiveTexture(TextureUnit.Texture0);
            GL.BindTexture(TextureTarget.Texture2D, TextureId);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
            GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
            fixed(A8 *pixelPointer = pixels)
            {
                GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Alpha, image.Width, image.Height, 0, PixelFormat.Alpha, PixelType.UnsignedByte, new IntPtr(pixelPointer));
            }

            GL.GenerateTextureMipmap(TextureId);

            watch.Stop();
            Console.WriteLine($"Font atlas with size {image.Width}x{image.Height} was created in {watch.ElapsedMilliseconds}ms!");
        }
예제 #20
0
        static DataNode ExportToNode(string[] files, Dictionary <string, Bitmap> images, Dictionary <string, Margin> margins, RectanglePacker <string> packer, bool giveNames)
        {
            var node = DataNode.CreateArray("images");

            foreach (var file in files)
            {
                int x, y;
                packer.GetRect(file, out x, out y);

                var margin = margins[file];
                x += margin.X;
                y += margin.Y;

                var img = images[file];

                var child = DataNode.CreateObject(giveNames ? "image": null);
                child.AddField("name", Path.GetFileNameWithoutExtension(file));
                child.AddField("x", x);
                child.AddField("y", y);
                child.AddField("width", img.Width);
                child.AddField("height", img.Height);
                node.AddNode(child);
            }
            return(node);
        }
예제 #21
0
    private void updateRectangles()
    {
        DateTime  start   = DateTime.Now;
        const int padding = 1;

        if (mPacker == null)
        {
            mPacker = new RectanglePacker((int)sliderWidth.value, (int)sliderHeight.value, padding);
        }
        else
        {
            mPacker.Reset((int)sliderWidth.value, (int)sliderHeight.value, padding);
        }

        for (int i = 0; i < RECTANGLE_COUNT; i++)
        {
            mPacker.InsertRectangle((int)mRectangles[i].width, (int)mRectangles[i].height, i);
        }

        mPacker.PackRectangles();

        DateTime end = DateTime.Now;

        if (mPacker.rectangleCount > 0)
        {
            packingTimeText.text = mPacker.rectangleCount + " rectangles packed in " + (end - start).Milliseconds + "ms";

            mTexture.SetPixels32(mFillColor);
            IntegerRectangle rect = new IntegerRectangle();
            Color32[]        tmpColor;

            for (int j = 0; j < mPacker.rectangleCount; j++)
            {
                rect = mPacker.GetRectangle(j, rect);

                int size = rect.width * rect.height;

                tmpColor = new Color32[size];
                for (int k = 0; k < size; ++k)
                {
                    tmpColor[k] = Color.black;
                }

                mTexture.SetPixels32(rect.x, rect.y, rect.width, rect.height, tmpColor);

                int   index = mPacker.GetRectangleId(j);
                Color color = convertHexToRGBA((uint)(0xFF171703 + (((18 * ((index + 4) % 13)) << 16) + ((31 * ((index * 3) % 8)) << 8) + 63 * (((index + 1) * 3) % 5))));

                size -= 4;

                tmpColor = new Color32[size];
                for (int k = 0; k < size; ++k)
                {
                    tmpColor[k] = color;
                }

                mTexture.SetPixels32(rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2, tmpColor);
            }

            mTexture.Apply();
        }
    }
예제 #22
0
        protected IEnumerator createPack(string savePath = "")
        {
            if (savePath != "")
            {
                if (deletePreviousCacheVersion && Directory.Exists(Application.persistentDataPath + "/AssetPacker/" + cacheName + "/"))
                {
                    foreach (string dirPath in Directory.GetDirectories(Application.persistentDataPath + "/AssetPacker/" + cacheName + "/", "*", SearchOption.AllDirectories))
                    {
                        Directory.Delete(dirPath, true);
                    }
                }

                Directory.CreateDirectory(savePath);
            }

            List <Texture2D> textures = new List <Texture2D>();
            List <string>    images   = new List <string>();

            foreach (TextureToPack itemToRaster in itemsToRaster)
            {
                Texture2D baseTexture = itemToRaster.preLoadedTexture;

                if (!baseTexture)
                {
                    WWW loader = new WWW("file:///" + itemToRaster.file);

                    yield return(loader);

                    baseTexture = loader.texture;
                }

                if (itemToRaster.sliceParams != null)
                {
                    TextureToPack.GridSlice sliceParams = itemToRaster.sliceParams;

                    if (sliceParams.width > baseTexture.width || sliceParams.height > baseTexture.height)
                    {
                        throw new Exception(string.Format("Width and/or height of texture {0} is less than the provided slice parameters.", itemToRaster.id));
                    }

                    if (!(baseTexture.width % sliceParams.width == 0 && baseTexture.height % sliceParams.height == 0))
                    {
                        throw new Exception(string.Format("Width and/or height of texture {0} not a multiple of the provided slice parameters.", itemToRaster.id));
                    }

                    int totalRows    = baseTexture.height / sliceParams.height;
                    int totalColumns = baseTexture.width / sliceParams.width;

                    int textureIndex = 0;

                    // Scan each slice left to right, top to bottom
                    for (int rowIndex = 0; rowIndex < totalRows; ++rowIndex)
                    {
                        for (int columnIndex = 0; columnIndex < totalColumns; ++columnIndex)
                        {
                            int x = columnIndex * sliceParams.width;
                            int y = (totalRows - rowIndex - 1) * sliceParams.height;    // Starting from the top, not the bottom. Specific to GH3 sprite sheets, not nesacarily universal.

                            Color[]   pixels  = baseTexture.GetPixels(x, y, sliceParams.width, sliceParams.height);
                            Texture2D texture = new Texture2D(sliceParams.width, sliceParams.height);
                            texture.SetPixels(pixels);
                            texture.Apply();

                            textures.Add(texture);
                            images.Add(string.Format("{0}_{1}", itemToRaster.id, textureIndex.ToString("D8")));

                            ++textureIndex;
                        }
                    }
                }
                else
                {
                    textures.Add(baseTexture);
                    images.Add(itemToRaster.id);
                }
            }

            int textureSize = allow4096Textures ? 4096 : 2048;

            List <Rect> rectangles = new List <Rect>();

            for (int i = 0; i < textures.Count; i++)
            {
                if (textures[i].width > textureSize || textures[i].height > textureSize)
                {
                    throw new Exception("A texture size is bigger than the sprite sheet size!");
                }
                else
                {
                    rectangles.Add(new Rect(0, 0, textures[i].width, textures[i].height));
                }
            }

            const int padding = 1;

            int numSpriteSheet = 0;

            while (rectangles.Count > 0)
            {
                Texture2D texture   = new Texture2D(textureSize, textureSize, TextureFormat.ARGB32, false);
                Color32[] fillColor = texture.GetPixels32();
                for (int i = 0; i < fillColor.Length; ++i)
                {
                    fillColor[i] = Color.clear;
                }

                RectanglePacker packer = new RectanglePacker(texture.width, texture.height, padding);

                for (int i = 0; i < rectangles.Count; i++)
                {
                    packer.insertRectangle((int)rectangles[i].width, (int)rectangles[i].height, i);
                }

                packer.packRectangles();

                if (packer.rectangleCount > 0)
                {
                    texture.SetPixels32(fillColor);
                    IntegerRectangle    rect          = new IntegerRectangle();
                    List <TextureAsset> textureAssets = new List <TextureAsset>();

                    List <Rect>      garbageRect    = new List <Rect>();
                    List <Texture2D> garabeTextures = new List <Texture2D>();
                    List <string>    garbageImages  = new List <string>();

                    for (int j = 0; j < packer.rectangleCount; j++)
                    {
                        rect = packer.getRectangle(j, rect);

                        int index = packer.getRectangleId(j);

                        texture.SetPixels32(rect.x, rect.y, rect.width, rect.height, textures[index].GetPixels32());

                        TextureAsset textureAsset = new TextureAsset();
                        textureAsset.x      = rect.x;
                        textureAsset.y      = rect.y;
                        textureAsset.width  = rect.width;
                        textureAsset.height = rect.height;
                        textureAsset.name   = images[index];

                        textureAssets.Add(textureAsset);

                        garbageRect.Add(rectangles[index]);
                        garabeTextures.Add(textures[index]);
                        garbageImages.Add(images[index]);
                    }

                    foreach (Rect garbage in garbageRect)
                    {
                        rectangles.Remove(garbage);
                    }

                    foreach (Texture2D garbage in garabeTextures)
                    {
                        textures.Remove(garbage);
                    }

                    foreach (string garbage in garbageImages)
                    {
                        images.Remove(garbage);
                    }

                    texture.Apply();

                    if (savePath != "")
                    {
                        File.WriteAllBytes(savePath + "/data" + numSpriteSheet + ".png", texture.EncodeToPNG());
                        File.WriteAllText(savePath + "/data" + numSpriteSheet + ".json", JsonUtility.ToJson(new TextureAssets(textureAssets.ToArray()), true));
                        ++numSpriteSheet;
                    }

                    foreach (TextureAsset textureAsset in textureAssets)
                    {
                        Sprite sprite = Sprite.Create(texture, new Rect(textureAsset.x, textureAsset.y, textureAsset.width, textureAsset.height), spritePivot, pixelsPerUnit, 0, SpriteMeshType.FullRect);
                        sprite.name = textureAsset.name;
                        mSprites.Add(textureAsset.name, sprite);
                    }
                }
            }

            OnProcessCompleted.Invoke();
        }