ImagePackNode.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace UnityEditor.U2D.Common
  5. {
  6. internal interface IImagePackNodeVisitor
  7. {
  8. void Visit(ImagePackNode node);
  9. }
  10. class CollectEmptyNodePositionVisitor : IImagePackNodeVisitor
  11. {
  12. public List<RectInt> emptyAreas = new List<RectInt>();
  13. public void Visit(ImagePackNode node)
  14. {
  15. if (node.imageId == -1)
  16. {
  17. emptyAreas.Add(node.rect);
  18. }
  19. }
  20. }
  21. class CollectPackNodePositionVisitor : IImagePackNodeVisitor
  22. {
  23. public CollectPackNodePositionVisitor()
  24. {
  25. positions = new Vector2Int[0];
  26. }
  27. public void Visit(ImagePackNode node)
  28. {
  29. if (node.imageId != -1)
  30. {
  31. if (positions.Length < node.imageId + 1)
  32. {
  33. var p = positions;
  34. Array.Resize(ref p, node.imageId + 1);
  35. positions = p;
  36. }
  37. positions[node.imageId].x = node.rect.x;
  38. positions[node.imageId].y = node.rect.y;
  39. }
  40. }
  41. public Vector2Int[] positions { get; private set; }
  42. }
  43. internal class ImagePackNode
  44. {
  45. public ImagePackNode left;
  46. public ImagePackNode right;
  47. public RectInt rect;
  48. public Vector2Int imageWidth;
  49. public int imageId = -1;
  50. public void AcceptVisitor(IImagePackNodeVisitor visitor)
  51. {
  52. visitor.Visit(this);
  53. if (left != null)
  54. left.AcceptVisitor(visitor);
  55. if (right != null)
  56. right.AcceptVisitor(visitor);
  57. }
  58. public void AdjustSize(int oriWidth, int oriHeight, int deltaW, int deltaH, out int adjustx, out int adjusty)
  59. {
  60. adjustx = adjusty = 0;
  61. int adjustXleft = 0, adjustYleft = 0, adjustXRight = 0, adjustYRight = 0;
  62. if (imageId == -1 || left == null)
  63. {
  64. if (rect.x + rect.width == oriWidth)
  65. {
  66. rect.width += deltaW;
  67. adjustx = deltaW;
  68. }
  69. if (rect.y + rect.height == oriHeight)
  70. {
  71. rect.height += deltaH;
  72. adjusty = deltaH;
  73. }
  74. }
  75. else
  76. {
  77. left.AdjustSize(oriWidth, oriHeight, deltaW, deltaH, out adjustXleft, out adjustYleft);
  78. right.AdjustSize(oriWidth, oriHeight, deltaW, deltaH, out adjustXRight, out adjustYRight);
  79. adjustx = Mathf.Max(adjustXleft, adjustXRight);
  80. rect.width += adjustx;
  81. adjusty = Mathf.Max(adjustYleft, adjustYRight);
  82. rect.height += adjusty;
  83. }
  84. }
  85. public bool TryInsert(ImagePacker.ImagePackRect insert, int padding, out Vector2Int remainingSpace)
  86. {
  87. remainingSpace = Vector2Int.zero;
  88. int insertWidth = insert.rect.width + padding * 2;
  89. int insertHeight = insert.rect.height + padding * 2;
  90. if (insertWidth > rect.width || insertHeight > rect.height)
  91. return false;
  92. if (imageId == -1)
  93. {
  94. remainingSpace.x = rect.width - insertWidth;
  95. remainingSpace.y = rect.height - insertHeight;
  96. }
  97. else
  98. {
  99. Vector2Int spaceLeft, spaceRight;
  100. bool insertLeft, insertRight;
  101. ImagePackNode tryLeft, tryRight;
  102. tryLeft = left;
  103. tryRight = right;
  104. if (left == null && !SplitRects(this, insert, padding, out tryLeft, out tryRight))
  105. {
  106. return false;
  107. }
  108. insertLeft = tryLeft.TryInsert(insert, padding, out spaceLeft);
  109. insertRight = tryRight.TryInsert(insert, padding, out spaceRight);
  110. if (insertLeft && insertRight)
  111. {
  112. remainingSpace = spaceLeft.sqrMagnitude < spaceRight.sqrMagnitude ? spaceLeft : spaceRight;
  113. }
  114. else if (insertLeft)
  115. remainingSpace = spaceLeft;
  116. else if (insertRight)
  117. remainingSpace = spaceRight;
  118. else
  119. return false;
  120. }
  121. return true;
  122. }
  123. static bool SplitRects(ImagePackNode node, ImagePacker.ImagePackRect insert, int padding, out ImagePackNode left, out ImagePackNode right)
  124. {
  125. // Find the best way to split the rect based on a new rect
  126. left = right = null;
  127. var tryRects = new[]
  128. {
  129. new ImagePackNode(), new ImagePackNode(),
  130. new ImagePackNode(), new ImagePackNode()
  131. };
  132. tryRects[0].rect = new RectInt(node.rect.x + node.imageWidth.x, node.rect.y, node.rect.width - node.imageWidth.x, node.rect.height);
  133. tryRects[1].rect = new RectInt(node.rect.x, node.rect.y + node.imageWidth.y, node.imageWidth.x, node.rect.height - node.imageWidth.y);
  134. tryRects[2].rect = new RectInt(node.rect.x, node.rect.y + node.imageWidth.y, node.rect.width, node.rect.height - node.imageWidth.y);
  135. tryRects[3].rect = new RectInt(node.rect.x + node.imageWidth.x, node.rect.y, node.rect.width - node.imageWidth.x, node.imageWidth.y);
  136. float smallestSpace = float.MinValue;
  137. for (int i = 0; i < tryRects.GetLength(0); ++i)
  138. {
  139. //for (int j = 0; j < tryRects.GetLength(1); ++j)
  140. {
  141. Vector2Int newSpaceLeft;
  142. if (tryRects[i].TryInsert(insert, padding, out newSpaceLeft))
  143. {
  144. if (smallestSpace < newSpaceLeft.sqrMagnitude)
  145. {
  146. smallestSpace = newSpaceLeft.sqrMagnitude;
  147. int index = i / 2 * 2;
  148. left = tryRects[index];
  149. right = tryRects[index + 1];
  150. }
  151. }
  152. }
  153. }
  154. return left != null;
  155. }
  156. public bool Insert(ImagePacker.ImagePackRect insert, int padding)
  157. {
  158. int insertWidth = insert.rect.width + padding * 2;
  159. int insertHeight = insert.rect.height + padding * 2;
  160. if (insertWidth > rect.width || insertHeight > rect.height)
  161. return false;
  162. if (imageId == -1)
  163. {
  164. imageId = insert.index;
  165. imageWidth = new Vector2Int(insertWidth, insertHeight);
  166. }
  167. else
  168. {
  169. if (left == null && !SplitRects(this, insert, padding, out left, out right))
  170. {
  171. return false;
  172. }
  173. // We assign to the node that has a better fit for the image
  174. Vector2Int spaceLeft, spaceRight;
  175. bool insertLeft, insertRight;
  176. insertLeft = left.TryInsert(insert, padding, out spaceLeft);
  177. insertRight = right.TryInsert(insert, padding, out spaceRight);
  178. if (insertLeft && insertRight)
  179. {
  180. if (spaceLeft.sqrMagnitude < spaceRight.sqrMagnitude)
  181. left.Insert(insert, padding);
  182. else
  183. right.Insert(insert, padding);
  184. }
  185. else if (insertLeft)
  186. left.Insert(insert, padding);
  187. else if (insertRight)
  188. right.Insert(insert, padding);
  189. else
  190. return false;
  191. }
  192. return true;
  193. }
  194. }
  195. }