mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 06:40:05 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			312 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			312 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include <scwx/qt/gl/draw/geo_line.hpp>
 | |
| #include <scwx/qt/util/geographic_lib.hpp>
 | |
| #include <scwx/qt/util/texture_atlas.hpp>
 | |
| #include <scwx/common/geographic.hpp>
 | |
| #include <scwx/util/logger.hpp>
 | |
| 
 | |
| #include <numbers>
 | |
| #include <optional>
 | |
| 
 | |
| namespace scwx
 | |
| {
 | |
| namespace qt
 | |
| {
 | |
| namespace gl
 | |
| {
 | |
| namespace draw
 | |
| {
 | |
| 
 | |
| static const std::string logPrefix_ = "scwx::qt::gl::draw::geo_line";
 | |
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_);
 | |
| 
 | |
| static constexpr size_t kNumRectangles        = 1;
 | |
| static constexpr size_t kNumTriangles         = kNumRectangles * 2;
 | |
| static constexpr size_t kVerticesPerTriangle  = 3;
 | |
| static constexpr size_t kVerticesPerRectangle = kVerticesPerTriangle * 2;
 | |
| static constexpr size_t kPointsPerVertex      = 10;
 | |
| static constexpr size_t kBufferLength =
 | |
|    kNumTriangles * kVerticesPerTriangle * kPointsPerVertex;
 | |
| 
 | |
| static const std::string kTextureName = "lines/default-1x7";
 | |
| 
 | |
| class GeoLine::Impl
 | |
| {
 | |
| public:
 | |
|    explicit Impl(std::shared_ptr<GlContext> context) :
 | |
|        context_ {context},
 | |
|        geodesic_ {util::GeographicLib::DefaultGeodesic()},
 | |
|        dirty_ {false},
 | |
|        visible_ {true},
 | |
|        points_ {},
 | |
|        angle_ {},
 | |
|        width_ {7.0f},
 | |
|        modulateColor_ {std::nullopt},
 | |
|        shaderProgram_ {nullptr},
 | |
|        uMVPMatrixLocation_(GL_INVALID_INDEX),
 | |
|        uMapMatrixLocation_(GL_INVALID_INDEX),
 | |
|        uMapScreenCoordLocation_(GL_INVALID_INDEX),
 | |
|        texture_ {},
 | |
|        vao_ {GL_INVALID_INDEX},
 | |
|        vbo_ {GL_INVALID_INDEX}
 | |
|    {
 | |
|    }
 | |
| 
 | |
|    ~Impl() {}
 | |
| 
 | |
|    std::shared_ptr<GlContext> context_;
 | |
| 
 | |
|    const GeographicLib::Geodesic& geodesic_;
 | |
| 
 | |
|    bool dirty_;
 | |
| 
 | |
|    bool                              visible_;
 | |
|    std::array<common::Coordinate, 2> points_;
 | |
|    float                             angle_;
 | |
|    float                             width_;
 | |
| 
 | |
|    std::optional<boost::gil::rgba8_pixel_t> modulateColor_;
 | |
| 
 | |
|    std::shared_ptr<ShaderProgram> shaderProgram_;
 | |
|    GLint                          uMVPMatrixLocation_;
 | |
|    GLint                          uMapMatrixLocation_;
 | |
|    GLint                          uMapScreenCoordLocation_;
 | |
| 
 | |
|    util::TextureAttributes texture_;
 | |
| 
 | |
|    GLuint vao_;
 | |
|    GLuint vbo_;
 | |
| 
 | |
|    void Update();
 | |
| };
 | |
| 
 | |
| GeoLine::GeoLine(std::shared_ptr<GlContext> context) :
 | |
|     DrawItem(context->gl()), p(std::make_unique<Impl>(context))
 | |
| {
 | |
| }
 | |
| GeoLine::~GeoLine() = default;
 | |
| 
 | |
| GeoLine::GeoLine(GeoLine&&) noexcept            = default;
 | |
| GeoLine& GeoLine::operator=(GeoLine&&) noexcept = default;
 | |
| 
 | |
| void GeoLine::Initialize()
 | |
| {
 | |
|    gl::OpenGLFunctions& gl = p->context_->gl();
 | |
| 
 | |
|    p->shaderProgram_ = p->context_->GetShaderProgram(":/gl/geo_line.vert",
 | |
|                                                      ":/gl/texture2d.frag");
 | |
| 
 | |
|    p->uMVPMatrixLocation_ =
 | |
|       gl.glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix");
 | |
|    if (p->uMVPMatrixLocation_ == -1)
 | |
|    {
 | |
|       logger_->warn("Could not find uMVPMatrix");
 | |
|    }
 | |
| 
 | |
|    p->uMapMatrixLocation_ =
 | |
|       gl.glGetUniformLocation(p->shaderProgram_->id(), "uMapMatrix");
 | |
|    if (p->uMapMatrixLocation_ == -1)
 | |
|    {
 | |
|       logger_->warn("Could not find uMapMatrix");
 | |
|    }
 | |
| 
 | |
|    p->uMapScreenCoordLocation_ =
 | |
|       gl.glGetUniformLocation(p->shaderProgram_->id(), "uMapScreenCoord");
 | |
|    if (p->uMapScreenCoordLocation_ == -1)
 | |
|    {
 | |
|       logger_->warn("Could not find uMapScreenCoord");
 | |
|    }
 | |
| 
 | |
|    p->texture_ =
 | |
|       util::TextureAtlas::Instance().GetTextureAttributes(kTextureName);
 | |
| 
 | |
|    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) * kBufferLength, nullptr, GL_DYNAMIC_DRAW);
 | |
| 
 | |
|    // aLatLong
 | |
|    gl.glVertexAttribPointer(0,
 | |
|                             2,
 | |
|                             GL_FLOAT,
 | |
|                             GL_FALSE,
 | |
|                             kPointsPerVertex * sizeof(float),
 | |
|                             static_cast<void*>(0));
 | |
|    gl.glEnableVertexAttribArray(0);
 | |
| 
 | |
|    // aXYOffset
 | |
|    gl.glVertexAttribPointer(1,
 | |
|                             2,
 | |
|                             GL_FLOAT,
 | |
|                             GL_FALSE,
 | |
|                             kPointsPerVertex * sizeof(float),
 | |
|                             reinterpret_cast<void*>(2 * sizeof(float)));
 | |
|    gl.glEnableVertexAttribArray(1);
 | |
| 
 | |
|    // aTexCoord
 | |
|    gl.glVertexAttribPointer(2,
 | |
|                             2,
 | |
|                             GL_FLOAT,
 | |
|                             GL_FALSE,
 | |
|                             kPointsPerVertex * sizeof(float),
 | |
|                             reinterpret_cast<void*>(4 * sizeof(float)));
 | |
|    gl.glEnableVertexAttribArray(2);
 | |
| 
 | |
|    // aModulate
 | |
|    gl.glVertexAttribPointer(3,
 | |
|                             4,
 | |
|                             GL_FLOAT,
 | |
|                             GL_FALSE,
 | |
|                             kPointsPerVertex * sizeof(float),
 | |
|                             reinterpret_cast<void*>(6 * sizeof(float)));
 | |
|    gl.glEnableVertexAttribArray(3);
 | |
| 
 | |
|    p->dirty_ = true;
 | |
| }
 | |
| 
 | |
| void GeoLine::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_);
 | |
