diff --git a/src/graphics/core/renderers.h b/src/graphics/core/renderers.h index 7f46d5c6..98caddc0 100644 --- a/src/graphics/core/renderers.h +++ b/src/graphics/core/renderers.h @@ -77,6 +77,7 @@ public: virtual void DrawPrimitive(PrimitiveType type, int count, const Vertex2D* vertices) = 0; virtual Vertex2D* BeginPrimitive(PrimitiveType type, int count) = 0; + virtual Vertex2D* BeginPrimitives(PrimitiveType type, int drawCount, const int* counts) = 0; virtual bool EndPrimitive() = 0; }; diff --git a/src/graphics/engine/text.cpp b/src/graphics/engine/text.cpp index 3c8fe378..02bb3150 100644 --- a/src/graphics/engine/text.cpp +++ b/src/graphics/engine/text.cpp @@ -136,26 +136,23 @@ public: renderer->SetTexture(Texture{ m_texID }); renderer->SetTransparency(m_transparency); - assert(m_firsts.size() == m_counts.size()); - if (m_firsts.size() < m_quads.size()) + if (m_counts.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); - 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(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) { - 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(m_quads.size() * 2)); m_quads.clear(); } @@ -164,7 +161,6 @@ private: struct Quad { Vertex2D vertices[4]; }; std::vector m_quads; - std::vector m_firsts; std::vector m_counts; Color m_color; @@ -1050,18 +1046,14 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, glm::iv Gfx::IntColor col = Gfx::ColorToIntColor(color); - auto renderer = m_device->GetUIRenderer(); - renderer->SetTransparency(TransparencyMode::WHITE); - renderer->SetTexture(Texture{ texID }); - auto vertices = renderer->BeginPrimitive(PrimitiveType::TRIANGLE_STRIP, 4); + Gfx::Vertex2D vertices[4]; vertices[0] = { { p1.x, p2.y }, { uv1.x, uv2.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[3] = { { p2.x, p1.y }, { uv2.x, uv1.y }, col }; - //m_quadBatch->Add(quad, texID, TransparencyMode::WHITE, color); - renderer->EndPrimitive(); + m_quadBatch->Add(vertices, texID, TransparencyMode::WHITE, color); pos.x += width; } @@ -1092,18 +1084,14 @@ void CText::DrawCharAndAdjustPos(UTF8Char ch, FontType font, float size, glm::iv Gfx::IntColor col = Gfx::ColorToIntColor(color); - auto renderer = m_device->GetUIRenderer(); - renderer->SetTransparency(TransparencyMode::ALPHA); - renderer->SetTexture(Texture{ tex.id }); - auto vertices = renderer->BeginPrimitive(PrimitiveType::TRIANGLE_STRIP, 4); + Gfx::Vertex2D vertices[4]; vertices[0] = { { p1.x, p2.y }, { texCoord1.x, texCoord2.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[3] = { { p2.x, p1.y }, { texCoord2.x, texCoord1.y }, col }; - //m_quadBatch->Add(quad, tex.id, TransparencyMode::ALPHA, color); - renderer->EndPrimitive(); + m_quadBatch->Add(vertices, tex.id, TransparencyMode::ALPHA, color); pos.x += tex.charSize.x * width; } diff --git a/src/graphics/opengl/gl33renderers.cpp b/src/graphics/opengl/gl33renderers.cpp index c81f1593..21000128 100644 --- a/src/graphics/opengl/gl33renderers.cpp +++ b/src/graphics/opengl/gl33renderers.cpp @@ -147,18 +147,30 @@ void CGL33UIRenderer::DrawPrimitive(PrimitiveType type, int count, const Vertex2 } 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); 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 if (total >= m_bufferCapacity) { glBufferData(GL_ARRAY_BUFFER, m_bufferCapacity * sizeof(Vertex2D), nullptr, GL_STREAM_DRAW); - m_offset = 0; + m_bufferOffset = 0; // Respecify vertex attributes glEnableVertexAttribArray(0); @@ -174,20 +186,33 @@ Vertex2D* CGL33UIRenderer::BeginPrimitive(PrimitiveType type, int count) reinterpret_cast(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, - m_offset * sizeof(Vertex2D), - count * sizeof(Vertex2D), + m_bufferOffset * sizeof(Vertex2D), + m_currentCount * sizeof(Vertex2D), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); m_mapped = true; m_type = type; - m_count = count; + m_drawCount = drawCount; // Mapping failed, use backup buffer if (ptr == nullptr) { m_backup = true; - m_buffer.resize(count); + m_buffer.resize(m_currentCount); return m_buffer.data(); } @@ -203,7 +228,10 @@ bool CGL33UIRenderer::EndPrimitive() 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 { @@ -218,9 +246,12 @@ bool CGL33UIRenderer::EndPrimitive() 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_backup = false; diff --git a/src/graphics/opengl/gl33renderers.h b/src/graphics/opengl/gl33renderers.h index 3a936d89..952a5119 100644 --- a/src/graphics/opengl/gl33renderers.h +++ b/src/graphics/opengl/gl33renderers.h @@ -51,6 +51,7 @@ public: virtual void DrawPrimitive(PrimitiveType type, int count, const Vertex2D* vertices) override; virtual Vertex2D* BeginPrimitive(PrimitiveType type, int count) override; + virtual Vertex2D* BeginPrimitives(PrimitiveType type, int drawCount, const int* counts) override; virtual bool EndPrimitive() override; private: @@ -78,12 +79,22 @@ private: GLuint m_bufferVAO = 0; // VBO capacity GLsizei m_bufferCapacity = 128 * 1024; + // Buffer offset + GLsizei m_bufferOffset = 0; // Buffer mapping state PrimitiveType m_type = {}; - GLuint m_offset = 0; - GLuint m_count = 0; + // Number of drawn primitives + GLuint m_drawCount = 0; + // Total count of drawn vertices + GLuint m_currentCount = 0; + // Starting offset for each drawn primitive + std::vector m_first; + // Numbers of vertices for each drawn primitive + std::vector m_count; + // True means currently drawing bool m_mapped = false; + // True means mapping failed, using auxiliary buffer bool m_backup = false; // Buffered vertex data