Skip to content
This repository was archived by the owner on Mar 15, 2025. It is now read-only.

Commit cda89bc

Browse files
committed
Use no GL-Types in TextureAtlasTiles anymore.
- Use std::size_t everywhere. - Get rid of a load of static_casts. - Those are now in the OpenGL specializations. - Fix ensureTextureSize for zero sized textures. - Added support for MipmapLevels in tests.
1 parent 17570d8 commit cda89bc

File tree

8 files changed

+128
-122
lines changed

8 files changed

+128
-122
lines changed

dang-gl/include/dang-gl/Texturing/MultiTextureAtlas.h

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,22 +73,27 @@ class TextureAtlasMultiTexture {
7373
Texture2DArray& texture(TSubTextureEnum sub_texture) { return textures_[sub_texture]; }
7474

7575
protected:
76-
bool resize(GLsizei required_size, GLsizei layers, GLsizei mipmap_levels)
76+
bool resize(std::size_t required_size, std::size_t layers, std::size_t mipmap_levels)
7777
{
7878
assert(textures_.front().size().x() == textures_.front().size().y());
7979
if (required_size == textures_.front().size().x() && layers == textures_.front().size().z())
8080
return false;
8181
// /!\ Resets all texture parameters!
82-
for (auto& texture : textures_)
83-
texture = Texture2DArray(
84-
{required_size, required_size, layers}, mipmap_levels, pixel_format_internal_v<v_pixel_format>);
82+
for (auto& texture : textures_) {
83+
texture = Texture2DArray(svec3(static_cast<GLsizei>(required_size),
84+
static_cast<GLsizei>(required_size),
85+
static_cast<GLsizei>(layers)),
86+
static_cast<GLsizei>(mipmap_levels),
87+
pixel_format_internal_v<v_pixel_format>);
88+
}
8589
return true;
8690
};
8791

88-
void modify(const BorderedImageData& bordered_image_data, ivec3 offset, GLint mipmap_level)
92+
void modify(const BorderedImageData& bordered_image_data, dmath::svec3 offset, std::size_t mipmap_level)
8993
{
9094
for (auto sub_texture : dutils::enumerate<TSubTextureEnum>)
91-
textures_[sub_texture].modify(bordered_image_data[sub_texture], offset, mipmap_level);
95+
textures_[sub_texture].modify(
96+
bordered_image_data[sub_texture], static_cast<GLint>(offset), static_cast<GLint>(mipmap_level));
9297
};
9398

9499
private:
@@ -116,8 +121,8 @@ class MultiTextureAtlas
116121
using Base = TextureAtlasBase<
117122
detail::TextureAtlasMultiTexture<TSubTextureEnum, v_pixel_format, v_pixel_type, v_row_alignment>>;
118123

119-
explicit MultiTextureAtlas(std::optional<GLsizei> max_texture_size = std::nullopt,
120-
std::optional<GLsizei> max_layer_count = std::nullopt)
124+
explicit MultiTextureAtlas(std::optional<std::size_t> max_texture_size = std::nullopt,
125+
std::optional<std::size_t> max_layer_count = std::nullopt)
121126
: Base(TextureAtlasUtils::checkLimits(max_texture_size, max_layer_count))
122127
{}
123128
};

