This repository was archived by the owner on Mar 15, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Allow for mipmapping in texture atlas. #50
Open
Possseidon
wants to merge
9
commits into
master
Choose a base branch
from
dev/mipmapping
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
fb0cb44
Fix mipmap count calculation in Texture.h.
Possseidon 93c0157
Add mipmapping support to texture atlas.
Possseidon 124f6cb
Added a function to calculate the absolute difference.
Possseidon 437f40f
Decoupled MipmapLevels a bit more from BorderedImageData.
Possseidon 13fa018
Use auto for a function return in MultiTextureAtlas.
Possseidon 2a701c5
Use no GL-Types in TextureAtlasTiles anymore.
Possseidon 53e9352
Added MipmapLevels to a few tests.
Possseidon de680a7
Fixed a typo.
Possseidon 0fcf4d0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#pragma once | ||
|
||
#include "dang-gl/Image/BorderedImage.h" | ||
#include "dang-gl/Image/ImageMipmapper.h" | ||
#include "dang-gl/Image/PixelFormat.h" | ||
#include "dang-gl/Image/PixelType.h" | ||
#include "dang-math/vector.h" | ||
|
||
namespace dang::gl { | ||
|
||
/// @brief Mipmaps a bordered image into a new bordered image (with border set to "none"). | ||
template <typename TCalcType = float> | ||
struct BorderedImageMipmapper { | ||
template <std::size_t v_dim, PixelFormat v_pixel_format, PixelType v_pixel_type, std::size_t v_row_alignment> | ||
auto operator()(const BorderedImage<v_dim, v_pixel_format, v_pixel_type, v_row_alignment>& bordered_image) const | ||
{ | ||
// Mipmaps entire image including border, but sets border of result to "none". | ||
using BorderedImage = BorderedImage<v_dim, v_pixel_format, v_pixel_type, v_row_alignment>; | ||
return BorderedImage(image_mipmapper<TCalcType>(bordered_image.image())); | ||
} | ||
}; | ||
|
||
template <typename TCalcType = float> | ||
inline constexpr BorderedImageMipmapper<TCalcType> bordered_image_mipmapper; | ||
|
||
} // namespace dang::gl |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#pragma once | ||
|
||
#include "dang-gl/Image/Image.h" | ||
#include "dang-gl/Image/PixelFormat.h" | ||
#include "dang-gl/Image/PixelType.h" | ||
#include "dang-math/vector.h" | ||
|
||
namespace dang::gl { | ||
|
||
/// @brief Mipmaps a regular image using a 2x2 box filter. | ||
/// @remark Odd pixels are copied over, which might result in bad mipmaps, if the size is odd on a lot of levels. | ||
template <typename TCalcType = float> | ||
struct ImageMipmapper { | ||
template <std::size_t v_dim, PixelFormat v_pixel_format, PixelType v_pixel_type, std::size_t v_row_alignment> | ||
auto operator()(const Image<v_dim, v_pixel_format, v_pixel_type, v_row_alignment>& image) const | ||
{ | ||
using Image = Image<v_dim, v_pixel_format, v_pixel_type, v_row_alignment>; | ||
using Pixel = typename Image::Pixel; | ||
using Size = typename Image::Size; | ||
using CalcPixel = dmath::Vector<TCalcType, Pixel::dim>; | ||
|
||
// It is not possible to change box_size at will. | ||
// To get that working more changes would be necessary. | ||
constexpr std::size_t box_size = 2; | ||
constexpr auto box_pixels = box_size * box_size; | ||
|
||
auto floor_size = image.size() / box_size; | ||
auto ceil_size = (image.size() - 1) / box_size + 1; | ||
Image result(ceil_size); | ||
for (const auto& pos : dmath::sbounds2(floor_size)) { | ||
CalcPixel color; | ||
for (const auto& offset : dmath::sbounds2(box_size)) | ||
color += static_cast<CalcPixel>(image[pos * box_size + offset]); | ||
result[pos] = static_cast<Pixel>(color / box_pixels); | ||
} | ||
|
||
auto odd_width = floor_size.x() != ceil_size.x(); | ||
auto odd_height = floor_size.y() != ceil_size.y(); | ||
|
||
if (odd_width) { | ||
auto x = floor_size.x(); | ||
for (std::size_t y = 0; y < floor_size.y(); y++) { | ||
CalcPixel color; | ||
for (std::size_t offset = 0; offset < box_size; offset++) | ||
color += static_cast<CalcPixel>(image[Size(x * box_size, y * box_size + offset)]); | ||
result[Size(x, y)] = static_cast<Pixel>(color / box_size); | ||
} | ||
} | ||
|
||
if (odd_height) { | ||
auto y = floor_size.y(); | ||
for (std::size_t x = 0; x < floor_size.x(); x++) { | ||
CalcPixel color; | ||
for (std::size_t offset = 0; offset < box_size; offset++) | ||
color += static_cast<CalcPixel>(image[Size(x * box_size + offset, y * box_size)]); | ||
result[Size(x, y)] = static_cast<Pixel>(color / box_size); | ||
} | ||
} | ||
|
||
if (odd_width && odd_height) | ||
result[floor_size] = image[floor_size * box_size]; | ||
|
||
return result; | ||
} | ||
}; | ||
|
||
template <typename TCalcType = float> | ||
inline constexpr ImageMipmapper<TCalcType> image_mipmapper; | ||
|
||
} // namespace dang::gl |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#pragma once | ||
|
||
#include "dang-gl/global.h" | ||
#include "dang-math/vector.h" | ||
#include "dang-utils/utils.h" | ||
|
||
namespace dang::gl { | ||
|
||
/// @brief Calculates the number of required mipmap levels for the given texture size. | ||
constexpr std::size_t maxMipmapLevels(std::size_t size) { return dutils::ilog2ceil(size) + 1; } | ||
|
||
/// @brief Returns the next mipmap level size. | ||
/// @remarks Rounds up, which is unusual for mipmaps, but necessary when used in a texture atlas. | ||
constexpr dmath::svec2 nextMipmapSize(const dmath::svec2& size) { return (size.maxValue() - 1) / 2 + 1; } | ||
|
||
/// @brief Combines several mipmap levels of the same image. | ||
template <typename TBorderedImageData> | ||
class MipmapLevels { | ||
public: | ||
using BorderedImageData = TBorderedImageData; | ||
|
||
/// @brief Only stores the given image without generating any additional mipmaps. | ||
MipmapLevels(BorderedImageData full_image) | ||
: mipmap_levels_{std::move(full_image)} | ||
{} | ||
|
||
/// @brief Stores the given bordered image and all mipmap levels using the provided mipmapper. | ||
template <typename TMipmapper> | ||
MipmapLevels(BorderedImageData full_image, TMipmapper mipmapper) | ||
: mipmap_levels_(generateMipmapLevels(std::move(full_image), mipmapper)) | ||
{} | ||
|
||
/// @brief The full image with the highest resolution. | ||
auto& fullImage() { return mipmap_levels_.front(); } | ||
/// @brief The full image with the highest resolution. | ||
const auto& fullImage() const { return mipmap_levels_.front(); } | ||
|
||
/// @brief The total number of mipmap levels, including the original, full size image. | ||
auto count() const { return mipmap_levels_.size(); } | ||
|
||
/// @brief A specific mipmap level with the given index, where 0 gives the original, full size image. | ||
auto& operator[](std::size_t index) { return mipmap_levels_[index]; } | ||
/// @brief A specific mipmap level with the given index, where 0 gives the original, full size image. | ||
const auto& operator[](std::size_t index) const { return mipmap_levels_[index]; } | ||
|
||
auto begin() { return mipmap_levels_.begin(); } | ||
auto begin() const { return mipmap_levels_.begin(); } | ||
auto end() { return mipmap_levels_.end(); } | ||
auto end() const { return mipmap_levels_.end(); } | ||
|
||
private: | ||
/// @brief Uses the given mipmapper to generate a vector of all mipmap levels for the given image. | ||
template <typename TMipmapper> | ||
static auto generateMipmapLevels(BorderedImageData&& full_image, TMipmapper mipmapper) | ||
{ | ||
auto count = maxMipmapLevels(full_image.size().maxValue()); | ||
std::vector<BorderedImageData> mipmap_levels{std::move(full_image)}; | ||
for (std::size_t index = 1; index < count; index++) { | ||
const auto& prev = mipmap_levels.back(); | ||
auto mipmapped = mipmapper(prev); | ||
ensureSizeHalved(prev.size(), mipmapped.size()); | ||
mipmap_levels.push_back(std::move(mipmapped)); | ||
} | ||
return mipmap_levels; | ||
} | ||
|
||
/// @brief Throws an exception if "halved" isn't the correct next mipmap level size for "original". | ||
static void ensureSizeHalved(dmath::svec2 original, dmath::svec2 halved) | ||
{ | ||
if (halved != nextMipmapSize(original)) | ||
throw std::invalid_argument("mipmapper did not properly half the image size"); | ||
} | ||
|
||
std::vector<BorderedImageData> mipmap_levels_; | ||
}; | ||
|
||
} // namespace dang::gl |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
size.x()
is just aGLsizei
and does not have.maxValue()
.Can I just use only
.maxValue()
everywhere and get rid of theseif constexpr
checks?