mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 22:10:05 +00:00
Load texture atlas images into shared pointers
This commit is contained in:
parent
6774c16cbb
commit
da267c4c22
1 changed files with 54 additions and 61 deletions
|
|
@ -6,7 +6,6 @@
|
||||||
#include <execution>
|
#include <execution>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
# pragma warning(push, 0)
|
# pragma warning(push, 0)
|
||||||
|
|
@ -26,6 +25,10 @@
|
||||||
# pragma warning(pop)
|
# pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(LoadImage)
|
||||||
|
# undef LoadImage
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace scwx
|
namespace scwx
|
||||||
{
|
{
|
||||||
namespace qt
|
namespace qt
|
||||||
|
|
@ -42,13 +45,15 @@ public:
|
||||||
explicit Impl() {}
|
explicit Impl() {}
|
||||||
~Impl() {}
|
~Impl() {}
|
||||||
|
|
||||||
static boost::gil::rgba8_image_t LoadImage(const std::string& imagePath);
|
static std::shared_ptr<boost::gil::rgba8_image_t>
|
||||||
|
LoadImage(const std::string& imagePath);
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> texturePathMap_ {};
|
std::unordered_map<std::string, std::string> texturePathMap_ {};
|
||||||
std::shared_mutex texturePathMutex_ {};
|
std::shared_mutex texturePathMutex_ {};
|
||||||
|
|
||||||
std::shared_mutex textureCacheMutex_ {};
|
std::shared_mutex textureCacheMutex_ {};
|
||||||
std::unordered_map<std::string, boost::gil::rgba8_image_t> textureCache_ {};
|
std::unordered_map<std::string, std::shared_ptr<boost::gil::rgba8_image_t>>
|
||||||
|
textureCache_ {};
|
||||||
|
|
||||||
std::vector<boost::gil::rgba8_image_t> atlasArray_ {};
|
std::vector<boost::gil::rgba8_image_t> atlasArray_ {};
|
||||||
std::unordered_map<std::string, TextureAttributes> atlasMap_ {};
|
std::unordered_map<std::string, TextureAttributes> atlasMap_ {};
|
||||||
|
|
@ -79,10 +84,11 @@ bool TextureAtlas::CacheTexture(const std::string& name,
|
||||||
const std::string& path)
|
const std::string& path)
|
||||||
{
|
{
|
||||||
// Attempt to load the image
|
// Attempt to load the image
|
||||||
boost::gil::rgba8_image_t image = TextureAtlas::Impl::LoadImage(path);
|
std::shared_ptr<boost::gil::rgba8_image_t> image =
|
||||||
|
TextureAtlas::Impl::LoadImage(path);
|
||||||
|
|
||||||
// If the image is valid
|
// 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
|
// Store it in the texture cache
|
||||||
std::unique_lock lock(p->textureCacheMutex_);
|
std::unique_lock lock(p->textureCacheMutex_);
|
||||||
|
|
@ -105,9 +111,8 @@ void TextureAtlas::BuildAtlas(std::size_t width, std::size_t height)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef std::vector<std::pair<
|
typedef std::vector<
|
||||||
std::string,
|
std::pair<std::string, std::shared_ptr<boost::gil::rgba8_image_t>>>
|
||||||
std::variant<boost::gil::rgba8_image_t, boost::gil::rgba8_image_t*>>>
|
|
||||||
ImageVector;
|
ImageVector;
|
||||||
|
|
||||||
ImageVector images {};
|
ImageVector images {};
|
||||||
|
|
@ -119,21 +124,22 @@ void TextureAtlas::BuildAtlas(std::size_t width, std::size_t height)
|
||||||
std::shared_lock lock(p->texturePathMutex_);
|
std::shared_lock lock(p->texturePathMutex_);
|
||||||
|
|
||||||
// For each registered texture
|
// For each registered texture
|
||||||
std::for_each(p->texturePathMap_.cbegin(),
|
std::for_each(
|
||||||
|
p->texturePathMap_.cbegin(),
|
||||||
p->texturePathMap_.cend(),
|
p->texturePathMap_.cend(),
|
||||||
[&](const auto& pair)
|
[&](const auto& pair)
|
||||||
{
|
{
|
||||||
// Load texture image
|
// Load texture image
|
||||||
boost::gil::rgba8_image_t image =
|
std::shared_ptr<boost::gil::rgba8_image_t> image =
|
||||||
Impl::LoadImage(pair.second);
|
Impl::LoadImage(pair.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
|
// Store STB rectangle pack data in a vector
|
||||||
stbrpRects.push_back(stbrp_rect {
|
stbrpRects.push_back(
|
||||||
0,
|
stbrp_rect {0,
|
||||||
static_cast<stbrp_coord>(image.width()),
|
static_cast<stbrp_coord>(image->width()),
|
||||||
static_cast<stbrp_coord>(image.height()),
|
static_cast<stbrp_coord>(image->height()),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0});
|
0});
|
||||||
|
|
@ -145,30 +151,29 @@ void TextureAtlas::BuildAtlas(std::size_t width, std::size_t height)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cached images
|
// Cached images
|
||||||
|
{
|
||||||
// Take a read lock on the texture cache map. The read lock must persist
|
// Take a read lock on the texture cache map while adding textures images
|
||||||
// through atlas population, as a pointer to the image is taken and used.
|
// to the atlas vector.
|
||||||
std::shared_lock textureCacheLock(p->textureCacheMutex_);
|
std::shared_lock textureCacheLock(p->textureCacheMutex_);
|
||||||
|
|
||||||
{
|
|
||||||
// For each cached texture
|
// For each cached texture
|
||||||
for (auto& texture : p->textureCache_)
|
for (auto& texture : p->textureCache_)
|
||||||
{
|
{
|
||||||
auto& image = texture.second;
|
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
|
// Store STB rectangle pack data in a vector
|
||||||
stbrpRects.push_back(
|
stbrpRects.push_back(
|
||||||
stbrp_rect {0,
|
stbrp_rect {0,
|
||||||
static_cast<stbrp_coord>(image.width()),
|
static_cast<stbrp_coord>(image->width()),
|
||||||
static_cast<stbrp_coord>(image.height()),
|
static_cast<stbrp_coord>(image->height()),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0});
|
0});
|
||||||
|
|
||||||
// Store image data in a vector
|
// 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)
|
if (stbrpRects[i].was_packed != 0)
|
||||||
{
|
{
|
||||||
// Populate the atlas
|
// Populate the atlas
|
||||||
boost::gil::rgba8c_view_t imageView;
|
boost::gil::rgba8c_view_t imageView =
|
||||||
|
boost::gil::const_view(*images[i].second);
|
||||||
// Retrieve the image
|
|
||||||
if (std::holds_alternative<boost::gil::rgba8_image_t>(
|
|
||||||
images[i].second))
|
|
||||||
{
|
|
||||||
imageView = boost::gil::const_view(
|
|
||||||
std::get<boost::gil::rgba8_image_t>(images[i].second));
|
|
||||||
}
|
|
||||||
else if (std::holds_alternative<boost::gil::rgba8_image_t*>(
|
|
||||||
images[i].second))
|
|
||||||
{
|
|
||||||
imageView = boost::gil::const_view(
|
|
||||||
*std::get<boost::gil::rgba8_image_t*>(images[i].second));
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::gil::rgba8_view_t atlasSubView =
|
boost::gil::rgba8_view_t atlasSubView =
|
||||||
boost::gil::subimage_view(atlasView,
|
boost::gil::subimage_view(atlasView,
|
||||||
|
|
@ -388,12 +380,13 @@ TextureAttributes TextureAtlas::GetTextureAttributes(const std::string& name)
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::gil::rgba8_image_t
|
std::shared_ptr<boost::gil::rgba8_image_t>
|
||||||
TextureAtlas::Impl::LoadImage(const std::string& imagePath)
|
TextureAtlas::Impl::LoadImage(const std::string& imagePath)
|
||||||
{
|
{
|
||||||
logger_->debug("Loading image: {}", imagePath);
|
logger_->debug("Loading image: {}", imagePath);
|
||||||
|
|
||||||
boost::gil::rgba8_image_t image;
|
std::shared_ptr<boost::gil::rgba8_image_t> image =
|
||||||
|
std::make_shared<boost::gil::rgba8_image_t>();
|
||||||
|
|
||||||
QUrl url = QUrl::fromUserInput(QString::fromStdString(imagePath));
|
QUrl url = QUrl::fromUserInput(QString::fromStdString(imagePath));
|
||||||
|
|
||||||
|
|
@ -406,7 +399,7 @@ TextureAtlas::Impl::LoadImage(const std::string& imagePath)
|
||||||
if (!imageFile.isOpen())
|
if (!imageFile.isOpen())
|
||||||
{
|
{
|
||||||
logger_->error("Could not open image: {}", imagePath);
|
logger_->error("Could not open image: {}", imagePath);
|
||||||
return image;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::iostreams::stream<util::IoDeviceSource> dataStream(imageFile);
|
boost::iostreams::stream<util::IoDeviceSource> dataStream(imageFile);
|
||||||
|
|
@ -414,12 +407,12 @@ TextureAtlas::Impl::LoadImage(const std::string& imagePath)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
boost::gil::read_and_convert_image(
|
boost::gil::read_and_convert_image(
|
||||||
dataStream, image, boost::gil::png_tag());
|
dataStream, *image, boost::gil::png_tag());
|
||||||
}
|
}
|
||||||
catch (const std::exception& ex)
|
catch (const std::exception& ex)
|
||||||
{
|
{
|
||||||
logger_->error("Error reading image: {}", ex.what());
|
logger_->error("Error reading image: {}", ex.what());
|
||||||
return image;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -447,7 +440,7 @@ TextureAtlas::Impl::LoadImage(const std::string& imagePath)
|
||||||
if (pixelData == nullptr)
|
if (pixelData == nullptr)
|
||||||
{
|
{
|
||||||
logger_->error("Error loading image: {}", stbi_failure_reason());
|
logger_->error("Error loading image: {}", stbi_failure_reason());
|
||||||
return image;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a view pointing to the STB image data
|
// Create a view pointing to the STB image data
|
||||||
|
|
@ -458,8 +451,8 @@ TextureAtlas::Impl::LoadImage(const std::string& imagePath)
|
||||||
width * desiredChannels);
|
width * desiredChannels);
|
||||||
|
|
||||||
// Copy the view to the destination image
|
// Copy the view to the destination image
|
||||||
image = boost::gil::rgba8_image_t(stbView);
|
*image = boost::gil::rgba8_image_t(stbView);
|
||||||
auto& view = boost::gil::view(image);
|
auto& view = boost::gil::view(*image);
|
||||||
|
|
||||||
// If no alpha channel, replace black with transparent
|
// If no alpha channel, replace black with transparent
|
||||||
if (numChannels == 3)
|
if (numChannels == 3)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue