mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 18:40:05 +00:00
Generate multiple texture atlases when first atlas is full
This commit is contained in:
parent
7198d1c7af
commit
9766e02f32
10 changed files with 205 additions and 141 deletions
|
|
@ -8,14 +8,14 @@
|
||||||
|
|
||||||
layout (location = 0) in vec2 aLatLong;
|
layout (location = 0) in vec2 aLatLong;
|
||||||
layout (location = 1) in vec2 aXYOffset;
|
layout (location = 1) in vec2 aXYOffset;
|
||||||
layout (location = 2) in vec2 aTexCoord;
|
layout (location = 2) in vec3 aTexCoord;
|
||||||
layout (location = 3) in vec4 aModulate;
|
layout (location = 3) in vec4 aModulate;
|
||||||
|
|
||||||
uniform mat4 uMVPMatrix;
|
uniform mat4 uMVPMatrix;
|
||||||
uniform mat4 uMapMatrix;
|
uniform mat4 uMapMatrix;
|
||||||
uniform vec2 uMapScreenCoord;
|
uniform vec2 uMapScreenCoord;
|
||||||
|
|
||||||
smooth out vec2 texCoord;
|
smooth out vec3 texCoord;
|
||||||
smooth out vec4 color;
|
smooth out vec4 color;
|
||||||
|
|
||||||
vec2 latLngToScreenCoordinate(in vec2 latLng)
|
vec2 latLngToScreenCoordinate(in vec2 latLng)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
layout (location = 0) in vec2 aLatLong;
|
layout (location = 0) in vec2 aLatLong;
|
||||||
layout (location = 1) in vec2 aXYOffset;
|
layout (location = 1) in vec2 aXYOffset;
|
||||||
layout (location = 2) in vec2 aTexCoord;
|
layout (location = 2) in vec3 aTexCoord;
|
||||||
layout (location = 3) in vec4 aModulate;
|
layout (location = 3) in vec4 aModulate;
|
||||||
layout (location = 4) in float aAngleDeg;
|
layout (location = 4) in float aAngleDeg;
|
||||||
layout (location = 5) in int aThreshold;
|
layout (location = 5) in int aThreshold;
|
||||||
|
|
@ -21,11 +21,11 @@ uniform vec2 uMapScreenCoord;
|
||||||
out VertexData
|
out VertexData
|
||||||
{
|
{
|
||||||
int threshold;
|
int threshold;
|
||||||
vec2 texCoord;
|
vec3 texCoord;
|
||||||
vec4 color;
|
vec4 color;
|
||||||
} vsOut;
|
} vsOut;
|
||||||
|
|
||||||
smooth out vec2 texCoord;
|
smooth out vec3 texCoord;
|
||||||
smooth out vec4 color;
|
smooth out vec4 color;
|
||||||
|
|
||||||
vec2 latLngToScreenCoordinate(in vec2 latLng)
|
vec2 latLngToScreenCoordinate(in vec2 latLng)
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ uniform vec2 uMapScreenCoord;
|
||||||
out VertexData
|
out VertexData
|
||||||
{
|
{
|
||||||
int threshold;
|
int threshold;
|
||||||
vec2 texCoord;
|
vec3 texCoord;
|
||||||
vec4 color;
|
vec4 color;
|
||||||
} vsOut;
|
} vsOut;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ precision mediump float;
|
||||||
|
|
||||||
uniform sampler2DArray uTexture;
|
uniform sampler2DArray uTexture;
|
||||||
|
|
||||||
smooth in vec2 texCoord;
|
smooth in vec3 texCoord;
|
||||||
smooth in vec4 color;
|
smooth in vec4 color;
|
||||||
|
|
||||||
layout (location = 0) out vec4 fragColor;
|
layout (location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
fragColor = texture(uTexture, vec3(texCoord, 0.0)) * color;
|
fragColor = texture(uTexture, texCoord) * color;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ uniform float uMapDistance;
|
||||||
in VertexData
|
in VertexData
|
||||||
{
|
{
|
||||||
int threshold;
|
int threshold;
|
||||||
vec2 texCoord;
|
vec3 texCoord;
|
||||||
vec4 color;
|
vec4 color;
|
||||||
} gsIn[];
|
} gsIn[];
|
||||||
|
|
||||||
smooth out vec2 texCoord;
|
smooth out vec3 texCoord;
|
||||||
smooth out vec4 color;
|
smooth out vec4 color;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ static constexpr size_t kNumRectangles = 1;
|
||||||
static constexpr size_t kNumTriangles = kNumRectangles * 2;
|
static constexpr size_t kNumTriangles = kNumRectangles * 2;
|
||||||
static constexpr size_t kVerticesPerTriangle = 3;
|
static constexpr size_t kVerticesPerTriangle = 3;
|
||||||
static constexpr size_t kVerticesPerRectangle = kVerticesPerTriangle * 2;
|
static constexpr size_t kVerticesPerRectangle = kVerticesPerTriangle * 2;
|
||||||
static constexpr size_t kPointsPerVertex = 10;
|
static constexpr size_t kPointsPerVertex = 11;
|
||||||
static constexpr size_t kBufferLength =
|
static constexpr size_t kBufferLength =
|
||||||
kNumTriangles * kVerticesPerTriangle * kPointsPerVertex;
|
kNumTriangles * kVerticesPerTriangle * kPointsPerVertex;
|
||||||
|
|
||||||
|
|
@ -147,7 +147,7 @@ void GeoLine::Initialize()
|
||||||
|
|
||||||
// aTexCoord
|
// aTexCoord
|
||||||
gl.glVertexAttribPointer(2,
|
gl.glVertexAttribPointer(2,
|
||||||
2,
|
3,
|
||||||
GL_FLOAT,
|
GL_FLOAT,
|
||||||
GL_FALSE,
|
GL_FALSE,
|
||||||
kPointsPerVertex * sizeof(float),
|
kPointsPerVertex * sizeof(float),
|
||||||
|
|
@ -160,7 +160,7 @@ void GeoLine::Initialize()
|
||||||
GL_FLOAT,
|
GL_FLOAT,
|
||||||
GL_FALSE,
|
GL_FALSE,
|
||||||
kPointsPerVertex * sizeof(float),
|
kPointsPerVertex * sizeof(float),
|
||||||
reinterpret_cast<void*>(6 * sizeof(float)));
|
reinterpret_cast<void*>(7 * sizeof(float)));
|
||||||
gl.glEnableVertexAttribArray(3);
|
gl.glEnableVertexAttribArray(3);
|
||||||
|
|
||||||
p->dirty_ = true;
|
p->dirty_ = true;
|
||||||
|
|
@ -264,6 +264,8 @@ void GeoLine::Impl::Update()
|
||||||
const float oy = width_ * 0.5f * sinf(angle_);
|
const float oy = width_ * 0.5f * sinf(angle_);
|
||||||
|
|
||||||
// Texture coordinates
|
// Texture coordinates
|
||||||
|
static constexpr float r = 0.0f;
|
||||||
|
|
||||||
const float ls = texture_.sLeft_;
|
const float ls = texture_.sLeft_;
|
||||||
const float rs = texture_.sRight_;
|
const float rs = texture_.sRight_;
|
||||||
const float tt = texture_.tTop_;
|
const float tt = texture_.tTop_;
|
||||||
|
|
@ -289,12 +291,12 @@ void GeoLine::Impl::Update()
|
||||||
{ //
|
{ //
|
||||||
// Line
|
// Line
|
||||||
{
|
{
|
||||||
{lx, by, -ox, -oy, ls, bt, mc0, mc1, mc2, mc3}, // BL
|
{lx, by, -ox, -oy, ls, bt, r, mc0, mc1, mc2, mc3}, // BL
|
||||||
{lx, by, +ox, +oy, ls, tt, mc0, mc1, mc2, mc3}, // TL
|
{lx, by, +ox, +oy, ls, tt, r, mc0, mc1, mc2, mc3}, // TL
|
||||||
{rx, ty, -ox, -oy, rs, bt, mc0, mc1, mc2, mc3}, // BR
|
{rx, ty, -ox, -oy, rs, bt, r, mc0, mc1, mc2, mc3}, // BR
|
||||||
{rx, ty, -ox, -oy, rs, bt, mc0, mc1, mc2, mc3}, // BR
|
{rx, ty, -ox, -oy, rs, bt, r, mc0, mc1, mc2, mc3}, // BR
|
||||||
{rx, ty, +ox, +oy, rs, tt, mc0, mc1, mc2, mc3}, // TR
|
{rx, ty, +ox, +oy, rs, tt, r, mc0, mc1, mc2, mc3}, // TR
|
||||||
{lx, by, +ox, +oy, ls, tt, mc0, mc1, mc2, mc3} // TL
|
{lx, by, +ox, +oy, ls, tt, r, mc0, mc1, mc2, mc3} // TL
|
||||||
}};
|
}};
|
||||||
|
|
||||||
gl.glBufferData(GL_ARRAY_BUFFER,
|
gl.glBufferData(GL_ARRAY_BUFFER,
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ static constexpr std::size_t kNumTriangles = kNumRectangles * 2;
|
||||||
static constexpr std::size_t kVerticesPerTriangle = 3;
|
static constexpr std::size_t kVerticesPerTriangle = 3;
|
||||||
static constexpr std::size_t kVerticesPerRectangle = kVerticesPerTriangle * 2;
|
static constexpr std::size_t kVerticesPerRectangle = kVerticesPerTriangle * 2;
|
||||||
static constexpr std::size_t kPointsPerVertex = 9;
|
static constexpr std::size_t kPointsPerVertex = 9;
|
||||||
static constexpr std::size_t kPointsPerTexCoord = 2;
|
static constexpr std::size_t kPointsPerTexCoord = 3;
|
||||||
static constexpr std::size_t kIconBufferLength =
|
static constexpr std::size_t kIconBufferLength =
|
||||||
kNumTriangles * kVerticesPerTriangle * kPointsPerVertex;
|
kNumTriangles * kVerticesPerTriangle * kPointsPerVertex;
|
||||||
static constexpr std::size_t kTextureBufferLength =
|
static constexpr std::size_t kTextureBufferLength =
|
||||||
|
|
@ -208,7 +208,7 @@ void PlacefileIcons::Initialize()
|
||||||
|
|
||||||
// aTexCoord
|
// aTexCoord
|
||||||
gl.glVertexAttribPointer(2,
|
gl.glVertexAttribPointer(2,
|
||||||
2,
|
3,
|
||||||
GL_FLOAT,
|
GL_FLOAT,
|
||||||
GL_FALSE,
|
GL_FALSE,
|
||||||
kPointsPerTexCoord * sizeof(float),
|
kPointsPerTexCoord * sizeof(float),
|
||||||
|
|
@ -508,12 +508,12 @@ void PlacefileIcons::Impl::UpdateTextureBuffer()
|
||||||
textureBuffer_.end(),
|
textureBuffer_.end(),
|
||||||
{
|
{
|
||||||
// Icon
|
// Icon
|
||||||
0.0f, 0.0f, // BL
|
0.0f, 0.0f, 0.0f, // BL
|
||||||
0.0f, 0.0f, // TL
|
0.0f, 0.0f, 0.0f, // TL
|
||||||
0.0f, 0.0f, // BR
|
0.0f, 0.0f, 0.0f, // BR
|
||||||
0.0f, 0.0f, // BR
|
0.0f, 0.0f, 0.0f, // BR
|
||||||
0.0f, 0.0f, // TR
|
0.0f, 0.0f, 0.0f, // TR
|
||||||
0.0f, 0.0f // TL
|
0.0f, 0.0f, 0.0f // TL
|
||||||
});
|
});
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
@ -536,12 +536,12 @@ void PlacefileIcons::Impl::UpdateTextureBuffer()
|
||||||
textureBuffer_.end(),
|
textureBuffer_.end(),
|
||||||
{
|
{
|
||||||
// Icon
|
// Icon
|
||||||
0.0f, 0.0f, // BL
|
0.0f, 0.0f, 0.0f, // BL
|
||||||
0.0f, 0.0f, // TL
|
0.0f, 0.0f, 0.0f, // TL
|
||||||
0.0f, 0.0f, // BR
|
0.0f, 0.0f, 0.0f, // BR
|
||||||
0.0f, 0.0f, // BR
|
0.0f, 0.0f, 0.0f, // BR
|
||||||
0.0f, 0.0f, // TR
|
0.0f, 0.0f, 0.0f, // TR
|
||||||
0.0f, 0.0f // TL
|
0.0f, 0.0f, 0.0f // TL
|
||||||
});
|
});
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
@ -559,18 +559,19 @@ void PlacefileIcons::Impl::UpdateTextureBuffer()
|
||||||
const float rs = ls + icon.scaledWidth_;
|
const float rs = ls + icon.scaledWidth_;
|
||||||
const float tt = icon.texture_.tTop_ + iconY;
|
const float tt = icon.texture_.tTop_ + iconY;
|
||||||
const float bt = tt + icon.scaledHeight_;
|
const float bt = tt + icon.scaledHeight_;
|
||||||
|
const float r = static_cast<float>(icon.texture_.layerId_);
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
textureBuffer_.insert(
|
textureBuffer_.insert(
|
||||||
textureBuffer_.end(),
|
textureBuffer_.end(),
|
||||||
{
|
{
|
||||||
// Icon
|
// Icon
|
||||||
ls, bt, // BL
|
ls, bt, r, // BL
|
||||||
ls, tt, // TL
|
ls, tt, r, // TL
|
||||||
rs, bt, // BR
|
rs, bt, r, // BR
|
||||||
rs, bt, // BR
|
rs, bt, r, // BR
|
||||||
rs, tt, // TR
|
rs, tt, r, // TR
|
||||||
ls, tt // TL
|
ls, tt, r // TL
|
||||||
});
|
});
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ static constexpr std::size_t kNumTriangles = kNumRectangles * 2;
|
||||||
static constexpr std::size_t kVerticesPerTriangle = 3;
|
static constexpr std::size_t kVerticesPerTriangle = 3;
|
||||||
static constexpr std::size_t kVerticesPerRectangle = kVerticesPerTriangle * 2;
|
static constexpr std::size_t kVerticesPerRectangle = kVerticesPerTriangle * 2;
|
||||||
static constexpr std::size_t kPointsPerVertex = 8;
|
static constexpr std::size_t kPointsPerVertex = 8;
|
||||||
static constexpr std::size_t kPointsPerTexCoord = 2;
|
static constexpr std::size_t kPointsPerTexCoord = 3;
|
||||||
static constexpr std::size_t kImageBufferLength =
|
static constexpr std::size_t kImageBufferLength =
|
||||||
kNumTriangles * kVerticesPerTriangle * kPointsPerVertex;
|
kNumTriangles * kVerticesPerTriangle * kPointsPerVertex;
|
||||||
static constexpr std::size_t kTextureBufferLength =
|
static constexpr std::size_t kTextureBufferLength =
|
||||||
|
|
@ -177,7 +177,7 @@ void PlacefileImages::Initialize()
|
||||||
|
|
||||||
// aTexCoord
|
// aTexCoord
|
||||||
gl.glVertexAttribPointer(2,
|
gl.glVertexAttribPointer(2,
|
||||||
2,
|
3,
|
||||||
GL_FLOAT,
|
GL_FLOAT,
|
||||||
GL_FALSE,
|
GL_FALSE,
|
||||||
kPointsPerTexCoord * sizeof(float),
|
kPointsPerTexCoord * sizeof(float),
|
||||||
|
|
@ -367,6 +367,8 @@ void PlacefileImages::Impl::UpdateTextureBuffer()
|
||||||
currentImageFiles_.cbegin()->second :
|
currentImageFiles_.cbegin()->second :
|
||||||
it->second;
|
it->second;
|
||||||
|
|
||||||
|
const float r = static_cast<float>(image.texture_.layerId_);
|
||||||
|
|
||||||
// Limit processing to groups of 3 (triangles)
|
// Limit processing to groups of 3 (triangles)
|
||||||
std::size_t numElements = di->elements_.size() - di->elements_.size() % 3;
|
std::size_t numElements = di->elements_.size() - di->elements_.size() % 3;
|
||||||
for (std::size_t i = 0; i < numElements; ++i)
|
for (std::size_t i = 0; i < numElements; ++i)
|
||||||
|
|
@ -379,7 +381,7 @@ void PlacefileImages::Impl::UpdateTextureBuffer()
|
||||||
const float t =
|
const float t =
|
||||||
image.texture_.tTop_ + (image.scaledHeight_ * element.tv_);
|
image.texture_.tTop_ + (image.scaledHeight_ * element.tv_);
|
||||||
|
|
||||||
textureBuffer_.insert(textureBuffer_.end(), {s, t});
|
textureBuffer_.insert(textureBuffer_.end(), {s, t, r});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ public:
|
||||||
std::shared_mutex textureCacheMutex_ {};
|
std::shared_mutex textureCacheMutex_ {};
|
||||||
std::unordered_map<std::string, boost::gil::rgba8_image_t> textureCache_ {};
|
std::unordered_map<std::string, boost::gil::rgba8_image_t> textureCache_ {};
|
||||||
|
|
||||||
boost::gil::rgba8_image_t atlas_ {};
|
std::vector<boost::gil::rgba8_image_t> atlasArray_ {};
|
||||||
std::unordered_map<std::string, TextureAttributes> atlasMap_ {};
|
std::unordered_map<std::string, TextureAttributes> atlasMap_ {};
|
||||||
std::shared_mutex atlasMutex_ {};
|
std::shared_mutex atlasMutex_ {};
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ bool TextureAtlas::CacheTexture(const std::string& name,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureAtlas::BuildAtlas(size_t width, size_t height)
|
void TextureAtlas::BuildAtlas(std::size_t width, std::size_t height)
|
||||||
{
|
{
|
||||||
logger_->debug("Building {}x{} texture atlas", width, height);
|
logger_->debug("Building {}x{} texture atlas", width, height);
|
||||||
|
|
||||||
|
|
@ -105,11 +105,13 @@ void TextureAtlas::BuildAtlas(size_t width, size_t height)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<
|
typedef std::vector<std::pair<
|
||||||
std::string,
|
std::string,
|
||||||
std::variant<boost::gil::rgba8_image_t, boost::gil::rgba8_image_t*>>>
|
std::variant<boost::gil::rgba8_image_t, boost::gil::rgba8_image_t*>>>
|
||||||
images;
|
ImageVector;
|
||||||
std::vector<stbrp_rect> stbrpRects;
|
|
||||||
|
ImageVector images {};
|
||||||
|
std::vector<stbrp_rect> stbrpRects {};
|
||||||
|
|
||||||
// Load images
|
// Load images
|
||||||
{
|
{
|
||||||
|
|
@ -171,13 +173,30 @@ void TextureAtlas::BuildAtlas(size_t width, size_t height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pack images
|
// GL_MAX_ARRAY_TEXTURE_LAYERS is guaranteed to be at least 256 in OpenGL 3.3
|
||||||
{
|
constexpr std::size_t kMaxLayers = 256u;
|
||||||
logger_->trace("Packing {} images", images.size());
|
|
||||||
|
const float xStep = 1.0f / width;
|
||||||
|
const float yStep = 1.0f / height;
|
||||||
|
const float xMin = xStep * 0.5f;
|
||||||
|
const float yMin = yStep * 0.5f;
|
||||||
|
|
||||||
// Optimal number of nodes = width
|
// Optimal number of nodes = width
|
||||||
stbrp_context stbrpContext;
|
stbrp_context stbrpContext;
|
||||||
std::vector<stbrp_node> stbrpNodes(width);
|
std::vector<stbrp_node> stbrpNodes(width);
|
||||||
|
ImageVector unpackedImages {};
|
||||||
|
std::vector<stbrp_rect> unpackedRects {};
|
||||||
|
|
||||||
|
std::vector<boost::gil::rgba8_image_t> newAtlasArray {};
|
||||||
|
std::unordered_map<std::string, TextureAttributes> newAtlasMap {};
|
||||||
|
|
||||||
|
for (std::size_t layer = 0; layer < kMaxLayers; ++layer)
|
||||||
|
{
|
||||||
|
logger_->trace("Processing layer {}", layer);
|
||||||
|
|
||||||
|
// Pack images
|
||||||
|
{
|
||||||
|
logger_->trace("Packing {} images", images.size());
|
||||||
|
|
||||||
stbrp_init_target(&stbrpContext,
|
stbrp_init_target(&stbrpContext,
|
||||||
static_cast<int>(width),
|
static_cast<int>(width),
|
||||||
|
|
@ -186,31 +205,22 @@ void TextureAtlas::BuildAtlas(size_t width, size_t height)
|
||||||
static_cast<int>(stbrpNodes.size()));
|
static_cast<int>(stbrpNodes.size()));
|
||||||
|
|
||||||
// Pack loaded textures
|
// Pack loaded textures
|
||||||
stbrp_pack_rects(
|
stbrp_pack_rects(&stbrpContext,
|
||||||
&stbrpContext, stbrpRects.data(), static_cast<int>(stbrpRects.size()));
|
stbrpRects.data(),
|
||||||
|
static_cast<int>(stbrpRects.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock atlas
|
|
||||||
std::unique_lock lock(p->atlasMutex_);
|
|
||||||
|
|
||||||
// Clear index
|
|
||||||
p->atlasMap_.clear();
|
|
||||||
|
|
||||||
// Clear atlas
|
// Clear atlas
|
||||||
p->atlas_.recreate(width, height);
|
auto& atlas =
|
||||||
boost::gil::rgba8_view_t atlasView = boost::gil::view(p->atlas_);
|
newAtlasArray.emplace_back(boost::gil::rgba8_image_t(width, height));
|
||||||
|
boost::gil::rgba8_view_t atlasView = boost::gil::view(atlas);
|
||||||
boost::gil::fill_pixels(atlasView,
|
boost::gil::fill_pixels(atlasView,
|
||||||
boost::gil::rgba8_pixel_t {255, 0, 255, 255});
|
boost::gil::rgba8_pixel_t {255, 0, 255, 255});
|
||||||
|
|
||||||
// Populate atlas
|
// Populate atlas
|
||||||
logger_->trace("Populating atlas");
|
logger_->trace("Populating atlas");
|
||||||
|
|
||||||
const float xStep = 1.0f / width;
|
for (std::size_t i = 0; i < images.size(); ++i)
|
||||||
const float yStep = 1.0f / height;
|
|
||||||
const float xMin = xStep * 0.5f;
|
|
||||||
const float yMin = yStep * 0.5f;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < images.size(); i++)
|
|
||||||
{
|
{
|
||||||
// If the image was packed successfully
|
// If the image was packed successfully
|
||||||
if (stbrpRects[i].was_packed != 0)
|
if (stbrpRects[i].was_packed != 0)
|
||||||
|
|
@ -252,10 +262,11 @@ void TextureAtlas::BuildAtlas(size_t width, size_t height)
|
||||||
const float tBottom =
|
const float tBottom =
|
||||||
tTop + static_cast<float>(imageView.height() - 1) / height;
|
tTop + static_cast<float>(imageView.height() - 1) / height;
|
||||||
|
|
||||||
p->atlasMap_.emplace(
|
newAtlasMap.emplace(
|
||||||
std::piecewise_construct,
|
std::piecewise_construct,
|
||||||
std::forward_as_tuple(images[i].first),
|
std::forward_as_tuple(images[i].first),
|
||||||
std::forward_as_tuple(
|
std::forward_as_tuple(
|
||||||
|
layer,
|
||||||
boost::gil::point_t {x, y},
|
boost::gil::point_t {x, y},
|
||||||
boost::gil::point_t {imageView.width(), imageView.height()},
|
boost::gil::point_t {imageView.width(), imageView.height()},
|
||||||
sLeft,
|
sLeft,
|
||||||
|
|
@ -265,10 +276,40 @@ void TextureAtlas::BuildAtlas(size_t width, size_t height)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger_->warn("Unable to pack texture: {}", images[i].first);
|
unpackedImages.push_back(std::move(images[i]));
|
||||||
|
unpackedRects.push_back(stbrpRects[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (unpackedImages.empty())
|
||||||
|
{
|
||||||
|
// All images have been packed into the texture atlas
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (layer == kMaxLayers - 1u)
|
||||||
|
{
|
||||||
|
// Some images were unable to be packed into the texture atlas
|
||||||
|
for (auto& image : unpackedImages)
|
||||||
|
{
|
||||||
|
logger_->warn("Unable to pack texture: {}", image.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Swap in unpacked images for processing the next atlas layer
|
||||||
|
images.swap(unpackedImages);
|
||||||
|
stbrpRects.swap(unpackedRects);
|
||||||
|
unpackedImages.clear();
|
||||||
|
unpackedRects.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock atlas
|
||||||
|
std::unique_lock lock(p->atlasMutex_);
|
||||||
|
|
||||||
|
p->atlasArray_.swap(newAtlasArray);
|
||||||
|
p->atlasMap_.swap(newAtlasMap);
|
||||||
|
|
||||||
// Mark the need to buffer the atlas
|
// Mark the need to buffer the atlas
|
||||||
++p->buildCount_;
|
++p->buildCount_;
|
||||||
}
|
}
|
||||||
|
|
@ -279,19 +320,28 @@ GLuint TextureAtlas::BufferAtlas(gl::OpenGLFunctions& gl)
|
||||||
|
|
||||||
std::shared_lock lock(p->atlasMutex_);
|
std::shared_lock lock(p->atlasMutex_);
|
||||||
|
|
||||||
if (p->atlas_.width() > 0u && p->atlas_.height() > 0u)
|
if (p->atlasArray_.size() > 0u && p->atlasArray_[0].width() > 0 &&
|
||||||
|
p->atlasArray_[0].height() > 0)
|
||||||
{
|
{
|
||||||
boost::gil::rgba8_view_t view = boost::gil::view(p->atlas_);
|
const std::size_t numLayers = p->atlasArray_.size();
|
||||||
std::vector<boost::gil::rgba8_pixel_t> pixelData(view.width() *
|
const std::size_t width = p->atlasArray_[0].width();
|
||||||
view.height());
|
const std::size_t height = p->atlasArray_[0].height();
|
||||||
|
const std::size_t layerSize = width * height;
|
||||||
|
|
||||||
|
std::vector<boost::gil::rgba8_pixel_t> pixelData {layerSize * numLayers};
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < numLayers; ++i)
|
||||||
|
{
|
||||||
|
boost::gil::rgba8_view_t view = boost::gil::view(p->atlasArray_[i]);
|
||||||
|
|
||||||
boost::gil::copy_pixels(
|
boost::gil::copy_pixels(
|
||||||
view,
|
view,
|
||||||
boost::gil::interleaved_view(view.width(),
|
boost::gil::interleaved_view(view.width(),
|
||||||
view.height(),
|
view.height(),
|
||||||
pixelData.data(),
|
pixelData.data() + (i * layerSize),
|
||||||
view.width() *
|
view.width() *
|
||||||
sizeof(boost::gil::rgba8_pixel_t)));
|
sizeof(boost::gil::rgba8_pixel_t)));
|
||||||
|
}
|
||||||
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
|
||||||
|
|
@ -308,9 +358,9 @@ GLuint TextureAtlas::BufferAtlas(gl::OpenGLFunctions& gl)
|
||||||
gl.glTexImage3D(GL_TEXTURE_2D_ARRAY,
|
gl.glTexImage3D(GL_TEXTURE_2D_ARRAY,
|
||||||
0,
|
0,
|
||||||
GL_RGBA,
|
GL_RGBA,
|
||||||
view.width(),
|
static_cast<GLsizei>(width),
|
||||||
view.height(),
|
static_cast<GLsizei>(height),
|
||||||
1u,
|
static_cast<GLsizei>(numLayers),
|
||||||
0,
|
0,
|
||||||
GL_RGBA,
|
GL_RGBA,
|
||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
|
|
@ -424,6 +474,11 @@ TextureAtlas::Impl::LoadImage(const std::string& imagePath)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::gil::write_view(
|
||||||
|
fmt::format("gil-{}.png", url.fileName().toStdString()),
|
||||||
|
image._view,
|
||||||
|
boost::gil::png_tag());
|
||||||
|
|
||||||
stbi_image_free(pixelData);
|
stbi_image_free(pixelData);
|
||||||
}
|
}
|
||||||
else if (response.status_code == 0)
|
else if (response.status_code == 0)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ struct TextureAttributes
|
||||||
{
|
{
|
||||||
TextureAttributes() :
|
TextureAttributes() :
|
||||||
valid_ {false},
|
valid_ {false},
|
||||||
|
layerId_ {},
|
||||||
position_ {},
|
position_ {},
|
||||||
size_ {},
|
size_ {},
|
||||||
sLeft_ {},
|
sLeft_ {},
|
||||||
|
|
@ -27,13 +28,15 @@ struct TextureAttributes
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureAttributes(boost::gil::point_t position,
|
TextureAttributes(std::size_t layerId,
|
||||||
|
boost::gil::point_t position,
|
||||||
boost::gil::point_t size,
|
boost::gil::point_t size,
|
||||||
float sLeft,
|
float sLeft,
|
||||||
float sRight,
|
float sRight,
|
||||||
float tTop,
|
float tTop,
|
||||||
float tBottom) :
|
float tBottom) :
|
||||||
valid_ {true},
|
valid_ {true},
|
||||||
|
layerId_ {layerId},
|
||||||
position_ {position},
|
position_ {position},
|
||||||
size_ {size},
|
size_ {size},
|
||||||
sLeft_ {sLeft},
|
sLeft_ {sLeft},
|
||||||
|
|
@ -44,6 +47,7 @@ struct TextureAttributes
|
||||||
}
|
}
|
||||||
|
|
||||||
bool valid_;
|
bool valid_;
|
||||||
|
std::size_t layerId_;
|
||||||
boost::gil::point_t position_;
|
boost::gil::point_t position_;
|
||||||
boost::gil::point_t size_;
|
boost::gil::point_t size_;
|
||||||
float sLeft_;
|
float sLeft_;
|
||||||
|
|
@ -70,7 +74,7 @@ public:
|
||||||
|
|
||||||
void RegisterTexture(const std::string& name, const std::string& path);
|
void RegisterTexture(const std::string& name, const std::string& path);
|
||||||
bool CacheTexture(const std::string& name, const std::string& path);
|
bool CacheTexture(const std::string& name, const std::string& path);
|
||||||
void BuildAtlas(size_t width, size_t height);
|
void BuildAtlas(std::size_t width, std::size_t height);
|
||||||
GLuint BufferAtlas(gl::OpenGLFunctions& gl);
|
GLuint BufferAtlas(gl::OpenGLFunctions& gl);
|
||||||
|
|
||||||
TextureAttributes GetTextureAttributes(const std::string& name);
|
TextureAttributes GetTextureAttributes(const std::string& name);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue