mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 00:10:06 +00:00 
			
		
		
		
	Extracting FontBuffer logic from Font
This commit is contained in:
		
							parent
							
								
									f21523d88b
								
							
						
					
					
						commit
						ee0f3b35bf
					
				
					 6 changed files with 232 additions and 177 deletions
				
			
		|  | @ -74,9 +74,10 @@ void TextShader::RenderText(const std::string&               text, | |||
|    gl.glActiveTexture(GL_TEXTURE0); | ||||
|    gl.glBindTexture(GL_TEXTURE_2D, textureId); | ||||
| 
 | ||||
|    std::shared_ptr<util::FontBuffer> buffer = util::Font::CreateBuffer(); | ||||
|    std::shared_ptr<util::FontBuffer> buffer = | ||||
|       std::make_shared<util::FontBuffer>(); | ||||
|    font->BufferText(buffer, text, x, y, scale, color); | ||||
|    util::Font::RenderBuffer(gl, buffer); | ||||
|    buffer->Render(gl); | ||||
| } | ||||
| 
 | ||||
| void TextShader::SetProjection(const glm::mat4& projection) | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| #include <scwx/qt/util/font.hpp> | ||||
| 
 | ||||
| #include <mutex> | ||||
| #include <unordered_map> | ||||
| 
 | ||||
| #include <boost/log/trivial.hpp> | ||||
|  | @ -65,34 +64,6 @@ static const std::string logPrefix_ = "[scwx::qt::util::font] "; | |||
| 
 | ||||
| static std::unordered_map<std::string, std::shared_ptr<Font>> 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<GLfloat> vertices_; | ||||
|    std::vector<GLuint>  indices_; | ||||
| 
 | ||||
|    std::mutex mutex_; | ||||
| }; | ||||
| 
 | ||||
| class FontImpl | ||||
| { | ||||
| public: | ||||
|  | @ -165,28 +136,15 @@ float Font::BufferText(std::shared_ptr<FontBuffer> buffer, | |||
|       float s1 = glyph.s1_; | ||||
|       float t1 = glyph.t1_; | ||||
| 
 | ||||
|       { | ||||
|          std::scoped_lock lock(buffer->mutex_); | ||||
| 
 | ||||
|          const GLuint i0 = static_cast<GLuint>(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> Font::Create(const std::string& resource) | |||
|    return font; | ||||
| } | ||||
| 
 | ||||
| std::shared_ptr<FontBuffer> Font::CreateBuffer() | ||||
| { | ||||
|    return std::make_shared<FontBuffer>(); | ||||
| } | ||||
| 
 | ||||
| void Font::ClearBuffer(std::shared_ptr<FontBuffer> 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<FontBuffer> 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<GLsizei>(buffer->vertices_.size() * sizeof(GLfloat)); | ||||
|       GLsizei iSize = | ||||
|          static_cast<GLsizei>(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<const GLvoid*>(3 * sizeof(float))); | ||||
| 
 | ||||
|       // vec4 aColor
 | ||||
|       gl.glEnableVertexAttribArray(2); | ||||
|       gl.glVertexAttribPointer( | ||||
|          2, | ||||
|          4, | ||||
|          GL_FLOAT, | ||||
|          GL_FALSE, | ||||
|          9 * sizeof(float), | ||||
|          reinterpret_cast<const GLvoid*>(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<GLsizei>(buffer->indices_.size()), | ||||
|                      GL_UNSIGNED_INT, | ||||
|                      0); | ||||
| } | ||||
| 
 | ||||
| } // namespace util
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  |  | |||
|  | @ -1,12 +1,12 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/util/font_buffer.hpp> | ||||
| #include <scwx/qt/util/gl.hpp> | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <string> | ||||
| 
 | ||||
| #include <boost/gil.hpp> | ||||
| #include <glm/glm.hpp> | ||||
| 
 | ||||
| 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<Font> Create(const std::string& resource); | ||||
| 
 | ||||
|    static std::shared_ptr<FontBuffer> CreateBuffer(); | ||||
|    static void ClearBuffer(std::shared_ptr<FontBuffer> buffer); | ||||
|    static void RenderBuffer(OpenGLFunctions&            gl, | ||||
|                             std::shared_ptr<FontBuffer> buffer); | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<FontImpl> p; | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										185
									
								
								scwx-qt/source/scwx/qt/util/font_buffer.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								scwx-qt/source/scwx/qt/util/font_buffer.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,185 @@ | |||
| #include <scwx/qt/util/font_buffer.hpp> | ||||
| 
 | ||||
| #include <mutex> | ||||
| 
 | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| 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<const GLvoid*>(3 * sizeof(float))); | ||||
| 
 | ||||
|       // vec4 aColor
 | ||||
|       gl.glEnableVertexAttribArray(2); | ||||
|       gl.glVertexAttribPointer( | ||||
|          2, | ||||
|          4, | ||||
|          GL_FLOAT, | ||||
|          GL_FALSE, | ||||
|          9 * sizeof(float), | ||||
|          reinterpret_cast<const GLvoid*>(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<GLsizei>(vertices_.size() * sizeof(GLfloat)); | ||||
|       GLsizei iSize = static_cast<GLsizei>(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<GLfloat> vertices_; | ||||
|    std::vector<GLuint>  indices_; | ||||
| 
 | ||||
|    std::mutex mutex_; | ||||
| }; | ||||
| 
 | ||||
| FontBuffer::FontBuffer() : p(std::make_unique<FontBufferImpl>()) {} | ||||
| 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<GLuint>  indices, | ||||
|                       std::initializer_list<GLfloat> 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<GLuint>(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<GLsizei>(p->indices_.size()), | ||||
|                      GL_UNSIGNED_INT, | ||||
|                      0); | ||||
| } | ||||
| 
 | ||||
| } // namespace util
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										39
									
								
								scwx-qt/source/scwx/qt/util/font_buffer.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								scwx-qt/source/scwx/qt/util/font_buffer.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/util/gl.hpp> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| 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<GLuint>  indices, | ||||
|              std::initializer_list<GLfloat> vertices); | ||||
|    void Render(OpenGLFunctions& gl); | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<FontBufferImpl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace util
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat