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}