feat(pack-shelf): height-sort desc shelf packing with oversize loud-error
This commit is contained in:
54
src/pack-shelf.js
Normal file
54
src/pack-shelf.js
Normal file
@@ -0,0 +1,54 @@
|
||||
// src/pack-shelf.js
|
||||
// Shelf-Pack (height-sort desc, left-to-right per row).
|
||||
// Deterministic: same input order + same maxSize -> same output.
|
||||
//
|
||||
// Input: rects = [{ alias, w, h, ...rest }]
|
||||
// Output: { placed: [{ x, y, w, h, alias, ...rest }], boundsW, boundsH }
|
||||
// or { error: 'oversize', message: '...' }
|
||||
|
||||
function packShelf(rects, maxSize) {
|
||||
// Sort by height descending; tie-break by alias to keep determinism
|
||||
const sorted = [...rects].sort((a, b) => {
|
||||
if (b.h !== a.h) return b.h - a.h;
|
||||
return a.alias.localeCompare(b.alias);
|
||||
});
|
||||
|
||||
const placed = [];
|
||||
let cursorX = 0;
|
||||
let cursorY = 0;
|
||||
let rowHeight = 0;
|
||||
let maxX = 0;
|
||||
|
||||
for (const r of sorted) {
|
||||
if (r.w > maxSize || r.h > maxSize) {
|
||||
return {
|
||||
error: 'oversize',
|
||||
message: `pack-shelf: sprite "${r.alias}" (${r.w}x${r.h}) exceeds max-size ${maxSize}`,
|
||||
};
|
||||
}
|
||||
// Row-wrap if this sprite would exceed maxSize in width
|
||||
if (cursorX + r.w > maxSize) {
|
||||
cursorY += rowHeight;
|
||||
cursorX = 0;
|
||||
rowHeight = 0;
|
||||
}
|
||||
// Check total atlas height
|
||||
if (cursorY + r.h > maxSize) {
|
||||
return {
|
||||
error: 'oversize',
|
||||
message: `pack-shelf: cumulative atlas height exceeds max-size ${maxSize}`,
|
||||
};
|
||||
}
|
||||
placed.push({ ...r, x: cursorX, y: cursorY });
|
||||
cursorX += r.w;
|
||||
if (cursorX > maxX) maxX = cursorX;
|
||||
if (r.h > rowHeight) rowHeight = r.h;
|
||||
}
|
||||
return {
|
||||
placed,
|
||||
boundsW: maxX,
|
||||
boundsH: cursorY + rowHeight,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { packShelf };
|
||||
Reference in New Issue
Block a user