From da267c4c22e03e7dfc9ccd2b49ea99c78d7db0d9 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 16 Sep 2023 23:18:19 -0500 Subject: [PATCH] Load texture atlas images into shared pointers --- scwx-qt/source/scwx/qt/util/texture_atlas.cpp | 115 ++++++++---------- 1 file changed, 54 insertions(+), 61 deletions(-) diff --git a/scwx-qt/source/scwx/qt/util/texture_atlas.cpp b/scwx-qt/source/scwx/qt/util/texture_atlas.cpp index c6a29d00..335bd70b 100644 --- a/scwx-qt/source/scwx/qt/util/texture_atlas.cpp +++ b/scwx-qt/source/scwx/qt/util/texture_atlas.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #if defined(_MSC_VER) # pragma warning(push, 0) @@ -26,6 +25,10 @@ # pragma warning(pop) #endif +#if defined(LoadImage) +# undef LoadImage +#endif + namespace scwx { namespace qt @@ -42,13 +45,15 @@ public: explicit Impl() {} ~Impl() {} - static boost::gil::rgba8_image_t LoadImage(const std::string& imagePath); + static std::shared_ptr + LoadImage(const std::string& imagePath); std::unordered_map texturePathMap_ {}; std::shared_mutex texturePathMutex_ {}; std::shared_mutex textureCacheMutex_ {}; - std::unordered_map textureCache_ {}; + std::unordered_map> + textureCache_ {}; std::vector atlasArray_ {}; std::unordered_map atlasMap_ {}; @@ -79,10 +84,11 @@ bool TextureAtlas::CacheTexture(const std::string& name, const std::string& path) { // Attempt to load the image - boost::gil::rgba8_image_t image = TextureAtlas::Impl::LoadImage(path); + std::shared_ptr image = + TextureAtlas::Impl::LoadImage(path); // If the image is valid - if (image.width() > 0 && image.height() > 0) + if (image != nullptr && image->width() > 0 && image->height() > 0) { // Store it in the texture cache std::unique_lock lock(p->textureCacheMutex_); @@ -105,9 +111,8 @@ void TextureAtlas::BuildAtlas(std::size_t width, std::size_t height) return; } - typedef std::vector>> + typedef std::vector< + std::pair>> ImageVector; ImageVector images {}; @@ -119,56 +124,56 @@ void TextureAtlas::BuildAtlas(std::size_t width, std::size_t height) std::shared_lock lock(p->texturePathMutex_); // For each registered texture - std::for_each(p->texturePathMap_.cbegin(), - p->texturePathMap_.cend(), - [&](const auto& pair) - { - // Load texture image - boost::gil::rgba8_image_t image = - Impl::LoadImage(pair.second); + std::for_each( + p->texturePathMap_.cbegin(), + p->texturePathMap_.cend(), + [&](const auto& pair) + { + // Load texture image + std::shared_ptr image = + Impl::LoadImage(pair.second); - if (image.width() > 0u && image.height() > 0u) - { - // Store STB rectangle pack data in a vector - stbrpRects.push_back(stbrp_rect { - 0, - static_cast(image.width()), - static_cast(image.height()), - 0, - 0, - 0}); + if (image != nullptr && image->width() > 0u && image->height() > 0u) + { + // Store STB rectangle pack data in a vector + stbrpRects.push_back( + stbrp_rect {0, + static_cast(image->width()), + static_cast(image->height()), + 0, + 0, + 0}); - // Store image data in a vector - images.emplace_back(pair.first, std::move(image)); - } - }); + // Store image data in a vector + images.emplace_back(pair.first, std::move(image)); + } + }); } // Cached images - - // Take a read lock on the texture cache map. The read lock must persist - // through atlas population, as a pointer to the image is taken and used. - std::shared_lock textureCacheLock(p->textureCacheMutex_); - { + // Take a read lock on the texture cache map while adding textures images + // to the atlas vector. + std::shared_lock textureCacheLock(p->textureCacheMutex_); + // For each cached texture for (auto& texture : p->textureCache_) { auto& image = texture.second; - if (image.width() > 0u && image.height() > 0u) + if (image != nullptr && image->width() > 0u && image->height() > 0u) { // Store STB rectangle pack data in a vector stbrpRects.push_back( stbrp_rect {0, - static_cast(image.width()), - static_cast(image.height()), + static_cast(image->width()), + static_cast(image->height()), 0, 0, 0}); // Store image data in a vector - images.emplace_back(texture.first, &image); + images.push_back({texture.first, image}); } } } @@ -227,21 +232,8 @@ void TextureAtlas::BuildAtlas(std::size_t width, std::size_t height) if (stbrpRects[i].was_packed != 0) { // Populate the atlas - boost::gil::rgba8c_view_t imageView; - - // Retrieve the image - if (std::holds_alternative( - images[i].second)) - { - imageView = boost::gil::const_view( - std::get(images[i].second)); - } - else if (std::holds_alternative( - images[i].second)) - { - imageView = boost::gil::const_view( - *std::get(images[i].second)); - } + boost::gil::rgba8c_view_t imageView = + boost::gil::const_view(*images[i].second); boost::gil::rgba8_view_t atlasSubView = boost::gil::subimage_view(atlasView, @@ -388,12 +380,13 @@ TextureAttributes TextureAtlas::GetTextureAttributes(const std::string& name) return attr; } -boost::gil::rgba8_image_t +std::shared_ptr TextureAtlas::Impl::LoadImage(const std::string& imagePath) { logger_->debug("Loading image: {}", imagePath); - boost::gil::rgba8_image_t image; + std::shared_ptr image = + std::make_shared(); QUrl url = QUrl::fromUserInput(QString::fromStdString(imagePath)); @@ -406,7 +399,7 @@ TextureAtlas::Impl::LoadImage(const std::string& imagePath) if (!imageFile.isOpen()) { logger_->error("Could not open image: {}", imagePath); - return image; + return nullptr; } boost::iostreams::stream dataStream(imageFile); @@ -414,12 +407,12 @@ TextureAtlas::Impl::LoadImage(const std::string& imagePath) try { boost::gil::read_and_convert_image( - dataStream, image, boost::gil::png_tag()); + dataStream, *image, boost::gil::png_tag()); } catch (const std::exception& ex) { logger_->error("Error reading image: {}", ex.what()); - return image; + return nullptr; } } else @@ -447,7 +440,7 @@ TextureAtlas::Impl::LoadImage(const std::string& imagePath) if (pixelData == nullptr) { logger_->error("Error loading image: {}", stbi_failure_reason()); - return image; + return nullptr; } // Create a view pointing to the STB image data @@ -458,8 +451,8 @@ TextureAtlas::Impl::LoadImage(const std::string& imagePath) width * desiredChannels); // Copy the view to the destination image - image = boost::gil::rgba8_image_t(stbView); - auto& view = boost::gil::view(image); + *image = boost::gil::rgba8_image_t(stbView); + auto& view = boost::gil::view(*image); // If no alpha channel, replace black with transparent if (numChannels == 3)