It ships with a demo executable for visualizing packing results and comparing against stb_rect_pack. It also conveniently runs in-browser (shoutout floooh for sokol making this reasonably straightforward).
You might want to spend a paragraph in Readme explaining why rect packing is and why is it useful. This is not needed for folks who already know that they need a rect packing library, but there’s plenty (well, at least one ) of people who don’t realize this is a thing at all.
What do you mean by smart resizing? With the default settings, the demo will automatically adjust the configured bin width to match the viewport width, but the actual packing is done on-demand into a fixed-sized bin. Perhaps I should have it automatically repack on window resize, which would demonstrate that it can comfortably pack a lot of rects well within a frame’s budget and give the appearance of “smart” resizing (at least as I understand it to mean).
Nice! It looks like this combines rect packing and atlas generation, whereas zrectpack (and stb_rect_pack) are just concerned with the rect packing part. One nice thing I discovered looking at the ghostty implementation is the existence of the orderedRemove function, which imo should just be called remove since it does exactly what you’d expect an ArrayList’s remove function to do.
Usage of orderedRemove is discouraged (since its slow) which is why it should be named longer than swapRemove
I don’t like this reasoning and I doubt that was the intent with the naming (discouragement via obfuscation doesn’t seem to vibe with the zig ethos).
Sometimes an ordered remove is just what’s needed so it’s usage shouldn’t be discouraged per se, the documentation should just make clear what the performance implications are, which it does. Because it doesn’t use canonical naming I just assumed it didn’t exist and ended up using using replaceRange with an empty slice which is effectively the same operation.
IMO this seems like a opportunity to leverage a comptime parameter: list.remove(i, .ordered) and list.remove(i, .swap).
This is exactly what intent was when naming. Original name was removeElementByShifting so we got lucky with shorter variant
It doesn’t sound like the intention was to obfuscate it, it was to make the performance implications more apparent. In my case, that came at the expense of discoverability. Maybe that’s just a skill issue on my part
I’m still trying to understand what this entails. Like it automatically packs into the smallest power-of-two-sized square that can accommodate all rects? It packs into a fixed-width bin with unbounded height?
No one is discouraging you from using the correct removal algorithm for your application. Ignore the cult of speed, embrace the cult of correctness.
But consider that if you’re doing a lot of ordered removal, you might want a different data structure, like the heap in PriorityQueue. If it’s just occasional it’s fine, especially if n is reasonably small.
If you were interested in ever expanding upon this project, there is a well-known (relative to the problem-space) paper that was written “A Thousand Ways to Pack the Bin - A Practical Approach to Two-Dimensional Rectangle Bin Packing.” that I found VERY informative, and explores multiple algorithms. I can’t get the page to load to link it here, but I had used its example code to create some rectangle packing libraries before, with great success.
It is C++, but easy to port. The STB implementation uses a modified Skyline algorithm IIRC, which is fairly balanced. While being balanced in speed/performance is commendable, typically in practice you are going to be needing one extreme or the other:
Computing a texture atlas (runs rarely). Maximum efficiency of space, speed not as much of a concern. A few extra milli-/micro-seconds is not a problem.
Computing every frame: Maximum speed at the expense of more wasted space if need be.
Skyline can be on-par with best-efficiency with certain data-sets, but typically the MaxRects algorithm in the link above will edge it out, especially if you experiment around with its heuristic (i.e. maximize vertical/horizontal, balance, short/long side best fit etc.
Either way, I mainly just wanted to share the link above, I found to be invaluable when designing a rect-packing library a few years in Go. I never ported it to Zig, but I imagine Zig’s language features would make it even easier to provide a single interface exposing multiple user options to get the best approach for the circumstances.