mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-11-04 03:10:05 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			184 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			184 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include <scwx/qt/util/font_buffer.hpp>
 | 
						|
#include <scwx/util/logger.hpp>
 | 
						|
 | 
						|
#include <mutex>
 | 
						|
 | 
						|
namespace scwx
 | 
						|
{
 | 
						|
namespace qt
 | 
						|
{
 | 
						|
namespace util
 | 
						|
{
 | 
						|
 | 
						|
static const std::string logPrefix_ = "scwx::qt::util::font_buffer";
 | 
						|
static const auto        logger_    = scwx::util::Logger::Create(logPrefix_);
 | 
						|
 | 
						|
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(gl::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(gl::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)
 | 
						|
   {
 | 
						|
      logger_->warn("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(gl::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
 |