dang-gl/include/dang-gl/Texturing/TextureAtlas.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,23 @@ class TextureAtlasSingleTexture {
2626
Texture2DArray& texture() { return texture_; }
2727

2828
protected:
29-
bool resize(GLsizei required_size, GLsizei layers, GLsizei mipmap_levels)
29+
bool resize(std::size_t required_size, std::size_t layers, std::size_t mipmap_levels)
3030
{
3131
assert(texture_.size().x() == texture_.size().y());
3232
if (required_size == texture_.size().x() && layers == texture_.size().z())
3333
return false;
3434
// /!\ Resets all texture parameters!
35-
texture_ = Texture2DArray(
36-
{required_size, required_size, layers}, mipmap_levels, pixel_format_internal_v<v_pixel_format>);
35+
texture_ = Texture2DArray(svec3(static_cast<GLsizei>(required_size),
36+
static_cast<GLsizei>(required_size),
37+
static_cast<GLsizei>(layers)),
38+
static_cast<GLsizei>(mipmap_levels),
39+
pixel_format_internal_v<v_pixel_format>);
3740
return true;
3841
};
3942

40-
void modify(const BorderedImageData& bordered_image_data, ivec3 offset, GLint mipmap_level)
43+
void modify(const BorderedImageData& bordered_image_data, dmath::svec3 offset, std::size_t mipmap_level)
4144
{
42-
texture_.modify(bordered_image_data.image(), offset, mipmap_level);
45+
texture_.modify(bordered_image_data.image(), static_cast<ivec3>(offset), static_cast<GLint>(mipmap_level));
4346
};
4447

4548
private:
@@ -56,8 +59,8 @@ class TextureAtlas
5659
public:
5760
using Base = TextureAtlasBase<detail::TextureAtlasSingleTexture<v_pixel_format, v_pixel_type, v_row_alignment>>;
5861

59-
explicit TextureAtlas(std::optional<GLsizei> max_texture_size = std::nullopt,
60-
std::optional<GLsizei> max_layer_count = std::nullopt)
62+
explicit TextureAtlas(std::optional<std::size_t> max_texture_size = std::nullopt,
63+
std::optional<std::size_t> max_layer_count = std::nullopt)
6164
: Base(TextureAtlasUtils::checkLimits(max_texture_size, max_layer_count))
6265
{}
6366
};

dang-gl/include/dang-gl/Texturing/TextureAtlasBase.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ The TextureBase concept:
1111
1212
- Move-constructible
1313
- using BorderedImageData = ...;
14-
- bool resize(GLsizei required_size, GLsizei layers, GLsizei mipmap_levels)
14+
- bool resize(std::size_t required_size, std::size_t layers, std::size_t mipmap_levels)
1515
-> protected, resizes the texture
16-
- void modify(const BorderedImageData& bordered_image_data, ivec3 offset, GLint mipmap_level)
16+
- void modify(const BorderedImageData& bordered_image_data, dmath::svec3 offset, std::size_t mipmap_level)
1717
-> protected, modifies the texture at a given spot
1818
1919
*/

dang-gl/include/dang-gl/Texturing/TextureAtlasTiles.h

Lines changed: 53 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ The BorderedImageData concept:
2929

3030
/// @brief Holds maximum size restrictions of the texture atlas.
3131
struct TextureAtlasLimits {
32-
GLsizei max_texture_size;
33-
GLsizei max_layer_count;
32+
std::size_t max_texture_size;
33+
std::size_t max_layer_count;
3434
};
3535

