libdonut 2.3.6
Application framework for cross-platform game development in C++20
Loading...
Searching...
No Matches
SpriteAtlas.hpp
Go to the documentation of this file.
1#ifndef DONUT_GRAPHICS_SPRITE_ATLAS_HPP
2#define DONUT_GRAPHICS_SPRITE_ATLAS_HPP
3
5#include <donut/Color.hpp>
8#include <donut/math.hpp>
9
10#include <cassert> // assert
11#include <cstddef> // std::size_t
12#include <cstdint> // std::uint8_t
13#include <vector> // std::vector
14
15namespace donut::graphics {
16
17class Renderer; // Forward declaration, to avoid including Renderer.hpp.
18
27 bool useLinearFiltering = false;
28};
29
35public:
39 using Flip = std::uint8_t;
40
44 enum FlipAxis : Flip {
45 NO_FLIP = 0,
47 FLIP_VERTICALLY = 1 << 1,
48 };
49
53 struct SpriteId {
54 private:
55 friend SpriteAtlas;
56
57 constexpr explicit SpriteId(std::size_t index) noexcept
58 : index(index) {}
59
60 std::size_t index;
61 };
62
66 struct Sprite {
67 vec2 position{};
68 vec2 size{};
70 };
71
75 SpriteAtlas() = default;
76
82 explicit SpriteAtlas(const SpriteAtlasOptions& options)
83 : options(options) {}
84
103 [[nodiscard]] SpriteId insert(Renderer& renderer, const ImageView& image, Flip flip = NO_FLIP) {
104 const auto [x, y, resized] = atlasPacker.insertRectangle(image.getWidth(), image.getHeight());
105 prepareAtlasTexture(renderer, resized);
106
107 atlasTexture.pasteImage2D(image, x, y);
108
109 const vec2 position{static_cast<float>(x), static_cast<float>(y)};
110 const vec2 size{static_cast<float>(image.getWidth()), static_cast<float>(image.getHeight())};
111
112 const std::size_t index = sprites.size();
113 sprites.push_back(Sprite{.position = position, .size = size, .flip = flip});
114 return SpriteId{index};
115 }
116
147 [[nodiscard]] SpriteId createSubSprite(SpriteId baseSpriteId, std::size_t offsetX, std::size_t offsetY, std::size_t width, std::size_t height, Flip flip = NO_FLIP) {
148 const Sprite& baseSprite = getSprite(baseSpriteId);
149 assert(static_cast<float>(offsetX) <= baseSprite.size.x);
150 assert(static_cast<float>(offsetY) <= baseSprite.size.y);
151 assert(static_cast<float>(width) <= baseSprite.size.x - static_cast<float>(offsetX));
152 assert(static_cast<float>(height) <= baseSprite.size.y - static_cast<float>(offsetY));
153
154 const vec2 position = baseSprite.position + vec2{static_cast<float>(offsetX), static_cast<float>(offsetY)};
155 const vec2 size{static_cast<float>(width), static_cast<float>(height)};
156
157 const std::size_t index = sprites.size();
158 sprites.push_back(Sprite{.position = position, .size = size, .flip = flip});
159 return SpriteId{index};
160 }
161
174 [[nodiscard]] const Sprite& getSprite(SpriteId id) const {
175 assert(id.index < sprites.size());
176 return sprites[id.index];
177 }
178
186 [[nodiscard]] const Texture& getAtlasTexture() const noexcept {
187 return atlasTexture;
188 }
189
190private:
191 static constexpr std::size_t INITIAL_RESOLUTION = 128;
192 static constexpr std::size_t PADDING = 6;
193
194 void prepareAtlasTexture(Renderer& renderer, bool resized) {
195 if (atlasTexture) {
196 if (resized) {
197 atlasTexture.grow2D(renderer, atlasPacker.getResolution(), atlasPacker.getResolution(), Color::INVISIBLE);
198 }
199 } else {
200 atlasTexture = {
202 atlasPacker.getResolution(),
203 atlasPacker.getResolution(),
204 {.repeat = false, .useLinearFiltering = options.useLinearFiltering, .useMipmap = false},
205 };
206 atlasTexture.fill2D(renderer, Color::INVISIBLE);
207 }
208 }
209
210 AtlasPacker<INITIAL_RESOLUTION, PADDING> atlasPacker{};
211 Texture atlasTexture{};
212 std::vector<Sprite> sprites{};
213 SpriteAtlasOptions options{};
214};
215
216} // namespace donut::graphics
217
218#endif
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
std::size_t getResolution() const noexcept
Get the current required resolution of the atlas.
Definition AtlasPacker.hpp:116
static const Color INVISIBLE
Definition Color.hpp:13
Read-only non-owning view over a 2D image.
Definition Image.hpp:39
constexpr std::size_t getHeight() const noexcept
Get the height of the image referenced by this view.
Definition Image.hpp:100
constexpr std::size_t getWidth() const noexcept
Get the width of the image referenced by this view.
Definition Image.hpp:87
Persistent system for rendering the batched draw commands of a RenderPass onto a Framebuffer,...
Definition Renderer.hpp:38
Expandable texture atlas for packing 2D images into a spritesheet to enable batch rendering.
Definition SpriteAtlas.hpp:34
FlipAxis
Flag values for Flip that describe how a sprite is flipped when rendered.
Definition SpriteAtlas.hpp:44
@ FLIP_HORIZONTALLY
Flip the sprite along the X axis.
Definition SpriteAtlas.hpp:46
@ NO_FLIP
Do not flip the sprite.
Definition SpriteAtlas.hpp:45
@ FLIP_VERTICALLY
Flip the sprite along the Y axis.
Definition SpriteAtlas.hpp:47
SpriteAtlas(const SpriteAtlasOptions &options)
Construct an empty sprite atlas.
Definition SpriteAtlas.hpp:82
const Sprite & getSprite(SpriteId id) const
Get information about a specific image in the spritesheet.
Definition SpriteAtlas.hpp:174
SpriteId insert(Renderer &renderer, const ImageView &image, Flip flip=NO_FLIP)
Add a new image to the spritesheet, possibly expanding the texture atlas in order to make space for i...
Definition SpriteAtlas.hpp:103
std::uint8_t Flip
Flags that describe how a sprite is flipped when rendered.
Definition SpriteAtlas.hpp:39
const Texture & getAtlasTexture() const noexcept
Get a reference to the internal texture atlas.
Definition SpriteAtlas.hpp:186
SpriteId createSubSprite(SpriteId baseSpriteId, std::size_t offsetX, std::size_t offsetY, std::size_t width, std::size_t height, Flip flip=NO_FLIP)
Add a new sprite that is defined as a sub-region of an existing sprite.
Definition SpriteAtlas.hpp:147
SpriteAtlas()=default
Construct an empty sprite atlas.
Storage for multidimensional data, such as 2D images, on the GPU, combined with a sampler configurati...
Definition Texture.hpp:75
void pasteImage2D(std::size_t imageWidth, std::size_t imageHeight, PixelFormat pixelFormat, PixelComponentType pixelComponentType, const void *pixels, std::size_t x, std::size_t y)
Copy 2D image data into the 2D texture at a specific position.
void grow2D(Renderer &renderer, std::size_t newWidth, std::size_t newHeight, std::optional< Color > backgroundColor={})
Expand the allocated 2D texture data by allocating larger texture storage and copying the old texture...
void fill2D(Renderer &renderer, Color color)
Fill the entire allocated 2D texture data with pixels of the given color.
Definition Buffer.hpp:7
@ R8G8B8A8_UNORM
Each texel comprises 4 normalized 8-bit unsigned integer components: red, green, blue,...
Configuration options for a SpriteAtlas.
Definition SpriteAtlas.hpp:22
bool useLinearFiltering
Use bilinear filtering rather than nearest-neighbor interpolation when rendering sprites from this sp...
Definition SpriteAtlas.hpp:27
Identifier for a specific image in the spritesheet.
Definition SpriteAtlas.hpp:53
Information about a specific image in the spritesheet.
Definition SpriteAtlas.hpp:66
Flip flip
Flags that describe how the sprite should be flipped when rendered.
Definition SpriteAtlas.hpp:69
vec2 size
Size of the image in the texture atlas, in texels.
Definition SpriteAtlas.hpp:68
vec2 position
Position of the image in the texture atlas, in texels.
Definition SpriteAtlas.hpp:67