/// <summary> /// Initializes a new instance of <see cref="BitmapBinPacker"/>. /// </summary> public BitmapBinPacker() { Bitmap = null; Disposed = false; Size = Size.Empty; SourceFiles = new List <string>().AsReadOnly(); RootNode = null; }
/// <summary> /// Initializes a new instance of the BinPackerNode class with specified /// parameters. /// </summary> /// <param name="bounds">The bounding box of the node.</param> /// <param name="leftChild">The node's "left-hand" child node.</param> /// <param name="rightChild">The node's "right-hand" child node.</param> /// <param name="leafName">The name of the node.</param> internal BinPackerNode( Rectangle bounds, BinPackerNode leftChild, BinPackerNode rightChild, string leafName ) { Bounds = bounds; LeftChild = leftChild; RightChild = rightChild; LeafName = leafName; }
/// <summary> /// Attempts to insert a new node as a child of this node. /// </summary> /// <param name="node">The node to insert.</param> /// <param name="rect">The bounding box rectangle of the node.</param> /// <returns>The inserted node.</returns> public BinPackerNode Insert(BinPackerNode node, Rectangle rect) { if (node.LeafName == null && node.LeftChild != null && node.RightChild != null) { BinPackerNode newNode = null; newNode = Insert(node.LeftChild, rect); if (newNode == null) { newNode = Insert(node.RightChild, rect); } return(newNode); } else { if (node.LeafName != null) { return(null); } if (node.Bounds.Width == rect.Width && node.Bounds.Height == rect.Height) { return(node); } if (node.Bounds.Width < rect.Width || node.Bounds.Height < rect.Height) { return(null); } node.LeftChild = new BinPackerNode(); node.RightChild = new BinPackerNode(); int deltaWidth = node.Bounds.Width - rect.Width; int deltaHeight = node.Bounds.Height - rect.Height; if (deltaWidth > deltaHeight) { node.LeftChild.Bounds = new Rectangle(node.Bounds.X, node.Bounds.Y, rect.Width, node.Bounds.Height); node.RightChild.Bounds = new Rectangle(node.Bounds.X + rect.Width, node.Bounds.Y, node.Bounds.Width - rect.Width, node.Bounds.Height); } else { node.LeftChild.Bounds = new Rectangle(node.Bounds.X, node.Bounds.Y, node.Bounds.Width, rect.Height); node.RightChild.Bounds = new Rectangle(node.Bounds.X, node.Bounds.Y + rect.Height, node.Bounds.Width, node.Bounds.Height - rect.Height); } return(Insert(node.LeftChild, rect)); } }
/// <summary> /// Maps sprite information to the specified list recursively. /// </summary> /// <param name="currentNode"> /// The current node to discover sprites from; if this is to be the first /// iteration, this should be the root node. /// </param> /// <param name="list"> /// A reference to the <see cref="List{SpriteInfo}"/> collection into which all /// sprite information will be inserted. /// </param> private void DiscoverSprites( BinPackerNode currentNode, ref List <SpriteInfo> list ) { if (currentNode.LeftChild != null) { DiscoverSprites(currentNode.LeftChild, ref list); } if (currentNode.RightChild != null) { DiscoverSprites(currentNode.RightChild, ref list); } if (currentNode.LeafName != null) { list.Add(new SpriteInfo(currentNode.LeafName, currentNode.Bounds)); } }
/// <summary> /// Refreshes the generated atlas <see cref="Bitmap"/>. /// </summary> public void Refresh() { AssertNotDisposed(); // Get ourselves a clean Bitmap // var newBitmap = new Bitmap(Size.Width, Size.Height); // Prepare our root node // RootNode = new BinPackerNode( new Rectangle(0, 0, Size.Width, Size.Height), null, null, null ); // Now do the actual bin packing // var result = BinPackerError.None; var ex = new Exception("Unknown error occurred."); using (var g = Graphics.FromImage(newBitmap)) { foreach (string filePath in SourceFiles) { Bitmap sprite; string spriteName = Path.GetFileNameWithoutExtension(filePath); BinPackerNode node; if (!File.Exists(filePath)) { result = BinPackerError.MissingFile; ex = new FileNotFoundException( "Failed to find a source file.", filePath ); break; } try { sprite = (Bitmap)Bitmap.FromFile(filePath); } catch (Exception anyEx) { result = BinPackerError.UnreadableFile; ex = anyEx; break; } node = RootNode.Insert( RootNode, new Rectangle(Point.Empty, sprite.Size) ); if (node != null) { g.DrawImage(sprite, node.Bounds); node.LeafName = spriteName; sprite.Dispose(); } else { result = BinPackerError.OutOfRoom; ex = new InvalidOperationException( "There is not enough room in the atlas to contain all of the sprites." ); sprite.Dispose(); break; } } } if (result != BinPackerError.None) { throw ex; } Bitmap?.Dispose(); Bitmap = newBitmap; }