diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 538b02ea..20f26629 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -65,9 +65,11 @@ set(SRC_MAP source/scwx/qt/map/map_widget.cpp source/scwx/qt/map/radar_range_layer.cpp source/scwx/qt/map/triangle_layer.cpp) set(HDR_UTIL source/scwx/qt/util/font.hpp + source/scwx/qt/util/font_buffer.hpp source/scwx/qt/util/gl.hpp source/scwx/qt/util/shader_program.hpp) set(SRC_UTIL source/scwx/qt/util/font.cpp + source/scwx/qt/util/font_buffer.cpp source/scwx/qt/util/shader_program.cpp) set(HDR_VIEW source/scwx/qt/view/radar_view.hpp) set(SRC_VIEW source/scwx/qt/view/radar_view.cpp) diff --git a/scwx-qt/source/scwx/qt/gl/text_shader.cpp b/scwx-qt/source/scwx/qt/gl/text_shader.cpp index 35f24007..1ef02af1 100644 --- a/scwx-qt/source/scwx/qt/gl/text_shader.cpp +++ b/scwx-qt/source/scwx/qt/gl/text_shader.cpp @@ -74,9 +74,10 @@ void TextShader::RenderText(const std::string& text, gl.glActiveTexture(GL_TEXTURE0); gl.glBindTexture(GL_TEXTURE_2D, textureId); - std::shared_ptr buffer = util::Font::CreateBuffer(); + std::shared_ptr buffer = + std::make_shared(); font->BufferText(buffer, text, x, y, scale, color); - util::Font::RenderBuffer(gl, buffer); + buffer->Render(gl); } void TextShader::SetProjection(const glm::mat4& projection) diff --git a/scwx-qt/source/scwx/qt/util/font.cpp b/scwx-qt/source/scwx/qt/util/font.cpp index 6be10e51..3a478a05 100644 --- a/scwx-qt/source/scwx/qt/util/font.cpp +++ b/scwx-qt/source/scwx/qt/util/font.cpp @@ -1,6 +1,5 @@ #include -#include #include #include @@ -65,34 +64,6 @@ static const std::string logPrefix_ = "[scwx::qt::util::font] "; static std::unordered_map> fontMap_; -class FontBuffer -{ -public: - explicit FontBuffer() : - vaoId_ {GL_INVALID_INDEX}, - verticesId_ {GL_INVALID_INDEX}, - indicesId_ {GL_INVALID_INDEX}, - gpuISize_ {0}, - gpuVSize_ {0}, - dirty_ {true} - { - } - - ~FontBuffer() {} - - GLuint vaoId_ = GL_INVALID_INDEX; - GLuint verticesId_ = GL_INVALID_INDEX; - GLuint indicesId_ = GL_INVALID_INDEX; - GLsizei gpuISize_ = 0; - GLsizei gpuVSize_ = 0; - bool dirty_ = true; - - std::vector vertices_; - std::vector indices_; - - std::mutex mutex_; -}; - class FontImpl { public: @@ -165,28 +136,15 @@ float Font::BufferText(std::shared_ptr buffer, float s1 = glyph.s1_; float t1 = glyph.t1_; - { - std::scoped_lock lock(buffer->mutex_); - - const GLuint i0 = static_cast(buffer->vertices_.size() / 9u); - const GLuint i1 = i0 + 1; - const GLuint i2 = i1 + 1; - const GLuint i3 = i2 + 1; - - buffer->indices_.insert(buffer->indices_.end(), - {i0, i1, i2, i0, i2, i3}); - buffer->vertices_.insert(buffer->vertices_.end(), - {x0, y0, 0, s0, t0, r, g, b, a, // + buffer->Push(/* Indices */ {0, 1, 2, 0, 2, 3}, // + /* Vertices */ {x0, y0, 0, s0, t0, r, g, b, a, // x0, y1, 0, s0, t1, r, g, b, a, // x1, y1, 0, s1, t1, r, g, b, a, // x1, y0, 0, s1, t0, r, g, b, a}); - } x += glyph.advanceX_ * scale; } - buffer->dirty_ = true; - return x; } @@ -316,129 +274,6 @@ std::shared_ptr Font::Create(const std::string& resource) return font; } -std::shared_ptr Font::CreateBuffer() -{ - return std::make_shared(); -} - -void Font::ClearBuffer(std::shared_ptr buffer) -{ - if (buffer != nullptr) - { - std::scoped_lock lock(buffer->mutex_); - buffer->indices_.clear(); - buffer->vertices_.clear(); - buffer->dirty_ = true; - } -} - -void Font::RenderBuffer(OpenGLFunctions& gl, std::shared_ptr buffer) -{ - // TODO: - if (buffer == nullptr) - { - return; - } - - std::scoped_lock lock(buffer->mutex_); - - // TODO: Vertex buffer upload - if (buffer->dirty_) - { - if (buffer->verticesId_ == GL_INVALID_INDEX) - { - gl.glGenBuffers(1, &buffer->verticesId_); - } - if (buffer->indicesId_ == GL_INVALID_INDEX) - { - gl.glGenBuffers(1, &buffer->indicesId_); - } - - GLsizei vSize = - static_cast(buffer->vertices_.size() * sizeof(GLfloat)); - GLsizei iSize = - static_cast(buffer->indices_.size() * sizeof(GLuint)); - - // Always upload vertices first to avoid rendering non-existent data - - // Upload vertices - gl.glBindBuffer(GL_ARRAY_BUFFER, buffer->verticesId_); - if (vSize != buffer->gpuVSize_) - { - gl.glBufferData( - GL_ARRAY_BUFFER, vSize, buffer->vertices_.data(), GL_DYNAMIC_DRAW); - buffer->gpuVSize_ = vSize; - } - else - { - gl.glBufferSubData( - GL_ARRAY_BUFFER, 0, vSize, buffer->vertices_.data()); - } - - // Upload indices - gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->indicesId_); - if (iSize != buffer->gpuISize_) - { - gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, - iSize, - buffer->indices_.data(), - GL_DYNAMIC_DRAW); - } - else - { - gl.glBufferSubData( - GL_ELEMENT_ARRAY_BUFFER, 0, iSize, buffer->indices_.data()); - } - - buffer->dirty_ = false; - } - - // TODO: Setup - if (buffer->vaoId_ == GL_INVALID_INDEX) - { - // Generate and setup VAO - gl.glGenVertexArrays(1, &buffer->vaoId_); - gl.glBindVertexArray(buffer->vaoId_); - - gl.glBindBuffer(GL_ARRAY_BUFFER, buffer->verticesId_); - - // vec3 aVertex - gl.glEnableVertexAttribArray(0); - gl.glVertexAttribPointer( - 0, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), nullptr); - - // vec2 aTexCoords - gl.glEnableVertexAttribArray(1); - gl.glVertexAttribPointer( - 1, - 2, - GL_FLOAT, - GL_FALSE, - 9 * sizeof(float), - reinterpret_cast(3 * sizeof(float))); - - // vec4 aColor - gl.glEnableVertexAttribArray(2); - gl.glVertexAttribPointer( - 2, - 4, - GL_FLOAT, - GL_FALSE, - 9 * sizeof(float), - reinterpret_cast(5 * sizeof(float))); - - gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->indicesId_); - } - - // Bind VAO for drawing - gl.glBindVertexArray(buffer->vaoId_); - - gl.glDrawElements(GL_TRIANGLES, - static_cast(buffer->indices_.size()), - GL_UNSIGNED_INT, - 0); -} - } // namespace util } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/util/font.hpp b/scwx-qt/source/scwx/qt/util/font.hpp index bdba72f3..0617b628 100644 --- a/scwx-qt/source/scwx/qt/util/font.hpp +++ b/scwx-qt/source/scwx/qt/util/font.hpp @@ -1,12 +1,12 @@ #pragma once +#include #include #include #include #include -#include namespace scwx { @@ -15,8 +15,6 @@ namespace qt namespace util { -class FontBuffer; - class FontImpl; class Font @@ -44,11 +42,6 @@ public: static std::shared_ptr Create(const std::string& resource); - static std::shared_ptr CreateBuffer(); - static void ClearBuffer(std::shared_ptr buffer); - static void RenderBuffer(OpenGLFunctions& gl, - std::shared_ptr buffer); - private: std::unique_ptr p; }; diff --git a/scwx-qt/source/scwx/qt/util/font_buffer.cpp b/scwx-qt/source/scwx/qt/util/font_buffer.cpp new file mode 100644 index 00000000..06bd4cec --- /dev/null +++ b/scwx-qt/source/scwx/qt/util/font_buffer.cpp @@ -0,0 +1,185 @@ +#include + +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace util +{ + +static const std::string logPrefix_ = "[scwx::qt::util::font_buffer] "; + +class FontBufferImpl +{ +public: + explicit FontBufferImpl() : + vaoId_ {GL_INVALID_INDEX}, + verticesId_ {GL_INVALID_INDEX}, + indicesId_ {GL_INVALID_INDEX}, + gpuISize_ {0}, + gpuVSize_ {0}, + dirty_ {true} + { + } + + ~FontBufferImpl() {} + + void RenderSetup(OpenGLFunctions& gl) + { + // Generate and setup VAO + gl.glGenVertexArrays(1, &vaoId_); + gl.glBindVertexArray(vaoId_); + + gl.glBindBuffer(GL_ARRAY_BUFFER, verticesId_); + + // vec3 aVertex + gl.glEnableVertexAttribArray(0); + gl.glVertexAttribPointer( + 0, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(float), nullptr); + + // vec2 aTexCoords + gl.glEnableVertexAttribArray(1); + gl.glVertexAttribPointer( + 1, + 2, + GL_FLOAT, + GL_FALSE, + 9 * sizeof(float), + reinterpret_cast(3 * sizeof(float))); + + // vec4 aColor + gl.glEnableVertexAttribArray(2); + gl.glVertexAttribPointer( + 2, + 4, + GL_FLOAT, + GL_FALSE, + 9 * sizeof(float), + reinterpret_cast(5 * sizeof(float))); + + gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesId_); + } + + void Upload(OpenGLFunctions& gl) + { + if (verticesId_ == GL_INVALID_INDEX) + { + gl.glGenBuffers(1, &verticesId_); + } + if (indicesId_ == GL_INVALID_INDEX) + { + gl.glGenBuffers(1, &indicesId_); + } + + GLsizei vSize = static_cast(vertices_.size() * sizeof(GLfloat)); + GLsizei iSize = static_cast(indices_.size() * sizeof(GLuint)); + + // Always upload vertices first to avoid rendering non-existent data + + // Upload vertices + gl.glBindBuffer(GL_ARRAY_BUFFER, verticesId_); + if (vSize != gpuVSize_) + { + gl.glBufferData( + GL_ARRAY_BUFFER, vSize, vertices_.data(), GL_DYNAMIC_DRAW); + gpuVSize_ = vSize; + } + else + { + gl.glBufferSubData(GL_ARRAY_BUFFER, 0, vSize, vertices_.data()); + } + + // Upload indices + gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesId_); + if (iSize != gpuISize_) + { + gl.glBufferData( + GL_ELEMENT_ARRAY_BUFFER, iSize, indices_.data(), GL_DYNAMIC_DRAW); + } + else + { + gl.glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, iSize, indices_.data()); + } + + dirty_ = false; + } + + GLuint vaoId_; + GLuint verticesId_; + GLuint indicesId_; + GLsizei gpuISize_; + GLsizei gpuVSize_; + bool dirty_; + + std::vector vertices_; + std::vector indices_; + + std::mutex mutex_; +}; + +FontBuffer::FontBuffer() : p(std::make_unique()) {} +FontBuffer::~FontBuffer() = default; + +void FontBuffer::Clear() +{ + if (!p->indices_.empty() || !p->vertices_.empty()) + { + std::scoped_lock lock(p->mutex_); + p->indices_.clear(); + p->vertices_.clear(); + p->dirty_ = true; + } +} + +void FontBuffer::Push(std::initializer_list indices, + std::initializer_list vertices) +{ + if (indices.size() % 3 != 0 || vertices.size() % 9 != 0) + { + BOOST_LOG_TRIVIAL(warning) + << logPrefix_ << "Invalid push arguments, ignoring"; + return; + } + + std::scoped_lock lock(p->mutex_); + + GLuint indexStart = static_cast(p->vertices_.size() / 9); + + for (GLuint index : indices) + { + p->indices_.push_back(index + indexStart); + } + + p->vertices_.insert(p->vertices_.end(), vertices); +} + +void FontBuffer::Render(OpenGLFunctions& gl) +{ + std::scoped_lock lock(p->mutex_); + + if (p->dirty_) + { + p->Upload(gl); + } + + if (p->vaoId_ == GL_INVALID_INDEX) + { + p->RenderSetup(gl); + } + + // Bind VAO for drawing + gl.glBindVertexArray(p->vaoId_); + + gl.glDrawElements(GL_TRIANGLES, + static_cast(p->indices_.size()), + GL_UNSIGNED_INT, + 0); +} + +} // namespace util +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/util/font_buffer.hpp b/scwx-qt/source/scwx/qt/util/font_buffer.hpp new file mode 100644 index 00000000..c794504c --- /dev/null +++ b/scwx-qt/source/scwx/qt/util/font_buffer.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace util +{ + +class FontBufferImpl; + +class FontBuffer +{ +public: + explicit FontBuffer(); + ~FontBuffer(); + + FontBuffer(const FontBuffer&) = delete; + FontBuffer& operator=(const FontBuffer&) = delete; + + FontBuffer(FontBuffer&&) = delete; + FontBuffer& operator=(FontBuffer&&) = delete; + + void Clear(); + void Push(std::initializer_list indices, + std::initializer_list vertices); + void Render(OpenGLFunctions& gl); + +private: + std::unique_ptr p; +}; + +} // namespace util +} // namespace qt +} // namespace scwx