3636
/// @brief Can store a large number of texture tiles in multiple layers of grids.
@@ -43,25 +43,25 @@ class TextureAtlasTiles {
4343

4444
/// @brief A function that is called with required size (width and height), layers and mipmap levels.
4545
/// @remark Returns whether actual resizing occurred.
46-
using TextureResizeFunction = std::function<bool(GLsizei, GLsizei, GLsizei)>;
46+
using TextureResizeFunction = std::function<bool(std::size_t, std::size_t, std::size_t)>;
4747

4848
/// @brief A function that uploads the image to a specific position and mipmap level of a texture.
49-
using TextureModifyFunction = std::function<void(const BorderedImageData&, ivec3, GLint)>;
49+
using TextureModifyFunction = std::function<void(const BorderedImageData&, dmath::svec3, std::size_t)>;
5050

5151
class TileHandle;
5252

5353
private:
5454
/// @brief Atlas information which is stored in a unique_ptr, so that it can be shared with all TileData instances.
5555
struct AtlasInfo {
56-
GLsizei atlas_size;
56+
std::size_t atlas_size;
5757
};
5858

5959
/// @brief Information about the placement of a tile, including whether it has been written to the texture yet.
6060
struct TilePlacement {
6161
/// @brief The index of this tile in the layer.
6262
std::size_t index = 0;
6363
/// @brief The position where the write this tile in the array texture.
64-
svec3 position;
64+
dmath::svec3 position;
6565
/// @brief Whether this tile has been written to the array texture yet.
6666
bool written = false;
6767

@@ -70,19 +70,19 @@ class TextureAtlasTiles {
7070
/// @param index The index of this tile in the layer.
7171
/// @param layer The index of the layer itself, determining the z position.
7272
/// @param position The x and y coordinates of the position.
73-
TilePlacement(std::size_t index, svec2 position, GLsizei layer)
73+
TilePlacement(std::size_t index, dmath::svec2 position, std::size_t layer)
7474
: index(index)
7575
, position(position.x(), position.y(), layer)
7676
{}
7777

7878
/// @brief The position on the given mipmap layer.
79-
auto pixelPos(GLsizei mipmap_layer = 0) const { return position.xy() >> mipmap_layer; }
79+
auto pixelPos(std::size_t mipmap_layer = 0) const { return position.xy() >> mipmap_layer; }
8080

8181
/// @brief The position and atlas layer on the given mipmap layer.
82-
auto pixelPosAndLayer(GLsizei mipmap_layer = 0) const
82+
auto pixelPosAndLayer(std::size_t mipmap_layer = 0) const
8383
{
8484
auto [x, y] = pixelPos(mipmap_layer);
85-
return svec3{x, y, position.z()};
85+
return dmath::svec3(x, y, position.z());
8686
}
8787
};
8888

@@ -108,7 +108,7 @@ class TextureAtlasTiles {
108108
class Layer {
109109
public:
110110
/// @brief Creates a new layer with the given tile size, specified as log2.
111-
explicit Layer(const svec2& tile_size_log2, std::size_t max_texture_size)
111+
explicit Layer(const dmath::svec2& tile_size_log2, std::size_t max_texture_size)
112112
: tile_size_log2_(tile_size_log2)
113113
, max_tiles_(calculateMaxTiles(max_texture_size))
114114
{}
@@ -119,22 +119,25 @@ class TextureAtlasTiles {
119119
Layer& operator=(Layer&&) = default;
120120

121121
/// @brief Returns the log2 of the pixel size of a tile.
122-
svec2 tileSizeLog2() const { return tile_size_log2_; }
122+
dmath::svec2 tileSizeLog2() const { return tile_size_log2_; }
123123
/// @brief Returns the pixel size of a single tile.
124-
svec2 tileSize() const { return {GLsizei{1} << tile_size_log2_.x(), GLsizei{1} << tile_size_log2_.y()}; }
124+
dmath::svec2 tileSize() const
125+
{
126+
return {std::size_t{1} << tile_size_log2_.x(), std::size_t{1} << tile_size_log2_.y()};
127+
}
125128

126129
/// @brief Calculates the required grid size (for the longer side) to fit all tiles.
127-
GLsizei requiredGridSizeLog2() const
130+
std::size_t requiredGridSizeLog2() const
128131
{
129132
if (tiles_.empty())
130133
return 0;
131-
auto diff_log2 = std::abs(tile_size_log2_.x() - tile_size_log2_.y());
134+
auto diff_log2 = dutils::absoluteDifference(tile_size_log2_.x(), tile_size_log2_.y());
132135
auto square_tiles = ((tiles_.size() - 1) >> diff_log2) + 1;
133136
return (dutils::ilog2ceil(square_tiles) + 1) >> 1;
134137
}
135138

136139
/// @brief Calculates the required texture size to fit all tiles.
137-
GLsizei requiredTextureSize() const { return tileSize().maxValue() << requiredGridSizeLog2(); }
140+
std::size_t requiredTextureSize() const { return tileSize().maxValue() << requiredGridSizeLog2(); }
138141

139142
/// @brief Whether the grid is empty.
140143
bool empty() const { return tiles_.empty(); }
@@ -143,7 +146,7 @@ class TextureAtlasTiles {
143146
bool full() const { return first_free_tile_ == max_tiles_; }
144147

145148
/// @brief Places a single tile in the grid, filling potential gaps that appeared after removing tiles.
146-
void addTile(TileData& tile, GLsizei layer)
149+
void addTile(TileData& tile, std::size_t layer)
147150
{
148151
assert(!full());
149152
tile.placement = TilePlacement(first_free_tile_, tileSize() * indexToPosition(first_free_tile_), layer);
@@ -199,8 +202,7 @@ class TextureAtlasTiles {
199202
/// @brief Draws a single tile onto the texture.
200203
void drawTile(TileData& tile, const TextureModifyFunction& modify) const
201204
{
202-
for (GLint mipmap_level = 0; mipmap_level < static_cast<GLint>(tile.mipmap_levels.count());
203-
mipmap_level++) {
205+
for (std::size_t mipmap_level = 0; mipmap_level < tile.mipmap_levels.count(); mipmap_level++) {
204206
const auto& bordered_image = tile.mipmap_levels[mipmap_level];
205207
assert(bordered_image);
206208
modify(bordered_image, tile.placement.pixelPosAndLayer(mipmap_level), mipmap_level);
@@ -211,38 +213,38 @@ class TextureAtlasTiles {
211213
/// @brief Returns the maximum number of tiles, that can fit in a square texture of the given size.
212214
std::size_t calculateMaxTiles(std::size_t max_texture_size) const
213215
{
214-
assert(static_cast<std::size_t>(tileSize().maxValue()) <= max_texture_size);
216+
assert(tileSize().maxValue() <= max_texture_size);
215217
auto x_tiles = std::size_t{1} << dutils::ilog2(max_texture_size >> tile_size_log2_.x());
216218
auto y_tiles = std::size_t{1} << dutils::ilog2(max_texture_size >> tile_size_log2_.y());
217219
return x_tiles * y_tiles;
218220
}
219221

220222
/// @brief Inverse pairing function, returning only even/odd bits as x/y.
221-
svec2 indexToPosition(std::size_t index)
223+
dmath::svec2 indexToPosition(std::size_t index)
222224
{
223-
auto size_diff_log2 = std::abs(tile_size_log2_.x() - tile_size_log2_.y());
225+
auto size_diff_log2 = dutils::absoluteDifference(tile_size_log2_.x(), tile_size_log2_.y());
224226
auto flip = tile_size_log2_.x() < tile_size_log2_.y();
225-
auto x = static_cast<GLsizei>(dutils::removeOddBits(index >> size_diff_log2));
226-
auto y = static_cast<GLsizei>(dutils::removeOddBits(index >> (size_diff_log2 + 1)));
227+
auto x = dutils::removeOddBits(index >> size_diff_log2);
228+
auto y = dutils::removeOddBits(index >> (size_diff_log2 + 1));
227229
y <<= size_diff_log2;
228230
y |= index & ~(~std::size_t{0} << size_diff_log2);
229-
return flip ? svec2(y, x) : svec2(x, y);
231+
return flip ? dmath::svec2(y, x) : dmath::svec2(x, y);
230232
}
231233

232234
/// @brief Pairing function, interleaving x/y as odd/even bits of the resulting integer.
233-
std::size_t positionToIndex(svec2 position)
235+
std::size_t positionToIndex(dmath::svec2 position)
234236
{
235237
auto size_diff_log2 = std::abs(tile_size_log2_.x() - tile_size_log2_.y());
236238
auto flip = tile_size_log2_.x() < tile_size_log2_.y();
237239
position = flip ? position.yx() : position;
238240
auto result = position.y() & ~(~std::size_t{0} << size_diff_log2);
239241
position.y() >>= size_diff_log2;
240-
result |= dutils::interleaveZeros(static_cast<std::size_t>(position.x())) << size_diff_log2;
241-
result |= dutils::interleaveZeros(static_cast<std::size_t>(position.y())) << (size_diff_log2 + 1);
242+
result |= dutils::interleaveZeros(position.x()) << size_diff_log2;
243+
result |= dutils::interleaveZeros(position.y()) << (size_diff_log2 + 1);
242244
return result;
243245
}
244246

245-
svec2 tile_size_log2_;
247+
dmath::svec2 tile_size_log2_;
246248
std::vector<TileData*> tiles_;
247249
std::size_t first_free_tile_ = 0;
248250
std::size_t max_tiles_;
@@ -271,30 +273,27 @@ class TextureAtlasTiles {
271273
return !(lhs == rhs);
272274
}
273275

274-
auto atlasPixelSize(GLsizei mipmap_layer = 0) const
276+
auto atlasPixelSize(std::size_t mipmap_layer = 0) const
275277
{
276278
return dataOrThrow().atlas_info->atlas_size >> mipmap_layer;
277279
}
278280

279-
auto pixelPos(GLsizei mipmap_layer = 0) const { return dataOrThrow().placement.pixelPos(mipmap_layer); }
281+
auto pixelPos(std::size_t mipmap_layer = 0) const { return dataOrThrow().placement.pixelPos(mipmap_layer); }
280282

281-
auto pixelSize(GLsizei mipmap_layer = 0) const
282-
{
283-
return dataOrThrow().mipmap_levels[static_cast<std::size_t>(mipmap_layer)].size();
284-
}
283+
auto pixelSize(std::size_t mipmap_layer = 0) const { return dataOrThrow().mipmap_levels[mipmap_layer].size(); }
285284

286-
auto pixelPosAndLayer(GLsizei mipmap_layer = 0) const
285+
auto pixelPosAndLayer(std::size_t mipmap_layer = 0) const
287286
{
288287
return dataOrThrow().placement.pixelPosAndLayer(mipmap_layer);
289288
}
290289

291-
auto pos() const { return static_cast<vec2>(pixelPos()) / vec2(static_cast<GLfloat>(atlasPixelSize())); }
292-
auto size() const { return static_cast<vec2>(pixelSize()) / vec2(static_cast<GLfloat>(atlasPixelSize())); }
290+
auto pos() const { return static_cast<dmath::vec2>(pixelPos()) / static_cast<float>(atlasPixelSize()); }
291+
auto size() const { return static_cast<dmath::vec2>(pixelSize()) / static_cast<float>(atlasPixelSize()); }
293292

294293
bounds2 bounds() const
295294
{
296-
auto padding = dataOrThrow().mipmap_levels.front().padding();
297-
auto inset = static_cast<vec2>(padding) / (2.0f * atlasPixelSize());
295+
auto padding = dataOrThrow().mipmap_levels[0].padding();
296+
auto inset = static_cast<dmath::vec2>(padding) / (2.0f * atlasPixelSize());
298297
auto top_left = pos();
299298
auto bottom_right = top_left + size();
300299
return bounds2(top_left, bottom_right).inset(inset);
@@ -323,12 +322,7 @@ class TextureAtlasTiles {
323322
/// @exception std::invalid_argument if either maximum is less than zero.
324323
TextureAtlasTiles(const TextureAtlasLimits& limits)
325324
: limits_(limits)
326-
{
327-
if (limits.max_texture_size < 0)
328-
throw std::invalid_argument("Maximum texture size cannot be negative.");
329-
if (limits.max_layer_count < 0)
330-
throw std::invalid_argument("Maximum layer count cannot be negative.");
331-
}
325+
{}
332326

333327
TextureAtlasTiles(const TextureAtlasTiles&) = delete;
334328
TextureAtlasTiles(TextureAtlasTiles&&) = default;
@@ -402,18 +396,20 @@ class TextureAtlasTiles {
402396
void ensureTextureSize(const TextureResizeFunction& resize)
403397
{
404398
auto required_size = maxLayerSize();
405-
auto layers = static_cast<GLsizei>(layers_.size());
406-
auto mipmap_levels = static_cast<GLsizei>(maxMipmapLevels(static_cast<std::size_t>(required_size)));
399+
if (required_size == 0)
400+
return;
401+
auto layers = layers_.size();
402+
auto mipmap_levels = maxMipmapLevels(required_size);
407403
if (!resize(required_size, layers, mipmap_levels))
408404
return;
409405
for (const auto& tile : tiles_)
410406
tile->placement.written = false;
411407
}
412408

413409
/// @brief Finds the maximum layer size.
414-
GLsizei maxLayerSize() const
410+
std::size_t maxLayerSize() const
415411
{
416-
GLsizei result = 0;
412+
std::size_t result = 0;
417413
for (auto& layer : layers_)
418414
result = std::max(result, layer.requiredTextureSize());
419415
return result;
@@ -423,16 +419,14 @@ class TextureAtlasTiles {
423419

424420
/// @brief Returns a pointer to a (possibly newly created) layer for the given tile size and its index.
425421
/// @remark The pointer can be null, in which case a new layer would have exceeded the maximum layer count.
426-
LayerResult layerForTile(const svec2& size)
422+
LayerResult layerForTile(const dmath::svec2& size)
427423
{
428-
auto unsigned_width = static_cast<std::make_unsigned_t<GLsizei>>(size.x());
429-
auto unsigned_height = static_cast<std::make_unsigned_t<GLsizei>>(size.y());
430-
auto tile_size_log2 = svec2(static_cast<GLsizei>(dutils::ilog2ceil(unsigned_width)),
431-
static_cast<GLsizei>(dutils::ilog2ceil(unsigned_height)));
424+
auto tile_size_log2 = dmath::svec2(static_cast<std::size_t>(dutils::ilog2ceil(size.x())),
425+
static_cast<std::size_t>(dutils::ilog2ceil(size.y())));
432426
auto layer_iter = std::find_if(begin(layers_), end(layers_), [&](const Layer& layer) {
433427
return !layer.full() && layer.tileSizeLog2() == tile_size_log2;
434428
});
435-
auto layer_index = std::distance(begin(layers_), layer_iter);
429+
auto layer_index = static_cast<std::size_t>(std::distance(begin(layers_), layer_iter));
436430
if (layer_iter != end(layers_))
437431
return {&*layer_iter, layer_index};
438432
if (layer_index >= limits_.max_layer_count)
@@ -455,13 +449,13 @@ class TextureAtlasTiles {
455449
throw std::invalid_argument("Image is too big for texture atlas. (" + size.format() + " > " +
456450
std::to_string(limits_.max_texture_size) + ")");
457451

458-
auto [layer, index] = layerForTile(static_cast<svec2>(size));
452+
auto [layer, index] = layerForTile(size);
459453
if (!layer)
460454
throw std::length_error("Too many texture atlas layers. (max " + std::to_string(limits_.max_layer_count) +
461455
")");
462456

463-
const auto& tile = tiles_.emplace_back(std::make_shared<TileData>(std::move(bordered_image_data), atlas_info_));
464-
layer->addTile(*tile, static_cast<GLsizei>(index));
457+
const auto& tile = tiles_.emplace_back(std::make_shared<TileData>(std::move(mipmap_levels), atlas_info_));
458+
layer->addTile(*tile, index);
465459
atlas_info_->atlas_size = maxLayerSize();
466460
return tile;
467461
}

0 commit comments

Comments
 (0)