|       UseMapProjection(
 | |
|          params, p->uMapMatrixLocation_, p->uMapScreenCoordLocation_);
 | |
| 
 | |
|       // Draw line
 | |
|       gl.glDrawArrays(GL_TRIANGLES, 0, 6);
 | |
|    }
 | |
| }
 | |
| 
 | |
| void GeoLine::Deinitialize()
 | |
| {
 | |
|    gl::OpenGLFunctions& gl = p->context_->gl();
 | |
| 
 | |
|    gl.glDeleteVertexArrays(1, &p->vao_);
 | |
|    gl.glDeleteBuffers(1, &p->vbo_);
 | |
| }
 | |
| 
 | |
| void GeoLine::SetPoints(float latitude1,
 | |
|                         float longitude1,
 | |
|                         float latitude2,
 | |
|                         float longitude2)
 | |
| {
 | |
|    if (p->points_[0].latitude_ != latitude1 ||
 | |
|        p->points_[0].longitude_ != longitude1 ||
 | |
|        p->points_[1].latitude_ != latitude2 ||
 | |
|        p->points_[1].longitude_ != longitude2)
 | |
|    {
 | |
|       p->points_[0] = {latitude1, longitude1};
 | |
|       p->points_[1] = {latitude2, longitude2};
 | |
| 
 | |
|       double azi1; // Azimuth at point 1 (degrees)
 | |
|       double azi2; // (Forward) azimuth at point 2 (degrees)
 | |
|       p->geodesic_.Inverse(p->points_[0].latitude_,
 | |
|                            p->points_[0].longitude_,
 | |
|                            p->points_[1].latitude_,
 | |
|                            p->points_[1].longitude_,
 | |
|                            azi1,
 | |
|                            azi2);
 | |
|       p->angle_ = -azi1 * std::numbers::pi / 180.0;
 | |
| 
 | |
|       p->dirty_ = true;
 | |
|    }
 | |
| }
 | |
