Add text outlines!

This commit is contained in:
Lynix
2019-04-16 01:46:26 +02:00
parent 8a8c233840
commit 79b0bd644c
12 changed files with 332 additions and 166 deletions

View File

@@ -30,13 +30,13 @@ namespace Nz
{
for (auto& pair : m_renderInfos)
{
Texture* overlay = pair.first;
const RenderKey& key = pair.first;
RenderIndices& indices = pair.second;
if (indices.count > 0)
{
const VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast<const VertexStruct_XYZ_Color_UV*>(instanceData.data.data());
renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(), &vertices[indices.first * 4], indices.count, scissorRect, overlay);
renderQueue->AddSprites(instanceData.renderOrder + key.renderOrder, GetMaterial(), &vertices[indices.first * 4], indices.count, scissorRect, key.texture);
}
}
}
@@ -101,15 +101,16 @@ namespace Nz
}
std::size_t glyphCount = drawer.GetGlyphCount();
m_localVertices.resize(glyphCount * 4);
// Reset glyph count for every texture to zero
for (auto& pair : m_renderInfos)
pair.second.count = 0;
// Count glyph count for each texture
Texture* lastTexture = nullptr;
RenderKey lastRenderKey { nullptr, 0 };
unsigned int* count = nullptr;
std::size_t visibleGlyphCount = 0;
for (std::size_t i = 0; i < glyphCount; ++i)
{
const AbstractTextDrawer::Glyph& glyph = drawer.GetGlyph(i);
@@ -117,19 +118,23 @@ namespace Nz
continue;
Texture* texture = static_cast<Texture*>(glyph.atlas);
if (lastTexture != texture)
RenderKey renderKey{ texture, glyph.renderOrder };
if (lastRenderKey != renderKey)
{
auto it = m_renderInfos.find(texture);
auto it = m_renderInfos.find(renderKey);
if (it == m_renderInfos.end())
it = m_renderInfos.insert(std::make_pair(texture, RenderIndices{0U, 0U})).first;
it = m_renderInfos.insert(std::make_pair(renderKey, RenderIndices{0U, 0U})).first;
count = &it->second.count;
lastTexture = texture;
lastRenderKey = renderKey;
}
(*count)++;
visibleGlyphCount++;
}
m_localVertices.resize(visibleGlyphCount * 4);
// Attributes indices and reinitialize glyph count to zero to use it as a counter in the next loop
// This is because the 1st glyph can use texture A, the 2nd glyph can use texture B and the 3th glyph C can use texture A again
// so we need a counter to know where to write informations
@@ -140,7 +145,7 @@ namespace Nz
{
RenderIndices& indices = infoIt->second;
if (indices.count == 0)
m_renderInfos.erase(infoIt++); //< No glyph uses this texture, remove from indices
infoIt = m_renderInfos.erase(infoIt); //< No glyph uses this texture, remove from indices
else
{
indices.first = index;
@@ -151,7 +156,7 @@ namespace Nz
}
}
lastTexture = nullptr;
lastRenderKey = { nullptr, 0 };
RenderIndices* indices = nullptr;
for (unsigned int i = 0; i < glyphCount; ++i)
{
@@ -160,10 +165,11 @@ namespace Nz
continue;
Texture* texture = static_cast<Texture*>(glyph.atlas);
if (lastTexture != texture)
RenderKey renderKey{ texture, glyph.renderOrder };
if (lastRenderKey != renderKey)
{
indices = &m_renderInfos[texture]; //< We changed texture, adjust the pointer
lastTexture = texture;
indices = &m_renderInfos[renderKey]; //< We changed texture, adjust the pointer
lastRenderKey = renderKey;
}
// First, compute the uv coordinates from our atlas rect
@@ -185,9 +191,10 @@ namespace Nz
for (unsigned int j = 0; j < 4; ++j)
{
// Remember that indices->count is a counter here, not a count value
m_localVertices[indices->count * 4 + j].color = glyph.color;
m_localVertices[indices->count * 4 + j].position.Set(glyph.corners[j]);
m_localVertices[indices->count * 4 + j].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j]));
std::size_t offset = (indices->first + indices->count) * 4 + j;
m_localVertices[offset].color = glyph.color;
m_localVertices[offset].position.Set(glyph.corners[j]);
m_localVertices[offset].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j]));
}
// Increment the counter, go to next glyph
@@ -236,13 +243,12 @@ namespace Nz
}
/*!
* \brief Handle the invalidation of an atlas layer
* \brief Handle the size change of an atlas layer
*
* \param atlas Atlas being invalidated
* \param oldLayer Pointer to the previous layer
* \param newLayer Pointer to the new layer
*/
void TextSprite::OnAtlasLayerChange(const AbstractAtlas* atlas, AbstractImage* oldLayer, AbstractImage* newLayer)
{
NazaraUnused(atlas);
@@ -255,33 +261,38 @@ namespace Nz
}
#endif
if (!oldLayer)
return;
assert(newLayer);
// The texture of an atlas have just been recreated (size change)
// we have to adjust the coordinates of the texture and the rendering texture
Texture* oldTexture = static_cast<Texture*>(oldLayer);
Texture* newTexture = static_cast<Texture*>(newLayer);
// It is possible that we don't use the texture (the atlas warning us for each of its layers)
auto it = m_renderInfos.find(oldTexture);
if (it != m_renderInfos.end())
Vector2ui oldSize(oldTexture->GetSize());
Vector2ui newSize(newTexture->GetSize());
Vector2f scale = Vector2f(oldSize) / Vector2f(newSize); // ratio of the old one to the new one
// It is possible we actually use that texture multiple times, check them all
for (auto it = m_renderInfos.begin(); it != m_renderInfos.end(); ++it)
{
// We indeed use this texture, we have to update its coordinates
RenderIndices indices = std::move(it->second);
const RenderKey& renderKey = it->first;
const RenderIndices& indices = it->second;
Vector2ui oldSize(oldTexture->GetSize());
Vector2ui newSize(newTexture->GetSize());
Vector2f scale = Vector2f(oldSize) / Vector2f(newSize); // ratio of the old one to the new one
// Now we will iterate through each coordinates of the concerned texture to multiply them by the ratio
SparsePtr<Vector2f> texCoordPtr(&m_localVertices[indices.first].uv, sizeof(VertexStruct_XYZ_Color_UV));
// Adjust texture coordinates by size ratio
SparsePtr<Vector2f> texCoordPtr(&m_localVertices[indices.first].uv, sizeof(VertexStruct_XY_Color_UV));
for (unsigned int i = 0; i < indices.count; ++i)
{
for (unsigned int j = 0; j < 4; ++j)
m_localVertices[i*4 + j].uv *= scale;
m_localVertices[i * 4 + j].uv *= scale;
}
// We get rid off the old texture and we set the new one at the place (same for indices)
// Erase and re-insert with the new texture handle
m_renderInfos.erase(it);
m_renderInfos.insert(std::make_pair(newTexture, std::move(indices)));
m_renderInfos.insert(std::make_pair(RenderKey{ newTexture, renderKey.renderOrder }, indices));
it = m_renderInfos.begin(); //< std::unordered_map::insert may invalidate all iterators, start from the beginning...
}
}