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