#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace scwx { namespace qt { namespace map { static const std::string logPrefix_ = "scwx::qt::map::overlay_layer"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); class OverlayLayerImpl { public: explicit OverlayLayerImpl(std::shared_ptr context) : textShader_(context->gl_), font_(util::Font::Create(":/res/fonts/din1451alt.ttf")), texture_ {GL_INVALID_INDEX}, activeBoxOuter_ {std::make_shared(context->gl_)}, activeBoxInner_ {std::make_shared(context->gl_)}, timeBox_ {std::make_shared(context->gl_)}, sweepTimeString_ {}, sweepTimeNeedsUpdate_ {true} { // TODO: Manage font at the global level, texture at the view level } ~OverlayLayerImpl() = default; gl::TextShader textShader_; std::shared_ptr font_; GLuint texture_; std::shared_ptr activeBoxOuter_; std::shared_ptr activeBoxInner_; std::shared_ptr timeBox_; std::string sweepTimeString_; bool sweepTimeNeedsUpdate_; }; OverlayLayer::OverlayLayer(std::shared_ptr context) : DrawLayer(context), p(std::make_unique(context)) { AddDrawItem(p->timeBox_); AddDrawItem(p->activeBoxOuter_); AddDrawItem(p->activeBoxInner_); p->activeBoxOuter_->SetPosition(0.0f, 0.0f); p->activeBoxOuter_->SetBorder(1.0f, {0, 0, 0, 255}); p->activeBoxInner_->SetBorder(1.0f, {255, 255, 255, 255}); p->activeBoxInner_->SetPosition(1.0f, 1.0f); p->timeBox_->SetFill({0, 0, 0, 192}); } OverlayLayer::~OverlayLayer() = default; void OverlayLayer::Initialize() { logger_->debug("Initialize()"); DrawLayer::Initialize(); gl::OpenGLFunctions& gl = context()->gl_; p->textShader_.Initialize(); if (p->texture_ == GL_INVALID_INDEX) { p->texture_ = p->font_->GenerateTexture(gl); } if (context()->radarProductView_ != nullptr) { connect(context()->radarProductView_.get(), &view::RadarProductView::SweepComputed, this, &OverlayLayer::UpdateSweepTimeNextFrame); } } void OverlayLayer::Render(const QMapbox::CustomLayerRenderParameters& params) { constexpr float fontSize = 16.0f; gl::OpenGLFunctions& gl = context()->gl_; if (p->sweepTimeNeedsUpdate_ && context()->radarProductView_ != nullptr) { p->sweepTimeString_ = scwx::util::TimeString(context()->radarProductView_->sweep_time(), std::chrono::current_zone(), false); p->sweepTimeNeedsUpdate_ = false; } glm::mat4 projection = glm::ortho(0.0f, static_cast(params.width), 0.0f, static_cast(params.height)); // Active Box p->activeBoxOuter_->SetVisible(context()->settings_.isActive_); p->activeBoxInner_->SetVisible(context()->settings_.isActive_); if (context()->settings_.isActive_) { p->activeBoxOuter_->SetSize(params.width, params.height); p->activeBoxInner_->SetSize(params.width - 2.0f, params.height - 2.0f); } if (p->sweepTimeString_.length() > 0) { const float textLength = p->font_->TextLength(p->sweepTimeString_, fontSize); p->timeBox_->SetPosition(static_cast(params.width) - textLength - 14.0f, static_cast(params.height) - 22.0f); p->timeBox_->SetSize(textLength + 14.0f, 22.0f); } DrawLayer::Render(params); if (p->sweepTimeString_.length() > 0) { // Render time p->textShader_.RenderText(p->sweepTimeString_, params.width - 7.0f, static_cast(params.height) - 16.0f, fontSize, projection, boost::gil::rgba8_pixel_t(255, 255, 255, 204), p->font_, p->texture_, gl::TextAlign::Right); } SCWX_GL_CHECK_ERROR(); } void OverlayLayer::Deinitialize() { logger_->debug("Deinitialize()"); DrawLayer::Deinitialize(); gl::OpenGLFunctions& gl = context()->gl_; gl.glDeleteTextures(1, &p->texture_); p->texture_ = GL_INVALID_INDEX; if (context()->radarProductView_ != nullptr) { disconnect(context()->radarProductView_.get(), &view::RadarProductView::SweepComputed, this, &OverlayLayer::UpdateSweepTimeNextFrame); } } void OverlayLayer::UpdateSweepTimeNextFrame() { p->sweepTimeNeedsUpdate_ = true; } } // namespace map } // namespace qt } // namespace scwx