-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAtlasPacker.cs
More file actions
84 lines (69 loc) · 2.69 KB
/
Copy pathAtlasPacker.cs
File metadata and controls
84 lines (69 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
namespace SpriteStitcher;
[SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")]
public static class AtlasPacker
{
public static Dictionary<string, AtlasHandler.SpriteRect> PackSprites(
List<(string Name, Bitmap Image)> images, int padding, int maxAtlasWidth,
out int atlasWidth, out int atlasHeight)
{
var positions = new Dictionary<string, AtlasHandler.SpriteRect>();
var skyline = new List<(int X, int Y)> { (0, 0) };
atlasWidth = 0;
atlasHeight = 0;
foreach (var (name, image) in images)
{
var wWithPad = image.Width + padding;
var hWithPad = image.Height + padding;
if (wWithPad > maxAtlasWidth)
throw new Exception(
$"Sprite {name} (width + padding {wWithPad}) exceeds max atlas width {maxAtlasWidth}.");
int bestX = -1, bestY = int.MaxValue;
for (var i = 0; i < skyline.Count; i++)
{
var (startX, startY) = skyline[i];
if (startX + wWithPad > maxAtlasWidth)
continue;
var maxY = startY;
var j = i + 1;
var endX = startX + wWithPad;
while (j < skyline.Count && skyline[j].X < endX)
{
maxY = Math.Max(maxY, skyline[j].Y);
j++;
}
if (maxY + hWithPad >= bestY) continue;
bestX = startX;
bestY = maxY;
}
// Start a new row if no fit found
if (bestX == -1)
{
bestX = 0;
bestY = atlasHeight; // place at the current bottom
skyline.Clear();
skyline.Add((0, bestY));
}
positions[name] = new AtlasHandler.SpriteRect
{
X = bestX + padding / 2,
Y = bestY + padding / 2,
Width = image.Width,
Height = image.Height
};
var insertX = bestX;
var insertY = bestY + image.Height + padding;
var insertEnd = bestX + image.Width + padding;
skyline.Add((insertX, insertY));
skyline = skyline
.Where(s => s.X < insertX || s.X > insertEnd)
.Append((insertEnd, bestY))
.OrderBy(s => s.Item1)
.ToList();
atlasWidth = Math.Max(atlasWidth, bestX + image.Width + padding);
atlasHeight = Math.Max(atlasHeight, bestY + image.Height + padding);
}
return positions;
}
}