From 264640420882ceeafd9b1149eba9472cf8835e7b Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sat, 27 Jan 2024 21:47:04 +0000 Subject: Render text in N draw calls Creates a single buffer per required texture and draws the whole buffer in one go. It does introduce the use of deprecated GL_QUADS primitive, but it's the easiest way to go without needing indices, repeated vertices etc --- test/Jamfile.jam | 2 +- test/test-text.cpp | 4 ++-- ui/text.cpp | 63 +++++++++++++++++++++++++++++++----------------------- ui/text.h | 17 ++++++--------- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/test/Jamfile.jam b/test/Jamfile.jam index c109051..733ef05 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -49,7 +49,7 @@ run test-lib.cpp ; run test-geoData.cpp : -- : fixtures/height/SD19.asc : test ; run test-network.cpp : : : test ; run test-persistence.cpp : -- : [ sequence.insertion-sort [ glob-tree $(fixtures)/json : *.json ] ] : test ; -run test-text.cpp : : : test ; +run test-text.cpp : -- : test-glContainer : test ; run test-enumDetails.cpp ; run test-render.cpp : -- : test-assetFactory : test ; run test-glContextBhvr.cpp ; diff --git a/test/test-text.cpp b/test/test-text.cpp index b540b5a..f652670 100644 --- a/test/test-text.cpp +++ b/test/test-text.cpp @@ -121,9 +121,9 @@ BOOST_AUTO_TEST_CASE(render_text) glViewport(0, 0, 640, 480); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - Text t {"I Like Trains", *this, {{0, 0}, {200, 40}}, {1, 1, 1}}; + Text t {"I Like Trains", *this, {{10, 10}, {200, 40}}, {1, 1, 1}}; UIShader s {640, 480}; - t.render(s, {{200, 200}, {200, 100}}); + t.render(s, {}); Texture::save(output.outImage, "/tmp/text.tga"); } diff --git a/ui/text.cpp b/ui/text.cpp index 5b9e591..5675061 100644 --- a/ui/text.cpp +++ b/ui/text.cpp @@ -1,37 +1,48 @@ #include "text.h" #include "font.h" #include "gfx/gl/uiShader.h" +#include "gfx/gl/vertexArrayObject.h" #include "uiComponent.h" #include +#include #include #include +#include +#include #include -Text::Text(std::string_view s, const Font & font, Position pos, glm::vec3 c) : UIComponent {pos}, colour {c} +Text::Text(std::string_view s, const Font & font, Position pos, glm::vec3 c) : + UIComponent {pos}, colour {c}, font {font} { - for (const auto & textureQuads : font.render(s)) { - auto & rendering - = models.emplace_back(textureQuads.first, static_cast(6 * textureQuads.second.size())); - glBindVertexArray(rendering.vao); - - glBindBuffer(GL_ARRAY_BUFFER, rendering.vbo); - std::vector vertices; - vertices.reserve(6 * textureQuads.second.size()); - for (const auto & quad : textureQuads.second) { - for (auto offset = 0U; offset < 3; offset += 2) { - for (auto vertex = 0U; vertex < 3; vertex += 1) { - vertices.emplace_back(quad[(vertex + offset) % 4] + glm::vec4 {position.origin, 0, 0}); - } - } - }; - glBufferData(GL_ARRAY_BUFFER, static_cast(sizeof(glm::vec4)) * rendering.count, - glm::value_ptr(vertices.front()), GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), nullptr); + VertexArrayObject {vao}.addAttribs(quads.bufferName(), 0); + operator=(s); +} - glBindVertexArray(0); +Text & +Text::operator=(const std::string_view s) +{ + auto tquads = font.render(s); + models.resize(tquads.size()); + const auto glyphCount = std::accumulate(tquads.begin(), tquads.end(), size_t {}, [](auto && init, const auto & q) { + return init += q.second.size(); + }); + quads.resize(glyphCount); + GLint current = 0; + auto model = models.begin(); + auto quad = quads.begin(); + for (const auto & [texture, fquads] : tquads) { + model->first = texture; + model->second = {fquads.size() * 4, current * 4}; + current += static_cast(fquads.size()); + model++; + quad = std::transform(fquads.begin(), fquads.end(), quad, [this](const Font::Quad & q) { + return q * [this](const glm::vec4 & corner) { + return corner + glm::vec4 {this->position.origin, 0, 0}; + }; + }); } + quads.unmap(); + return *this; } void @@ -39,10 +50,10 @@ Text::render(const UIShader & shader, const Position &) const { shader.text.use(colour); glActiveTexture(GL_TEXTURE0); + glBindVertexArray(vao); for (const auto & m : models) { - glBindTexture(GL_TEXTURE_2D, m.texture); - glBindVertexArray(m.vao); - glDrawArrays(GL_TRIANGLES, 0, m.count); + glBindTexture(GL_TEXTURE_2D, m.first); + glDrawArrays(GL_QUADS, m.second.second, m.second.first); } glBindVertexArray(0); glBindTexture(GL_TEXTURE_2D, 0); @@ -53,5 +64,3 @@ Text::handleInput(const SDL_Event &, const Position &) { return false; } - -Text::Model::Model(GLuint t, GLsizei c) : texture {t}, count {c} { } diff --git a/ui/text.h b/ui/text.h index 5217050..31ed9a5 100644 --- a/ui/text.h +++ b/ui/text.h @@ -1,12 +1,12 @@ #pragma once #include "font.h" +#include "glContainer.h" #include "uiComponent.h" #include #include #include #include -#include class UIShader; union SDL_Event; @@ -18,15 +18,12 @@ public: void render(const UIShader &, const Position & parentPos) const override; bool handleInput(const SDL_Event &, const Position & parentPos) override; -private: - struct Model { - Model(GLuint, GLsizei); - GLuint texture; - GLsizei count; - glVertexArray vao; - glBuffer vbo; - }; + Text & operator=(const std::string_view s); - std::vector models; +private: + std::vector>> models; + glContainer quads; + glVertexArray vao; glm::vec3 colour; + const Font & font; }; -- cgit v1.2.3