214 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			214 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using System; | ||
|  | using System.Collections.Generic; | ||
|  | using UnityEngine; | ||
|  | 
 | ||
|  | namespace UnityEditor.U2D.Aseprite.Common | ||
|  | { | ||
|  |     internal interface IImagePackNodeVisitor | ||
|  |     { | ||
|  |         void Visit(ImagePackNode node); | ||
|  |     } | ||
|  | 
 | ||
|  |     class CollectEmptyNodePositionVisitor : IImagePackNodeVisitor | ||
|  |     { | ||
|  |         public List<RectInt> emptyAreas = new List<RectInt>(); | ||
|  |         public void Visit(ImagePackNode node) | ||
|  |         { | ||
|  |             if (node.imageId == -1) | ||
|  |             { | ||
|  |                 emptyAreas.Add(node.rect); | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     class CollectPackNodePositionVisitor : IImagePackNodeVisitor | ||
|  |     { | ||
|  |         public CollectPackNodePositionVisitor() | ||
|  |         { | ||
|  |             positions = new Vector2Int[0]; | ||
|  |         } | ||
|  | 
 | ||
|  |         public void Visit(ImagePackNode node) | ||
|  |         { | ||
|  |             if (node.imageId != -1) | ||
|  |             { | ||
|  |                 if (positions.Length < node.imageId + 1) | ||
|  |                 { | ||
|  |                     var p = positions; | ||
|  |                     Array.Resize(ref p, node.imageId + 1); | ||
|  |                     positions = p; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 positions[node.imageId].x = node.rect.x; | ||
|  |                 positions[node.imageId].y = node.rect.y; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public Vector2Int[] positions { get; private set; } | ||
|  |     } | ||
|  | 
 | ||
|  |     internal class ImagePackNode | ||
|  |     { | ||
|  |         public ImagePackNode left; | ||
|  |         public ImagePackNode right; | ||
|  |         public RectInt rect; | ||
|  |         public Vector2Int imageWidth; | ||
|  |         public int imageId = -1; | ||
|  | 
 | ||
|  |         public void AcceptVisitor(IImagePackNodeVisitor visitor) | ||
|  |         { | ||
|  |             visitor.Visit(this); | ||
|  |             if (left != null) | ||
|  |                 left.AcceptVisitor(visitor); | ||
|  |             if (right != null) | ||
|  |                 right.AcceptVisitor(visitor); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void AdjustSize(int oriWidth, int oriHeight, int deltaW, int deltaH, out int adjustx, out int adjusty) | ||
|  |         { | ||
|  |             adjustx = adjusty = 0; | ||
|  |             int adjustXleft = 0, adjustYleft = 0, adjustXRight = 0, adjustYRight = 0; | ||
|  |             if (imageId == -1 || left == null) | ||
|  |             { | ||
|  |                 if (rect.x + rect.width == oriWidth) | ||
|  |                 { | ||
|  |                     rect.width += deltaW; | ||
|  |                     adjustx = deltaW; | ||
|  |                 } | ||
|  |                 if (rect.y + rect.height == oriHeight) | ||
|  |                 { | ||
|  |                     rect.height += deltaH; | ||
|  |                     adjusty = deltaH; | ||
|  |                 } | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 left.AdjustSize(oriWidth, oriHeight, deltaW, deltaH, out adjustXleft, out adjustYleft); | ||
|  |                 right.AdjustSize(oriWidth, oriHeight, deltaW, deltaH, out adjustXRight, out adjustYRight); | ||
|  | 
 | ||
|  |                 adjustx = Mathf.Max(adjustXleft, adjustXRight); | ||
|  |                 rect.width += adjustx; | ||
|  |                 adjusty = Mathf.Max(adjustYleft, adjustYRight); | ||
|  |                 rect.height += adjusty; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public bool TryInsert(ImagePacker.ImagePackRect insert, int padding, out Vector2Int remainingSpace) | ||
|  |         { | ||
|  |             remainingSpace = Vector2Int.zero; | ||
|  |             int insertWidth = insert.rect.width + padding * 2; | ||
|  |             int insertHeight = insert.rect.height + padding * 2; | ||
|  |             if (insertWidth > rect.width || insertHeight > rect.height) | ||
|  |                 return false; | ||
|  | 
 | ||
|  |             if (imageId == -1) | ||
|  |             { | ||
|  |                 remainingSpace.x = rect.width - insertWidth; | ||
|  |                 remainingSpace.y = rect.height - insertHeight; | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 Vector2Int spaceLeft, spaceRight; | ||
|  |                 bool insertLeft, insertRight; | ||
|  |                 ImagePackNode tryLeft, tryRight; | ||
|  |                 tryLeft = left; | ||
|  |                 tryRight = right; | ||
|  |                 if (left == null && !SplitRects(this, insert, padding, out tryLeft, out tryRight)) | ||
|  |                 { | ||
|  |                     return false; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 insertLeft = tryLeft.TryInsert(insert, padding, out spaceLeft); | ||
|  |                 insertRight = tryRight.TryInsert(insert, padding, out spaceRight); | ||
|  |                 if (insertLeft && insertRight) | ||
|  |                 { | ||
|  |                     remainingSpace = spaceLeft.sqrMagnitude < spaceRight.sqrMagnitude ? spaceLeft : spaceRight; | ||
|  |                 } | ||
|  |                 else if (insertLeft) | ||
|  |                     remainingSpace = spaceLeft; | ||
|  |                 else if (insertRight) | ||
|  |                     remainingSpace = spaceRight; | ||
|  |                 else | ||
|  |                     return false; | ||
|  |             } | ||
|  | 
 | ||
|  |             return true; | ||
|  |         } | ||
|  | 
 | ||
|  |         static bool SplitRects(ImagePackNode node, ImagePacker.ImagePackRect insert, int padding, out ImagePackNode left, out ImagePackNode right) | ||
|  |         { | ||
|  |             // Find the best way to split the rect based on a new rect | ||
|  |             left = right = null; | ||
|  |             var tryRects = new[] | ||
|  |             { | ||
|  |                 new ImagePackNode(), new ImagePackNode(), | ||
|  |                 new ImagePackNode(), new ImagePackNode() | ||
|  |             }; | ||
|  | 
 | ||
|  |             tryRects[0].rect = new RectInt(node.rect.x + node.imageWidth.x, node.rect.y, node.rect.width - node.imageWidth.x, node.rect.height); | ||
|  |             tryRects[1].rect = new RectInt(node.rect.x, node.rect.y + node.imageWidth.y, node.imageWidth.x, node.rect.height - node.imageWidth.y); | ||
|  |             tryRects[2].rect = new RectInt(node.rect.x, node.rect.y + node.imageWidth.y, node.rect.width, node.rect.height - node.imageWidth.y); | ||
|  |             tryRects[3].rect = new RectInt(node.rect.x + node.imageWidth.x, node.rect.y, node.rect.width - node.imageWidth.x, node.imageWidth.y); | ||
|  |             float smallestSpace = float.MinValue; | ||
|  |             for (int i = 0; i < tryRects.GetLength(0); ++i) | ||
|  |             { | ||
|  |                 //for (int j = 0; j < tryRects.GetLength(1); ++j) | ||
|  |                 { | ||
|  |                     Vector2Int newSpaceLeft; | ||
|  |                     if (tryRects[i].TryInsert(insert, padding, out newSpaceLeft)) | ||
|  |                     { | ||
|  |                         if (smallestSpace < newSpaceLeft.sqrMagnitude) | ||
|  |                         { | ||
|  |                             smallestSpace = newSpaceLeft.sqrMagnitude; | ||
|  |                             int index = i / 2 * 2; | ||
|  |                             left = tryRects[index]; | ||
|  |                             right = tryRects[index + 1]; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |             return left != null; | ||
|  |         } | ||
|  | 
 | ||
|  |         public bool Insert(ImagePacker.ImagePackRect insert, int padding) | ||
|  |         { | ||
|  |             int insertWidth = insert.rect.width + padding * 2; | ||
|  |             int insertHeight = insert.rect.height + padding * 2; | ||
|  |             if (insertWidth > rect.width || insertHeight > rect.height) | ||
|  |                 return false; | ||
|  | 
 | ||
|  |             if (imageId == -1) | ||
|  |             { | ||
|  |                 imageId = insert.index; | ||
|  |                 imageWidth = new Vector2Int(insertWidth, insertHeight); | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 if (left == null && !SplitRects(this, insert, padding, out left, out right)) | ||
|  |                 { | ||
|  |                     return false; | ||
|  |                 } | ||
|  |                 // We assign to the node that has a better fit for the image | ||
|  |                 Vector2Int spaceLeft, spaceRight; | ||
|  |                 bool insertLeft, insertRight; | ||
|  |                 insertLeft = left.TryInsert(insert, padding, out spaceLeft); | ||
|  |                 insertRight = right.TryInsert(insert, padding, out spaceRight); | ||
|  |                 if (insertLeft && insertRight) | ||
|  |                 { | ||
|  |                     if (spaceLeft.sqrMagnitude < spaceRight.sqrMagnitude) | ||
|  |                         left.Insert(insert, padding); | ||
|  |                     else | ||
|  |                         right.Insert(insert, padding); | ||
|  |                 } | ||
|  |                 else if (insertLeft) | ||
|  |                     left.Insert(insert, padding); | ||
|  |                 else if (insertRight) | ||
|  |                     right.Insert(insert, padding); | ||
|  |                 else | ||
|  |                     return false; | ||
|  |             } | ||
|  |             return true; | ||
|  |         } | ||
|  |     } | ||
|  | } |