| 
 | |
| void GeoLine::SetModulateColor(boost::gil::rgba8_pixel_t color)
 | |
| {
 | |
|    if (p->modulateColor_ != color)
 | |
|    {
 | |
|       p->modulateColor_ = color;
 | |
|       p->dirty_         = true;
 | |
|    }
 | |
| }
 | |
| 
 | |
| void GeoLine::SetWidth(float width)
 | |
| {
 | |
|    if (p->width_ != width)
 | |
|    {
 | |
|       p->width_ = width;
 | |
|       p->dirty_ = true;
 | |
|    }
 | |
| }
 | |
| 
 | |
| void GeoLine::SetVisible(bool visible)
 | |
| {
 | |
|    p->visible_ = visible;
 | |
| }
 | |
| 
 | |
| void GeoLine::Impl::Update()
 | |
| {
 | |
|    if (dirty_)
 | |
|    {
 | |
|       gl::OpenGLFunctions& gl = context_->gl();
 | |
| 
 | |
|       texture_ =
 | |
|          util::TextureAtlas::Instance().GetTextureAttributes(kTextureName);
 | |
| 
 | |
|       // Latitude and longitude coordinates in degrees
 | |
|       const float lx = points_[0].latitude_;
 | |
|       const float rx = points_[1].latitude_;
 | |
|       const float by = points_[0].longitude_;
 | |
|       const float ty = points_[1].longitude_;
 | |
| 
 | |
|       // Offset x/y in pixels
 | |
|       const float ox = width_ * 0.5f * cosf(angle_);
 | |
|       const float oy = width_ * 0.5f * sinf(angle_);
 | |
| 
 | |
|       // Texture coordinates
 | |
|       const float ls = texture_.sLeft_;
 | |
|       const float rs = texture_.sRight_;
 | |
|       const float tt = texture_.tTop_;
 | |
|       const float bt = texture_.tBottom_;
 | |
| 
 | |
|       float mc0 = 1.0f;
 | |
|       float mc1 = 1.0f;
 | |
|       float mc2 = 1.0f;
 | |
|       float mc3 = 1.0f;
 | |
| 
 | |
|       if (modulateColor_.has_value())
 | |
|       {
 | |
|          boost::gil::rgba8_pixel_t& mc = modulateColor_.value();
 | |
| 
 | |
|          mc0 = mc[0] / 255.0f;
 | |
|          mc1 = mc[1] / 255.0f;
 | |
|          mc2 = mc[2] / 255.0f;
 | |
|          mc3 = mc[3] / 255.0f;
 | |
|       }
 | |
| 
 | |
|       const float buffer[kNumRectangles][kVerticesPerRectangle]
 | |
|                         [kPointsPerVertex] = //
 | |
|          {                                   //
 | |
|           // Line
 | |
|           {
 | |
|              {lx, by, -ox, -oy, ls, bt, mc0, mc1, mc2, mc3}, // BL
 | |
|              {lx, by, +ox, +oy, ls, tt, mc0, mc1, mc2, mc3}, // TL
 | |
|              {rx, ty, -ox, -oy, rs, bt, mc0, mc1, mc2, mc3}, // BR
 | |
|              {rx, ty, -ox, -oy, rs, bt, mc0, mc1, mc2, mc3}, // BR
 | |
|              {rx, ty, +ox, +oy, rs, tt, mc0, mc1, mc2, mc3}, // TR
 | |
|              {lx, by, +ox, +oy, ls, tt, mc0, mc1, mc2, mc3}  // TL
 | |
|           }};
 | |
| 
 | |
|       gl.glBufferData(GL_ARRAY_BUFFER,
 | |
|                       sizeof(float) * kBufferLength,
 | |
|                       buffer,
 | |
|                       GL_DYNAMIC_DRAW);
 | |
| 
 | |
|       dirty_ = false;
 | |
|    }
 | |
| }
 | |
| 
 | |
| } // namespace draw
 | |
| } // namespace gl
 | |
| } // namespace qt
 | |
| } // namespace scwx
 | 
