Optimized text rendering
parent
aacc2d0596
commit
0d612b9928
|
@ -77,6 +77,7 @@ public:
|
||||||
virtual void DrawPrimitive(PrimitiveType type, int count, const Vertex2D* vertices) = 0;
|
virtual void DrawPrimitive(PrimitiveType type, int count, const Vertex2D* vertices) = 0;
|
||||||
|
|
||||||
virtual Vertex2D* BeginPrimitive(PrimitiveType type, int count) = 0;
|
virtual Vertex2D* BeginPrimitive(PrimitiveType type, int count) = 0;
|
||||||
|
virtual Vertex2D* BeginPrimitives(PrimitiveType type, int drawCount, const int* counts) = 0;
|
||||||
virtual bool EndPrimitive() = 0;
|
virtual bool EndPrimitive() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -136,26 +136,23 @@ public:
|
||||||
renderer->SetTexture(Texture{ m_texID });
|
renderer->SetTexture(Texture{ m_texID });
|
||||||
renderer->SetTransparency(m_transparency);
|
renderer->SetTransparency(m_transparency);
|
||||||
|
|
||||||
assert(m_firsts.size() == m_counts.size());
|
if (m_counts.size() < m_quads.size())
|
||||||
if (m_firsts.size() < m_quads.size())
|
|
||||||
{
|
{
|
||||||
// m_firsts needs to look like { 0, 4, 8, 12, ... }
|
|
||||||
// m_counts needs to look like { 4, 4, 4, 4, ... }
|
|
||||||
// and both need to be the same length as m_quads
|
|
||||||
m_counts.resize(m_quads.size(), 4);
|
m_counts.resize(m_quads.size(), 4);
|
||||||
std::size_t begin = m_firsts.size();
|
|
||||||
m_firsts.resize(m_quads.size());
|
|
||||||
for (std::size_t i = begin; i < m_firsts.size(); ++i)
|
|
||||||
{
|
|
||||||
m_firsts[i] = static_cast<int>(4 * i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto vertices = renderer->BeginPrimitives(PrimitiveType::TRIANGLE_STRIP, m_quads.size(), m_counts.data());
|
||||||
|
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
for (const auto& quad : m_quads)
|
for (const auto& quad : m_quads)
|
||||||
{
|
{
|
||||||
renderer->DrawPrimitive(PrimitiveType::TRIANGLE_STRIP, 4, quad.vertices);
|
std::copy_n(quad.vertices, 4, vertices + offset);
|
||||||
|
offset += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderer->EndPrimitive();
|
||||||
|
|
||||||
m_engine.AddStatisticTriangle(static_cast<int>(m_quads.size() * 2));
|
m_engine.AddStatisticTriangle(static_cast<int>(m_quads.size() * 2));
|
||||||
m_quads.clear();
|
m_quads.clear();
|
||||||
}
|
}
|
||||||
|
@ -164,7 +161,6 @@ private:
|
||||||
|
|
||||||
struct Quad { Vertex2D vertices[4]; };
|
struct Quad { Vertex2D vertices[4]; };
|
||||||
std::vector<Quad> m_quads;
|
std::vector<Quad> m_quads;
|
||||||
std::vector<int> m_firsts;
|
|
||||||
std::vector<int> m_counts;
|
std::vector<int> m_counts;
|
||||||
|
|
||||||
Color m_color;
|
Color m_color;
|
||||||
|
@ -1050,18 +1046,14 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, glm::iv
|
||||||
|
|
||||||
Gfx::IntColor col = Gfx::ColorToIntColor(color);
|
Gfx::IntColor col = Gfx::ColorToIntColor(color);
|
||||||
|
|
||||||
auto renderer = m_device->GetUIRenderer();
|
Gfx::Vertex2D vertices[4];
|
||||||
renderer->SetTransparency(TransparencyMode::WHITE);
|
|
||||||
renderer->SetTexture(Texture{ texID });
|
|
||||||
auto vertices = renderer->BeginPrimitive(PrimitiveType::TRIANGLE_STRIP, 4);
|
|
||||||
|
|
||||||
vertices[0] = { { p1.x, p2.y }, { uv1.x, uv2.y }, col };
|
vertices[0] = { { p1.x, p2.y }, { uv1.x, uv2.y }, col };
|
||||||
vertices[1] = { { p1.x, p1.y }, { uv1.x, uv1.y }, col };
|
vertices[1] = { { p1.x, p1.y }, { uv1.x, uv1.y }, col };
|
||||||
vertices[2] = { { p2.x, p2.y }, { uv2.x, uv2.y }, col };
|
vertices[2] = { { p2.x, p2.y }, { uv2.x, uv2.y }, col };
|
||||||
vertices[3] = { { p2.x, p1.y }, { uv2.x, uv1.y }, col };
|
vertices[3] = { { p2.x, p1.y }, { uv2.x, uv1.y }, col };
|
||||||
|
|
||||||
//m_quadBatch->Add(quad, texID, TransparencyMode::WHITE, color);
|
m_quadBatch->Add(vertices, texID, TransparencyMode::WHITE, color);
|
||||||
renderer->EndPrimitive();
|
|
||||||
|
|
||||||
pos.x += width;
|
pos.x += width;
|
||||||
}
|
}
|
||||||
|
@ -1092,18 +1084,14 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, glm::iv
|
||||||
|
|
||||||
Gfx::IntColor col = Gfx::ColorToIntColor(color);
|
Gfx::IntColor col = Gfx::ColorToIntColor(color);
|
||||||
|
|
||||||
auto renderer = m_device->GetUIRenderer();
|
Gfx::Vertex2D vertices[4];
|
||||||
renderer->SetTransparency(TransparencyMode::ALPHA);
|
|
||||||
renderer->SetTexture(Texture{ tex.id });
|
|
||||||
auto vertices = renderer->BeginPrimitive(PrimitiveType::TRIANGLE_STRIP, 4);
|
|
||||||
|
|
||||||
vertices[0] = { { p1.x, p2.y }, { texCoord1.x, texCoord2.y }, col };
|
vertices[0] = { { p1.x, p2.y }, { texCoord1.x, texCoord2.y }, col };
|
||||||
vertices[1] = { { p1.x, p1.y }, { texCoord1.x, texCoord1.y }, col };
|
vertices[1] = { { p1.x, p1.y }, { texCoord1.x, texCoord1.y }, col };
|
||||||
vertices[2] = { { p2.x, p2.y }, { texCoord2.x, texCoord2.y }, col };
|
vertices[2] = { { p2.x, p2.y }, { texCoord2.x, texCoord2.y }, col };
|
||||||
vertices[3] = { { p2.x, p1.y }, { texCoord2.x, texCoord1.y }, col };
|
vertices[3] = { { p2.x, p1.y }, { texCoord2.x, texCoord1.y }, col };
|
||||||
|
|
||||||
//m_quadBatch->Add(quad, tex.id, TransparencyMode::ALPHA, color);
|
m_quadBatch->Add(vertices, tex.id, TransparencyMode::ALPHA, color);
|
||||||
renderer->EndPrimitive();
|
|
||||||
|
|
||||||
pos.x += tex.charSize.x * width;
|
pos.x += tex.charSize.x * width;
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,18 +147,30 @@ void CGL33UIRenderer::DrawPrimitive(PrimitiveType type, int count, const Vertex2
|
||||||
}
|
}
|
||||||
|
|
||||||
Vertex2D* CGL33UIRenderer::BeginPrimitive(PrimitiveType type, int count)
|
Vertex2D* CGL33UIRenderer::BeginPrimitive(PrimitiveType type, int count)
|
||||||
|
{
|
||||||
|
return BeginPrimitives(type, 1, &count);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex2D* CGL33UIRenderer::BeginPrimitives(PrimitiveType type, int drawCount, const int* counts)
|
||||||
{
|
{
|
||||||
glBindVertexArray(m_bufferVAO);
|
glBindVertexArray(m_bufferVAO);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, m_bufferVBO);
|
glBindBuffer(GL_ARRAY_BUFFER, m_bufferVBO);
|
||||||
|
|
||||||
GLuint total = m_offset + count;
|
m_currentCount = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < drawCount; i++)
|
||||||
|
{
|
||||||
|
m_currentCount += counts[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint total = m_bufferOffset + m_currentCount;
|
||||||
|
|
||||||
// Buffer full, orphan
|
// Buffer full, orphan
|
||||||
if (total >= m_bufferCapacity)
|
if (total >= m_bufferCapacity)
|
||||||
{
|
{
|
||||||
glBufferData(GL_ARRAY_BUFFER, m_bufferCapacity * sizeof(Vertex2D), nullptr, GL_STREAM_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, m_bufferCapacity * sizeof(Vertex2D), nullptr, GL_STREAM_DRAW);
|
||||||
|
|
||||||
m_offset = 0;
|
m_bufferOffset = 0;
|
||||||
|
|
||||||
// Respecify vertex attributes
|
// Respecify vertex attributes
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
|
@ -174,20 +186,33 @@ Vertex2D* CGL33UIRenderer::BeginPrimitive(PrimitiveType type, int count)
|
||||||
reinterpret_cast<void*>(offsetof(Vertex2D, color)));
|
reinterpret_cast<void*>(offsetof(Vertex2D, color)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_first.resize(drawCount);
|
||||||
|
m_count.resize(drawCount);
|
||||||
|
|
||||||
|
GLsizei currentOffset = m_bufferOffset;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < drawCount; i++)
|
||||||
|
{
|
||||||
|
m_first[i] = currentOffset;
|
||||||
|
m_count[i] = counts[i];
|
||||||
|
|
||||||
|
currentOffset += counts[i];
|
||||||
|
}
|
||||||
|
|
||||||
auto ptr = glMapBufferRange(GL_ARRAY_BUFFER,
|
auto ptr = glMapBufferRange(GL_ARRAY_BUFFER,
|
||||||
m_offset * sizeof(Vertex2D),
|
m_bufferOffset * sizeof(Vertex2D),
|
||||||
count * sizeof(Vertex2D),
|
m_currentCount * sizeof(Vertex2D),
|
||||||
GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
|
GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
|
||||||
|
|
||||||
m_mapped = true;
|
m_mapped = true;
|
||||||
m_type = type;
|
m_type = type;
|
||||||
m_count = count;
|
m_drawCount = drawCount;
|
||||||
|
|
||||||
// Mapping failed, use backup buffer
|
// Mapping failed, use backup buffer
|
||||||
if (ptr == nullptr)
|
if (ptr == nullptr)
|
||||||
{
|
{
|
||||||
m_backup = true;
|
m_backup = true;
|
||||||
m_buffer.resize(count);
|
m_buffer.resize(m_currentCount);
|
||||||
|
|
||||||
return m_buffer.data();
|
return m_buffer.data();
|
||||||
}
|
}
|
||||||
|
@ -203,7 +228,10 @@ bool CGL33UIRenderer::EndPrimitive()
|
||||||
|
|
||||||
if (m_backup)
|
if (m_backup)
|
||||||
{
|
{
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, m_offset * sizeof(Vertex2D), m_count * sizeof(Vertex2D), m_buffer.data());
|
glBufferSubData(GL_ARRAY_BUFFER,
|
||||||
|
m_bufferOffset * sizeof(Vertex2D),
|
||||||
|
m_currentCount * sizeof(Vertex2D),
|
||||||
|
m_buffer.data());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -218,9 +246,12 @@ bool CGL33UIRenderer::EndPrimitive()
|
||||||
|
|
||||||
m_device->SetDepthTest(false);
|
m_device->SetDepthTest(false);
|
||||||
|
|
||||||
glDrawArrays(TranslateGfxPrimitive(m_type), m_offset, m_count);
|
if (m_drawCount == 1)
|
||||||
|
glDrawArrays(TranslateGfxPrimitive(m_type), m_first.front(), m_count.front());
|
||||||
|
else
|
||||||
|
glMultiDrawArrays(TranslateGfxPrimitive(m_type), m_first.data(), m_count.data(), m_drawCount);
|
||||||
|
|
||||||
m_offset += m_count;
|
m_bufferOffset += m_currentCount;
|
||||||
|
|
||||||
m_mapped = false;
|
m_mapped = false;
|
||||||
m_backup = false;
|
m_backup = false;
|
||||||
|
|
|
@ -51,6 +51,7 @@ public:
|
||||||
virtual void DrawPrimitive(PrimitiveType type, int count, const Vertex2D* vertices) override;
|
virtual void DrawPrimitive(PrimitiveType type, int count, const Vertex2D* vertices) override;
|
||||||
|
|
||||||
virtual Vertex2D* BeginPrimitive(PrimitiveType type, int count) override;
|
virtual Vertex2D* BeginPrimitive(PrimitiveType type, int count) override;
|
||||||
|
virtual Vertex2D* BeginPrimitives(PrimitiveType type, int drawCount, const int* counts) override;
|
||||||
virtual bool EndPrimitive() override;
|
virtual bool EndPrimitive() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -78,12 +79,22 @@ private:
|
||||||
GLuint m_bufferVAO = 0;
|
GLuint m_bufferVAO = 0;
|
||||||
// VBO capacity
|
// VBO capacity
|
||||||
GLsizei m_bufferCapacity = 128 * 1024;
|
GLsizei m_bufferCapacity = 128 * 1024;
|
||||||
|
// Buffer offset
|
||||||
|
GLsizei m_bufferOffset = 0;
|
||||||
|
|
||||||
// Buffer mapping state
|
// Buffer mapping state
|
||||||
PrimitiveType m_type = {};
|
PrimitiveType m_type = {};
|
||||||
GLuint m_offset = 0;
|
// Number of drawn primitives
|
||||||
GLuint m_count = 0;
|
GLuint m_drawCount = 0;
|
||||||
|
// Total count of drawn vertices
|
||||||
|
GLuint m_currentCount = 0;
|
||||||
|
// Starting offset for each drawn primitive
|
||||||
|
std::vector<GLint> m_first;
|
||||||
|
// Numbers of vertices for each drawn primitive
|
||||||
|
std::vector<GLsizei> m_count;
|
||||||
|
// True means currently drawing
|
||||||
bool m_mapped = false;
|
bool m_mapped = false;
|
||||||
|
// True means mapping failed, using auxiliary buffer
|
||||||
bool m_backup = false;
|
bool m_backup = false;
|
||||||
|
|
||||||
// Buffered vertex data
|
// Buffered vertex data
|
||||||
|
|
Loading…
Reference in New Issue