libdonut 2.3.6
Application framework for cross-platform game development in C++20
Loading...
Searching...
No Matches
AtlasPacker.hpp
Go to the documentation of this file.
1#ifndef DONUT_ATLAS_PACKER_HPP
2#define DONUT_ATLAS_PACKER_HPP
3
4#include <cstddef> // std::size_t
5#include <vector> // std::vector
6
7namespace donut {
8
17template <std::size_t InitialResolution, std::size_t Padding>
19public:
24 static constexpr std::size_t INITIAL_RESOLUTION = InitialResolution;
25
30 static constexpr std::size_t GROWTH_FACTOR = 2;
31
35 static constexpr std::size_t PADDING = Padding;
36
42 static constexpr float MINIMUM_ROW_HEIGHT_RATIO = 0.7f;
43
52 std::size_t x;
53
58 std::size_t y;
59
65 bool resized;
66 };
67
79 [[nodiscard]] InsertRectangleResult insertRectangle(std::size_t width, std::size_t height) {
80 const std::size_t paddedWidth = width + PADDING * std::size_t{2};
81 const std::size_t paddedHeight = height + PADDING * std::size_t{2};
82
83 Row* rowPointer = nullptr;
84 for (Row& row : rows) {
85 if (const float heightRatio = static_cast<float>(paddedHeight) / static_cast<float>(row.height);
86 heightRatio >= MINIMUM_ROW_HEIGHT_RATIO && heightRatio <= 1.0f && paddedWidth <= resolution - row.width) {
87 rowPointer = &row;
88 break;
89 }
90 }
91
92 bool resized = false;
93 if (!rowPointer) {
94 const std::size_t newRowTop = (rows.empty()) ? std::size_t{0} : rows.back().top + rows.back().height;
95 const std::size_t newRowHeight = paddedHeight + paddedHeight / std::size_t{10};
96 while (resolution < newRowTop + newRowHeight || resolution < paddedWidth) {
97 resolution *= GROWTH_FACTOR;
98 resized = true;
99 }
100 rowPointer = &rows.emplace_back(newRowTop, paddedHeight);
101 }
102
103 const std::size_t x = rowPointer->width + PADDING;
104 const std::size_t y = rowPointer->top + PADDING;
105
106 rowPointer->width += paddedWidth;
107
108 return InsertRectangleResult{x, y, resized};
109 }
110
116 [[nodiscard]] std::size_t getResolution() const noexcept {
117 return resolution;
118 }
119
120private:
121 struct Row {
122 Row(std::size_t top, std::size_t height) noexcept
123 : top(top)
124 , height(height) {}
125
126 std::size_t top;
127 std::size_t width = 0;
128 std::size_t height;
129 };
130
131 std::vector<Row> rows{};
132 std::size_t resolution = INITIAL_RESOLUTION;
133};
134
135} // namespace donut
136
137#endif
Axis-aligned rectangle packer for expandable square texture atlases.
Definition AtlasPacker.hpp:18
static constexpr std::size_t INITIAL_RESOLUTION
The initial resolution that was passed to the InitialResolution template parameter.
Definition AtlasPacker.hpp:24
static constexpr std::size_t GROWTH_FACTOR
The factor by which the resolution of the atlas will grow when it needs to make more space for a new ...
Definition AtlasPacker.hpp:30
static constexpr float MINIMUM_ROW_HEIGHT_RATIO
The minimum ratio between the height of a new rectangle and the size of an existing row in the atlas ...
Definition AtlasPacker.hpp:42
InsertRectangleResult insertRectangle(std::size_t width, std::size_t height)
Find and reserve a suitable space for a new axis-aligned rectangle to be inserted into the atlas.
Definition AtlasPacker.hpp:79
static constexpr std::size_t PADDING
The padding that was passed to the Padding template parameter.
Definition AtlasPacker.hpp:35
std::size_t getResolution() const noexcept
Get the current required resolution of the atlas.
Definition AtlasPacker.hpp:116
Definition Application.hpp:9
Result of the insertRectangle() function.
Definition AtlasPacker.hpp:47
std::size_t x
The horizontal offset, in pixels, from the left edge of the atlas where the new rectangle was inserte...
Definition AtlasPacker.hpp:52
std::size_t y
The vertical offset, in pixels, from the bottom edge of the atlas where the new rectangle was inserte...
Definition AtlasPacker.hpp:58
bool resized
Whether the atlas needed to grow in order to accommodate the new rectangle or not.
Definition AtlasPacker.hpp:65