61 lines
1.5 KiB
C#
61 lines
1.5 KiB
C#
using System;
|
|
|
|
namespace KeepersCompound.TMV;
|
|
|
|
public static class RectPacker
|
|
{
|
|
public struct Rect
|
|
{
|
|
public int Id;
|
|
public ushort X;
|
|
public ushort Y;
|
|
public ushort Width;
|
|
public ushort Height;
|
|
}
|
|
|
|
public static Rect Pack(Rect[] rectangles, ushort width = 2048, ushort minHeight = 512)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(rectangles);
|
|
ArgumentOutOfRangeException.ThrowIfZero(width);
|
|
ArgumentOutOfRangeException.ThrowIfZero(minHeight);
|
|
|
|
var bounds = new Rect
|
|
{
|
|
Width = width,
|
|
Height = minHeight
|
|
};
|
|
if (rectangles.Length == 0)
|
|
{
|
|
return bounds;
|
|
}
|
|
|
|
Array.Sort(rectangles, (a, b) => b.Height.CompareTo(a.Height));
|
|
|
|
// Naively try to pack into the row, wrapping when we reach the end
|
|
// and expanding the bounds when needed
|
|
ushort rowMaxH = rectangles[0].Height;
|
|
ushort x = 0;
|
|
ushort y = 0;
|
|
var rectCount = rectangles.Length;
|
|
for (var i = 0; i < rectCount; i++)
|
|
{
|
|
var rect = rectangles[i];
|
|
if (x + rect.Width > width)
|
|
{
|
|
x = 0;
|
|
y += rowMaxH;
|
|
rowMaxH = rect.Height;
|
|
}
|
|
|
|
rect.X = x;
|
|
rect.Y = y;
|
|
rectangles[i] = rect;
|
|
|
|
x += rect.Width;
|
|
}
|
|
|
|
bounds.Height = (ushort)(y + rowMaxH);
|
|
return bounds;
|
|
}
|
|
}
|