/// <summary> /// Combines as many <see cref="ITextureAtlasable"/> items as possible into an atlas. /// </summary> /// <param name="items">Collection of <see cref="ITextureAtlasable"/> items to add to the atlas.</param> /// <param name="width">Width of the atlas.</param> /// <param name="height">Height of the atlas.</param> /// <param name="breakOnAddFail">If true, the method will return instantly after failing to add an item.</param> /// <returns>Stack containing all items that were successfully added to the atlas. If the /// count of this return value equals the count of the <paramref name="items"/> collection, /// all items were successfully added to the atlas of the specified size.</returns> /// <exception cref="ArgumentException"><paramref name="items"/> is null.</exception> static Stack <AtlasTextureItem> CombineSingleTexture(ICollection <ITextureAtlasable> items, int width, int height, bool breakOnAddFail) { if (items == null) { const string errmsg = "items is null."; if (log.IsFatalEnabled) { log.Fatal(errmsg); } throw new ArgumentException(errmsg, "items"); } // Create the node stack for all set nodes var nodeStack = new Stack <AtlasTextureItem>(items.Count); // Set the positions var root = new AtlasTreeNode(new AtlasTextureItem(width, height)); foreach (var ta in items) { var node = root.Insert(ta.SourceRect.Width + Padding * 2, ta.SourceRect.Height + Padding * 2, ta); if (node != null) { // Assign the TextureAtlas and push the node onto the stack nodeStack.Push(node.AtlasNode); } else if (breakOnAddFail) { // Node didn't fit - return return(nodeStack); } } return(nodeStack); }
/// <summary> /// Inserts a <see cref="ITextureAtlasable"/> into the tree from this <see cref="AtlasTreeNode"/>. /// </summary> /// <param name="w">Width of the area to insert into.</param> /// <param name="h">Height of the area to insert into.</param> /// <param name="atlasItem">The <see cref="ITextureAtlasable"/> that inserted node is for.</param> /// <returns>The <see cref="AtlasTreeNode"/> containing the area the claimed, or null if no area of the /// required size could be found.</returns> public AtlasTreeNode Insert(int w, int h, ITextureAtlasable atlasItem) { if (!IsLeaf) { // Insert into children (left first then right) AtlasTreeNode ret = null; if (Left != null) { ret = Left.Insert(w, h, atlasItem); } if (ret == null && Right != null) { ret = Right.Insert(w, h, atlasItem); } if (ret != null) { ret.AtlasNode.ITextureAtlasable = atlasItem; } return(ret); } else { // Check if it fits and not in use if (ITextureAtlasable != null || w > Rect.Width || h > Rect.Height) { return(null); } // Perfect fit if (w == Rect.Width && h == Rect.Height) { return(this); } // Not a perfect fit, split the node up into new nodes var diffW = Rect.Width - w; var diffH = Rect.Height - h; // Decide which way to split if (diffW > diffH) { // Split vertically Left = new AtlasTreeNode(new Rectangle(Rect.Left, Rect.Top, w, Rect.Height)); Right = new AtlasTreeNode(new Rectangle(Rect.Left + w, Rect.Top, Rect.Width - w, Rect.Height)); } else { // Split horizontally Left = new AtlasTreeNode(new Rectangle(Rect.Left, Rect.Top, Rect.Width, h)); Right = new AtlasTreeNode(new Rectangle(Rect.Left, Rect.Top + h, Rect.Width, Rect.Height - h)); } // Insert the rectangle first new child var node = Left.Insert(w, h, atlasItem); // If the insert is a perfect fit, drop the node from the tree to prevent checking it again if (diffW == 0 || diffH == 0) { Left = null; } // If the node was created, set the atlas item if (node != null) { node.AtlasNode.ITextureAtlasable = atlasItem; } return(node); } }
/// <summary> /// Combines as many <see cref="ITextureAtlasable"/> items as possible into an atlas. /// </summary> /// <param name="items">Collection of <see cref="ITextureAtlasable"/> items to add to the atlas.</param> /// <param name="width">Width of the atlas.</param> /// <param name="height">Height of the atlas.</param> /// <param name="breakOnAddFail">If true, the method will return instantly after failing to add an item.</param> /// <returns>Stack containing all items that were successfully added to the atlas. If the /// count of this return value equals the count of the <paramref name="items"/> collection, /// all items were successfully added to the atlas of the specified size.</returns> /// <exception cref="ArgumentException"><paramref name="items"/> is null.</exception> static Stack<AtlasTextureItem> CombineSingleTexture(ICollection<ITextureAtlasable> items, int width, int height, bool breakOnAddFail) { if (items == null) { const string errmsg = "items is null."; if (log.IsFatalEnabled) log.Fatal(errmsg); throw new ArgumentException(errmsg, "items"); } // Create the node stack for all set nodes var nodeStack = new Stack<AtlasTextureItem>(items.Count); // Set the positions var root = new AtlasTreeNode(new AtlasTextureItem(width, height)); foreach (var ta in items) { var node = root.Insert(ta.SourceRect.Width + Padding * 2, ta.SourceRect.Height + Padding * 2, ta); if (node != null) { // Assign the TextureAtlas and push the node onto the stack nodeStack.Push(node.AtlasNode); } else if (breakOnAddFail) { // Node didn't fit - return return nodeStack; } } return nodeStack; }
/// <summary> /// Inserts a <see cref="ITextureAtlasable"/> into the tree from this <see cref="AtlasTreeNode"/>. /// </summary> /// <param name="w">Width of the area to insert into.</param> /// <param name="h">Height of the area to insert into.</param> /// <param name="atlasItem">The <see cref="ITextureAtlasable"/> that inserted node is for.</param> /// <returns>The <see cref="AtlasTreeNode"/> containing the area the claimed, or null if no area of the /// required size could be found.</returns> public AtlasTreeNode Insert(int w, int h, ITextureAtlasable atlasItem) { if (!IsLeaf) { // Insert into children (left first then right) AtlasTreeNode ret = null; if (Left != null) ret = Left.Insert(w, h, atlasItem); if (ret == null && Right != null) ret = Right.Insert(w, h, atlasItem); if (ret != null) ret.AtlasNode.ITextureAtlasable = atlasItem; return ret; } else { // Check if it fits and not in use if (ITextureAtlasable != null || w > Rect.Width || h > Rect.Height) return null; // Perfect fit if (w == Rect.Width && h == Rect.Height) return this; // Not a perfect fit, split the node up into new nodes var diffW = Rect.Width - w; var diffH = Rect.Height - h; // Decide which way to split if (diffW > diffH) { // Split vertically Left = new AtlasTreeNode(new Rectangle(Rect.Left, Rect.Top, w, Rect.Height)); Right = new AtlasTreeNode(new Rectangle(Rect.Left + w, Rect.Top, Rect.Width - w, Rect.Height)); } else { // Split horizontally Left = new AtlasTreeNode(new Rectangle(Rect.Left, Rect.Top, Rect.Width, h)); Right = new AtlasTreeNode(new Rectangle(Rect.Left, Rect.Top + h, Rect.Width, Rect.Height - h)); } // Insert the rectangle first new child var node = Left.Insert(w, h, atlasItem); // If the insert is a perfect fit, drop the node from the tree to prevent checking it again if (diffW == 0 || diffH == 0) Left = null; // If the node was created, set the atlas item if (node != null) node.AtlasNode.ITextureAtlasable = atlasItem; return node; } }