Simplify packing by reversing sort and growing in only 1 direction
This commit is contained in:
parent
d55231178e
commit
f6ef623bb4
|
@ -365,10 +365,8 @@ public partial class Mission : Node3D
|
|||
{
|
||||
var bounds = Timing.TimeStage("RectPack", () =>
|
||||
{
|
||||
var bounds = RectPacker.Pack(packingRects);
|
||||
return bounds;
|
||||
return RectPacker.Pack(packingRects);
|
||||
});
|
||||
bounds = RectPacker.TightBounds(packingRects);
|
||||
GD.Print($"Packed {packingRects.Length} rects in ({bounds.Width}, {bounds.Height})");
|
||||
|
||||
var lightmapFormat = Image.Format.Rgba8;
|
||||
|
|
|
@ -13,21 +13,15 @@ public static class RectPacker
|
|||
public ushort Height;
|
||||
}
|
||||
|
||||
enum ExpandDir
|
||||
{
|
||||
X,
|
||||
Y,
|
||||
}
|
||||
|
||||
public static Rect Pack(Rect[] rectangles, ushort minWidth = 512, ushort minHeight = 512)
|
||||
public static Rect Pack(Rect[] rectangles, ushort width = 1024, ushort minHeight = 512)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(rectangles);
|
||||
ArgumentOutOfRangeException.ThrowIfZero(minWidth);
|
||||
ArgumentOutOfRangeException.ThrowIfZero(width);
|
||||
ArgumentOutOfRangeException.ThrowIfZero(minHeight);
|
||||
|
||||
var bounds = new Rect
|
||||
{
|
||||
Width = minWidth,
|
||||
Width = width,
|
||||
Height = minHeight
|
||||
};
|
||||
if (rectangles.Length == 0)
|
||||
|
@ -35,51 +29,25 @@ public static class RectPacker
|
|||
return bounds;
|
||||
}
|
||||
|
||||
Array.Sort(rectangles, (a, b) => a.Height.CompareTo(b.Height));
|
||||
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 rowStartX = 0;
|
||||
ushort rowMaxH = 0;
|
||||
ushort rowMaxH = rectangles[0].Height;
|
||||
ushort x = 0;
|
||||
ushort y = 0;
|
||||
var expandDir = ExpandDir.Y;
|
||||
var rectCount = rectangles.Length;
|
||||
for (var i = 0; i < rectCount; i++)
|
||||
{
|
||||
var rect = rectangles[i];
|
||||
if (rect.Width == 0 || rect.Height == 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(rectangles), rectangles, $"{nameof(rectangles)} contains rect with width or height 0.");
|
||||
}
|
||||
|
||||
// uh oh we've hit the edge, wrap to next row
|
||||
if (x + rect.Width > bounds.Width)
|
||||
{
|
||||
// we just loop to next row
|
||||
x = rowStartX;
|
||||
x = 0;
|
||||
y += rowMaxH;
|
||||
rowMaxH = 0;
|
||||
}
|
||||
|
||||
// uh oh we've hit the edge, expand
|
||||
if (y + rect.Height > bounds.Height)
|
||||
{
|
||||
if (expandDir == ExpandDir.X)
|
||||
rowMaxH = rect.Height;
|
||||
if (y + rowMaxH > bounds.Height)
|
||||
{
|
||||
// We can expand to the right
|
||||
x = bounds.Width;
|
||||
rowStartX = bounds.Width;
|
||||
y = 0;
|
||||
rowMaxH = 0;
|
||||
bounds.Width *= 2;
|
||||
expandDir = ExpandDir.Y;
|
||||
}
|
||||
else if (expandDir == ExpandDir.Y)
|
||||
{
|
||||
rowStartX = 0;
|
||||
bounds.Height *= 2;
|
||||
expandDir = ExpandDir.X;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,32 +56,9 @@ public static class RectPacker
|
|||
rectangles[i] = rect;
|
||||
|
||||
x += rect.Width;
|
||||
if (rect.Height > rowMaxH)
|
||||
{
|
||||
rowMaxH = rect.Height;
|
||||
}
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public static Rect TightBounds(Rect[] rectangles)
|
||||
{
|
||||
var bounds = new Rect();
|
||||
foreach (var rect in rectangles)
|
||||
{
|
||||
var w = rect.X + rect.Width;
|
||||
if (w > bounds.Width)
|
||||
{
|
||||
bounds.Width = (ushort)w;
|
||||
}
|
||||
|
||||
var h = rect.Y + rect.Height;
|
||||
if (h > bounds.Height)
|
||||
{
|
||||
bounds.Height = (ushort)h;
|
||||
}
|
||||
}
|
||||
bounds.Height = (ushort)(y + rowMaxH);
|
||||
return bounds;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue