mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 23:30:05 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			304 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			304 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include <scwx/qt/gl/draw/rectangle.hpp>
 | |
| #include <scwx/util/logger.hpp>
 | |
| 
 | |
| #include <optional>
 | |
| 
 | |
| namespace scwx
 | |
| {
 | |
| namespace qt
 | |
| {
 | |
| namespace gl
 | |
| {
 | |
| namespace 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_ {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() {}
 | |
| 
 | |
|    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(context->gl()), p(std::make_unique<Impl>(context))
 | |
| {
 | |
| }
 | |
| Rectangle::~Rectangle() = default;
 | |
| 
 | |
| Rectangle::Rectangle(Rectangle&&) noexcept            = default;
 | |
| Rectangle& Rectangle::operator=(Rectangle&&) noexcept = default;
 | |
| 
 | |
| void Rectangle::Initialize()
 | |
| {
 | |
|    gl::OpenGLFunctions& gl = p->context_->gl();
 | |
| 
 | |
|    p->shaderProgram_ =
 | |
|       p->context_->GetShaderProgram(":/gl/color.vert", ":/gl/color.frag");
 | |
| 
 | |
|    p->uMVPMatrixLocation_ =
 | |
|       gl.glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix");
 | |
|    if (p->uMVPMatrixLocation_ == -1)
 | |
|    {
 | |
|       logger_->warn("Could not find uMVPMatrix");
 | |
|    }
 | |
| 
 | |
|    gl.glGenVertexArrays(1, &p->vao_);
 | |
|    gl.glGenBuffers(1, &p->vbo_);
 | |
| 
 | |
|    gl.glBindVertexArray(p->vao_);
 | |
|    gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_);
 | |
|    gl.glBufferData(
 | |
|       GL_ARRAY_BUFFER, sizeof(float) * BUFFER_LENGTH, nullptr, GL_DYNAMIC_DRAW);
 | |
| 
 | |
|    gl.glVertexAttribPointer(0,
 | |
|                             3,
 | |
|                             GL_FLOAT,
 | |
|                             GL_FALSE,
 | |
|                             POINTS_PER_VERTEX * sizeof(float),
 | |
|                             static_cast<void*>(0));
 | |
|    gl.glEnableVertexAttribArray(0);
 | |
| 
 | |
|    gl.glVertexAttribPointer(1,
 | |
|                             4,
 | |
|                             GL_FLOAT,
 | |
|                             GL_FALSE,
 | |
|                             POINTS_PER_VERTEX * sizeof(float),
 | |
|                             reinterpret_cast<void*>(3 * sizeof(float)));
 | |
|    gl.glEnableVertexAttribArray(1);
 | |
| 
 | |
|    p->dirty_ = true;
 | |
| }
 | |
| 
 | |
| void Rectangle::Render(const QMapLibreGL::CustomLayerRenderParameters& params)
 | |
| {
 | |
|    if (p->visible_)
 | |
|    {
 | |
|       gl::OpenGLFunctions& gl = p->context_->gl();
 | |
| 
 | |
|       gl.glBindVertexArray(p->vao_);
 | |
|       gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_);
 | |
| 
 | |
|       p->Update();
 | |
|       p->shaderProgram_->Use();
 | |
|       UseDefaultProjection(params, p->uMVPMatrixLocation_);
 | |
| 
 | |
|       if (p->fillColor_.has_value())
 | |
|       {
 | |
|          // Draw fill
 | |
|          gl.glDrawArrays(GL_TRIANGLES, 24, 6);
 | |
|       }
 | |
| 
 | |
|       if (p->borderWidth_ > 0.0f)
 | |
|       {
 | |
|          // Draw border
 | |
|          gl.glDrawArrays(GL_TRIANGLES, 0, 24);
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| void Rectangle::Deinitialize()
 | |
| {
 | |
|    gl::OpenGLFunctions& gl = p->context_->gl();
 | |
| 
 | |
|    gl.glDeleteVertexArrays(1, &p->vao_);
 | |
|    gl.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_)
 | |
|    {
 | |
|       gl::OpenGLFunctions& gl = context_->gl();
 | |
| 
 | |
|       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
 | |
|           }};
 | |
| 
 | |
|       gl.glBufferData(GL_ARRAY_BUFFER,
 | |
|                       sizeof(float) * BUFFER_LENGTH,
 | |
|                       buffer,
 | |
|                       GL_DYNAMIC_DRAW);
 | |
| 
 | |
|       dirty_ = false;
 | |
|    }
 | |
| }
 | |
| 
 | |
| } // namespace draw
 | |
| } // namespace gl
 | |
| } // namespace qt
 | |
| } // namespace scwx
 | 
