mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-11-04 15:20:06 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			299 lines
		
	
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			299 lines
		
	
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include <scwx/qt/gl/draw/rectangle.hpp>
 | 
						|
#include <scwx/util/logger.hpp>
 | 
						|
 | 
						|
#include <optional>
 | 
						|
 | 
						|
namespace scwx::qt::gl::draw
 | 
						|
{
 | 
						|
 | 
						|
static const std::string logPrefix_ = "scwx::qt::gl::draw::rectangle";
 | 
						|
static const auto        logger_    = scwx::util::Logger::Create(logPrefix_);
 | 
						|
 | 
						|
static constexpr size_t NUM_RECTANGLES         = 5;
 | 
						|
static constexpr size_t NUM_TRIANGLES          = NUM_RECTANGLES * 2;
 | 
						|
static constexpr size_t VERTICES_PER_TRIANGLE  = 3;
 | 
						|
static constexpr size_t VERTICES_PER_RECTANGLE = VERTICES_PER_TRIANGLE * 2;
 | 
						|
static constexpr size_t POINTS_PER_VERTEX      = 7;
 | 
						|
static constexpr size_t BUFFER_LENGTH =
 | 
						|
   NUM_TRIANGLES * VERTICES_PER_TRIANGLE * POINTS_PER_VERTEX;
 | 
						|
 | 
						|
class Rectangle::Impl
 | 
						|
{
 | 
						|
public:
 | 
						|
   explicit Impl(std::shared_ptr<GlContext> context) :
 | 
						|
       context_ {std::move(context)},
 | 
						|
       dirty_ {false},
 | 
						|
       visible_ {true},
 | 
						|
       x_ {0.0f},
 | 
						|
       y_ {0.0f},
 | 
						|
       z_ {0.0f},
 | 
						|
       width_ {0.0f},
 | 
						|
       height_ {0.0f},
 | 
						|
       borderWidth_ {0.0f},
 | 
						|
       borderColor_ {0, 0, 0, 0},
 | 
						|
       fillColor_ {std::nullopt},
 | 
						|
       shaderProgram_ {nullptr},
 | 
						|
       uMVPMatrixLocation_(GL_INVALID_INDEX),
 | 
						|
       vao_ {GL_INVALID_INDEX},
 | 
						|
       vbo_ {GL_INVALID_INDEX}
 | 
						|
   {
 | 
						|
   }
 | 
						|
   ~Impl() = default;
 | 
						|
 | 
						|
   Impl(const Impl&)             = delete;
 | 
						|
   Impl& operator=(const Impl&)  = delete;
 | 
						|
   Impl(const Impl&&)            = delete;
 | 
						|
   Impl& operator=(const Impl&&) = delete;
 | 
						|
 | 
						|
   std::shared_ptr<GlContext> context_;
 | 
						|
 | 
						|
   bool dirty_;
 | 
						|
 | 
						|
   bool  visible_;
 | 
						|
   float x_;
 | 
						|
   float y_;
 | 
						|
   float z_;
 | 
						|
   float width_;
 | 
						|
   float height_;
 | 
						|
 | 
						|
   float                     borderWidth_;
 | 
						|
   boost::gil::rgba8_pixel_t borderColor_;
 | 
						|
 | 
						|
   std::optional<boost::gil::rgba8_pixel_t> fillColor_;
 | 
						|
 | 
						|
   std::shared_ptr<ShaderProgram> shaderProgram_;
 | 
						|
   GLint                          uMVPMatrixLocation_;
 | 
						|
 | 
						|
   GLuint vao_;
 | 
						|
   GLuint vbo_;
 | 
						|
 | 
						|
   void Update();
 | 
						|
};
 | 
						|
 | 
						|
Rectangle::Rectangle(std::shared_ptr<GlContext> context) :
 | 
						|
    DrawItem(), p(std::make_unique<Impl>(context))
 | 
						|
{
 | 
						|
}
 | 
						|
Rectangle::~Rectangle() = default;
 | 
						|
 | 
						|
Rectangle::Rectangle(Rectangle&&) noexcept            = default;
 | 
						|
Rectangle& Rectangle::operator=(Rectangle&&) noexcept = default;
 | 
						|
 | 
						|
void Rectangle::Initialize()
 | 
						|
{
 | 
						|
   p->shaderProgram_ =
 | 
						|
      p->context_->GetShaderProgram(":/gl/color.vert", ":/gl/color.frag");
 | 
						|
 | 
						|
   p->uMVPMatrixLocation_ =
 | 
						|
      glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix");
 | 
						|
   if (p->uMVPMatrixLocation_ == -1)
 | 
						|
   {
 | 
						|
      logger_->warn("Could not find uMVPMatrix");
 | 
						|
   }
 | 
						|
 | 
						|
   glGenVertexArrays(1, &p->vao_);
 | 
						|
   glGenBuffers(1, &p->vbo_);
 | 
						|
 | 
						|
   glBindVertexArray(p->vao_);
 | 
						|
   glBindBuffer(GL_ARRAY_BUFFER, p->vbo_);
 | 
						|
   glBufferData(
 | 
						|
      GL_ARRAY_BUFFER, sizeof(float) * BUFFER_LENGTH, nullptr, GL_DYNAMIC_DRAW);
 | 
						|
 | 
						|
   // NOLINTBEGIN(modernize-use-nullptr)
 | 
						|
   // NOLINTBEGIN(performance-no-int-to-ptr)
 | 
						|
 | 
						|
   glVertexAttribPointer(0,
 | 
						|
                         3,
 | 
						|
                         GL_FLOAT,
 | 
						|
                         GL_FALSE,
 | 
						|
                         POINTS_PER_VERTEX * sizeof(float),
 | 
						|
                         static_cast<void*>(0));
 | 
						|
   glEnableVertexAttribArray(0);
 | 
						|
 | 
						|
   glVertexAttribPointer(1,
 | 
						|
                         4,
 | 
						|
                         GL_FLOAT,
 | 
						|
                         GL_FALSE,
 | 
						|
                         POINTS_PER_VERTEX * sizeof(float),
 | 
						|
                         reinterpret_cast<void*>(3 * sizeof(float)));
 | 
						|
   glEnableVertexAttribArray(1);
 | 
						|
 | 
						|
   // NOLINTEND(performance-no-int-to-ptr)
 | 
						|
   // NOLINTEND(modernize-use-nullptr)
 | 
						|
 | 
						|
   p->dirty_ = true;
 | 
						|
}
 | 
						|
 | 
						|
void Rectangle::Render(const QMapLibre::CustomLayerRenderParameters& params)
 | 
						|
{
 | 
						|
   if (p->visible_)
 | 
						|
   {
 | 
						|
      glBindVertexArray(p->vao_);
 | 
						|
      glBindBuffer(GL_ARRAY_BUFFER, p->vbo_);
 | 
						|
 | 
						|
      p->Update();
 | 
						|
      p->shaderProgram_->Use();
 | 
						|
      UseDefaultProjection(params, p->uMVPMatrixLocation_);
 | 
						|
 | 
						|
      if (p->fillColor_.has_value())
 | 
						|
      {
 | 
						|
         // Draw fill
 | 
						|
         // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
 | 
						|
         glDrawArrays(GL_TRIANGLES, 24, 6);
 | 
						|
      }
 | 
						|
 | 
						|
      if (p->borderWidth_ > 0.0f)
 | 
						|
      {
 | 
						|
         // Draw border
 | 
						|
         // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
 | 
						|
         glDrawArrays(GL_TRIANGLES, 0, 24);
 | 
						|
      }
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
void Rectangle::Deinitialize()
 | 
						|
{
 | 
						|
   glDeleteVertexArrays(1, &p->vao_);
 | 
						|
   glDeleteBuffers(1, &p->vbo_);
 | 
						|
}
 | 
						|
 | 
						|
void Rectangle::SetBorder(float width, boost::gil::rgba8_pixel_t color)
 | 
						|
{
 | 
						|
   if (p->borderWidth_ != width || p->borderColor_ != color)
 | 
						|
   {
 | 
						|
      p->borderWidth_ = width;
 | 
						|
      p->borderColor_ = color;
 | 
						|
      p->dirty_       = true;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
void Rectangle::SetFill(boost::gil::rgba8_pixel_t color)
 | 
						|
{
 | 
						|
   if (p->fillColor_ != color)
 | 
						|
   {
 | 
						|
      p->fillColor_ = color;
 | 
						|
      p->dirty_     = true;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
void Rectangle::SetPosition(float x, float y, float z)
 | 
						|
{
 | 
						|
   if (p->x_ != x || p->y_ != y || p->z_ != z)
 | 
						|
   {
 | 
						|
      p->x_     = x;
 | 
						|
      p->y_     = y;
 | 
						|
      p->z_     = z;
 | 
						|
      p->dirty_ = true;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
void Rectangle::SetSize(float width, float height)
 | 
						|
{
 | 
						|
   if (p->width_ != width || p->height_ != height)
 | 
						|
   {
 | 
						|
      p->width_  = width;
 | 
						|
      p->height_ = height;
 | 
						|
      p->dirty_  = true;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
void Rectangle::SetVisible(bool visible)
 | 
						|
{
 | 
						|
   p->visible_ = visible;
 | 
						|
}
 | 
						|
 | 
						|
void Rectangle::Impl::Update()
 | 
						|
{
 | 
						|
   if (dirty_)
 | 
						|
   {
 | 
						|
      const float lox = x_;
 | 
						|
      const float rox = x_ + width_;
 | 
						|
      const float boy = y_;
 | 
						|
      const float toy = y_ + height_;
 | 
						|
 | 
						|
      const float lix = lox + borderWidth_;
 | 
						|
      const float rix = rox - borderWidth_;
 | 
						|
 | 
						|
      const float biy = boy + borderWidth_;
 | 
						|
      const float tiy = toy - borderWidth_;
 | 
						|
 | 
						|
      const float bc0 = borderColor_[0] / 255.0f;
 | 
						|
      const float bc1 = borderColor_[1] / 255.0f;
 | 
						|
      const float bc2 = borderColor_[2] / 255.0f;
 | 
						|
      const float bc3 = borderColor_[3] / 255.0f;
 | 
						|
 | 
						|
      float fc0 = 0.0f;
 | 
						|
      float fc1 = 0.0f;
 | 
						|
      float fc2 = 0.0f;
 | 
						|
      float fc3 = 0.0f;
 | 
						|
 | 
						|
      if (fillColor_.has_value())
 | 
						|
      {
 | 
						|
         boost::gil::rgba8_pixel_t& fc = fillColor_.value();
 | 
						|
 | 
						|
         fc0 = fc[0] / 255.0f;
 | 
						|
         fc1 = fc[1] / 255.0f;
 | 
						|
         fc2 = fc[2] / 255.0f;
 | 
						|
         fc3 = fc[3] / 255.0f;
 | 
						|
      }
 | 
						|
 | 
						|
      const float buffer[NUM_RECTANGLES][VERTICES_PER_RECTANGLE]
 | 
						|
                        [POINTS_PER_VERTEX] = //
 | 
						|
         {                                    //
 | 
						|
 | 
						|
          // Left Border
 | 
						|
          {
 | 
						|
             {lox, boy, z_, bc0, bc1, bc2, bc3}, // BL
 | 
						|
             {lox, toy, z_, bc0, bc1, bc2, bc3}, // TL
 | 
						|
             {lix, boy, z_, bc0, bc1, bc2, bc3}, // BR
 | 
						|
             {lix, boy, z_, bc0, bc1, bc2, bc3}, // BR
 | 
						|
             {lix, toy, z_, bc0, bc1, bc2, bc3}, // TR
 | 
						|
             {lox, toy, z_, bc0, bc1, bc2, bc3}  // TL
 | 
						|
          },
 | 
						|
          // Right Border
 | 
						|
          {
 | 
						|
             {rox, boy, z_, bc0, bc1, bc2, bc3}, // BR
 | 
						|
             {rox, toy, z_, bc0, bc1, bc2, bc3}, // TR
 | 
						|
             {rix, boy, z_, bc0, bc1, bc2, bc3}, // BL
 | 
						|
             {rix, boy, z_, bc0, bc1, bc2, bc3}, // BL
 | 
						|
             {rix, toy, z_, bc0, bc1, bc2, bc3}, // TL
 | 
						|
             {rox, toy, z_, bc0, bc1, bc2, bc3}  // TR
 | 
						|
          },
 | 
						|
          // Top Border
 | 
						|
          {
 | 
						|
             {lox, toy, z_, bc0, bc1, bc2, bc3}, // TL
 | 
						|
             {rox, toy, z_, bc0, bc1, bc2, bc3}, // TR
 | 
						|
             {rox, tiy, z_, bc0, bc1, bc2, bc3}, // BR
 | 
						|
             {rox, tiy, z_, bc0, bc1, bc2, bc3}, // BR
 | 
						|
             {lox, tiy, z_, bc0, bc1, bc2, bc3}, // BL
 | 
						|
             {lox, toy, z_, bc0, bc1, bc2, bc3}  // TL
 | 
						|
          },
 | 
						|
          // Bottom Border
 | 
						|
          {
 | 
						|
             {lox, boy, z_, bc0, bc1, bc2, bc3}, // BL
 | 
						|
             {rox, boy, z_, bc0, bc1, bc2, bc3}, // BR
 | 
						|
             {rox, biy, z_, bc0, bc1, bc2, bc3}, // TR
 | 
						|
             {rox, biy, z_, bc0, bc1, bc2, bc3}, // TR
 | 
						|
             {lox, biy, z_, bc0, bc1, bc2, bc3}, // TL
 | 
						|
             {lox, boy, z_, bc0, bc1, bc2, bc3}  // BL
 | 
						|
          },
 | 
						|
          // Fill
 | 
						|
          {
 | 
						|
             {lox, toy, z_, fc0, fc1, fc2, fc3}, // TL
 | 
						|
             {rox, toy, z_, fc0, fc1, fc2, fc3}, // TR
 | 
						|
             {rox, boy, z_, fc0, fc1, fc2, fc3}, // BR
 | 
						|
             {rox, boy, z_, fc0, fc1, fc2, fc3}, // BR
 | 
						|
             {lox, boy, z_, fc0, fc1, fc2, fc3}, // BL
 | 
						|
             {lox, toy, z_, fc0, fc1, fc2, fc3}  // TL
 | 
						|
          }};
 | 
						|
 | 
						|
      glBufferData(GL_ARRAY_BUFFER,
 | 
						|
                   sizeof(float) * BUFFER_LENGTH,
 | 
						|
                   static_cast<const void*>(buffer),
 | 
						|
                   GL_DYNAMIC_DRAW);
 | 
						|
 | 
						|
      dirty_ = false;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
} // namespace scwx::qt::gl::draw
 |