private List<TextureInfo> LayoutAtlas(List<TextureInfo> _Textures, Atlas _Atlas) { List<Node> freeList = new List<Node>(); List<TextureInfo> textures = new List<TextureInfo>(); _Atlas.Nodes = new List<Node>(); textures = _Textures.ToList(); Node root = new Node(); root.Bounds.Size = new Size(_Atlas.Width, _Atlas.Height); root.SplitType = SplitType.Horizontal; freeList.Add(root); while (freeList.Count > 0 && textures.Count > 0) { Node node = freeList[0]; freeList.RemoveAt(0); TextureInfo bestFit = FindBestFitForNode(node, textures); if (bestFit != null) { if (node.SplitType == SplitType.Horizontal) { HorizontalSplit(node, bestFit.Width, bestFit.Height, freeList); } else { VerticalSplit(node, bestFit.Width, bestFit.Height, freeList); } node.Texture = bestFit; node.Bounds.Width = bestFit.Width; node.Bounds.Height = bestFit.Height; textures.Remove(bestFit); } _Atlas.Nodes.Add(node); } return textures; }
private void VerticalSplit(Node _ToSplit, int _Width, int _Height, List<Node> _List) { Node n1 = new Node(); n1.Bounds.X = _ToSplit.Bounds.X + _Width + Padding; n1.Bounds.Y = _ToSplit.Bounds.Y; n1.Bounds.Width = _ToSplit.Bounds.Width - _Width - Padding; n1.Bounds.Height = _ToSplit.Bounds.Height; n1.SplitType = SplitType.Vertical; Node n2 = new Node(); n2.Bounds.X = _ToSplit.Bounds.X; n2.Bounds.Y = _ToSplit.Bounds.Y + _Height + Padding; n2.Bounds.Width = _Width; n2.Bounds.Height = _ToSplit.Bounds.Height - _Height - Padding; n2.SplitType = SplitType.Horizontal; if (n1.Bounds.Width > 0 && n1.Bounds.Height > 0) _List.Add(n1); if (n2.Bounds.Width > 0 && n2.Bounds.Height > 0) _List.Add(n2); }
private TextureInfo FindBestFitForNode(Node _Node, List<TextureInfo> _Textures) { TextureInfo bestFit = null; float nodeArea = _Node.Bounds.Width * _Node.Bounds.Height; float maxCriteria = 0.0f; foreach (TextureInfo ti in _Textures) { switch (FitHeuristic) { // Max of Width and Height ratios case BestFitHeuristic.MaxOneAxis: if (ti.Width <= _Node.Bounds.Width && ti.Height <= _Node.Bounds.Height) { float wRatio = (float)ti.Width / (float)_Node.Bounds.Width; float hRatio = (float)ti.Height / (float)_Node.Bounds.Height; float ratio = wRatio > hRatio ? wRatio : hRatio; if (ratio > maxCriteria) { maxCriteria = ratio; bestFit = ti; } } break; // Maximize Area coverage case BestFitHeuristic.Area: if (ti.Width <= _Node.Bounds.Width && ti.Height <= _Node.Bounds.Height) { float textureArea = ti.Width * ti.Height; float coverage = textureArea / nodeArea; if (coverage > maxCriteria) { maxCriteria = coverage; bestFit = ti; } } break; } } return bestFit; }