From 037e0922b0024542f3102df5a9588dd1dfe7b361 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 7 Jul 2024 11:51:53 -0500 Subject: [PATCH] Update only dirty lines --- scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp | 275 ++++++++++++++---- scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp | 47 ++- .../source/scwx/qt/gl/draw/linked_vectors.cpp | 40 +-- 3 files changed, 268 insertions(+), 94 deletions(-) diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp b/scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp index e415d24e..9312eea8 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp @@ -6,6 +6,7 @@ #include +#include #include namespace scwx @@ -25,11 +26,13 @@ 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 = 9; -static constexpr size_t kBufferLength = +static constexpr size_t kLineBufferLength_ = kNumTriangles * kVerticesPerTriangle * kPointsPerVertex; -// Threshold, start time, end time -static constexpr std::size_t kIntegersPerVertex_ = 3; +// Threshold, start time, end time, displayed +static constexpr std::size_t kIntegersPerVertex_ = 4; +static constexpr std::size_t kIntegerBufferLength_ = + kNumTriangles * kVerticesPerTriangle * kIntegersPerVertex_; struct GeoLineDrawItem { @@ -81,6 +84,12 @@ public: void BufferLine(const std::shared_ptr& di); void Update(); void UpdateBuffers(); + void UpdateModifiedLineBuffers(); + void UpdateSingleBuffer(const std::shared_ptr& di, + std::size_t lineIndex, + std::vector& linesBuffer, + std::vector& integerBuffer, + std::vector& hoverLines); std::shared_ptr context_; @@ -88,6 +97,8 @@ public: bool dirty_ {false}; bool thresholded_ {false}; + boost::unordered_flat_set> dirtyLines_ {}; + std::chrono::system_clock::time_point selectedTime_ {}; std::mutex lineMutex_ {}; @@ -136,8 +147,7 @@ void GeoLines::set_thresholded(bool thresholded) void GeoLines::Initialize() { - gl::OpenGLFunctions& gl = p->context_->gl(); - auto& gl30 = p->context_->gl30(); + gl::OpenGLFunctions& gl = p->context_->gl(); p->shaderProgram_ = p->context_->GetShaderProgram( {{GL_VERTEX_SHADER, ":/gl/geo_texture2d.vert"}, @@ -158,8 +168,10 @@ void GeoLines::Initialize() gl.glBindVertexArray(p->vao_); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); - gl.glBufferData( - GL_ARRAY_BUFFER, sizeof(float) * kBufferLength, nullptr, GL_DYNAMIC_DRAW); + gl.glBufferData(GL_ARRAY_BUFFER, + sizeof(float) * kLineBufferLength_, + nullptr, + GL_DYNAMIC_DRAW); // aLatLong gl.glVertexAttribPointer(0, @@ -217,7 +229,13 @@ void GeoLines::Initialize() gl.glEnableVertexAttribArray(6); // aDisplayed - gl30.glVertexAttribI1i(7, 1); + gl.glVertexAttribPointer(7, + 1, + GL_INT, + GL_FALSE, + kIntegersPerVertex_ * sizeof(GLint), + reinterpret_cast(3 * sizeof(float))); + gl.glEnableVertexAttribArray(7); p->dirty_ = true; } @@ -280,7 +298,7 @@ void GeoLines::Deinitialize() gl::OpenGLFunctions& gl = p->context_->gl(); gl.glDeleteVertexArrays(1, &p->vao_); - gl.glDeleteBuffers(2, p->vbo_.data()); + gl.glDeleteBuffers(static_cast(p->vbo_.size()), p->vbo_.data()); std::unique_lock lock {p->lineMutex_}; @@ -314,43 +332,94 @@ void GeoLines::SetLineLocation(const std::shared_ptr& di, float latitude2, float longitude2) { - di->latitude1_ = latitude1; - di->longitude1_ = longitude1; - di->latitude2_ = latitude2; - di->longitude2_ = longitude2; + if (di->latitude1_ != latitude1 || di->longitude1_ != longitude1 || + di->latitude2_ != latitude1 || di->longitude2_ != longitude1) + { + di->latitude1_ = latitude1; + di->longitude1_ = longitude1; + di->latitude2_ = latitude2; + di->longitude2_ = longitude2; + p->dirtyLines_.insert(di); + } } void GeoLines::SetLineModulate(const std::shared_ptr& di, boost::gil::rgba8_pixel_t modulate) { - di->modulate_ = {modulate[0] / 255.0f, - modulate[1] / 255.0f, - modulate[2] / 255.0f, - modulate[3] / 255.0f}; + boost::gil::rgba32f_pixel_t newModulate = {modulate[0] / 255.0f, + modulate[1] / 255.0f, + modulate[2] / 255.0f, + modulate[3] / 255.0f}; + + if (di->modulate_ != newModulate) + { + di->modulate_ = newModulate; + p->dirtyLines_.insert(di); + } } void GeoLines::SetLineModulate(const std::shared_ptr& di, boost::gil::rgba32f_pixel_t modulate) { - di->modulate_ = modulate; + if (di->modulate_ != modulate) + { + di->modulate_ = modulate; + p->dirtyLines_.insert(di); + } } void GeoLines::SetLineWidth(const std::shared_ptr& di, float width) { - di->width_ = width; + if (di->width_ != width) + { + di->width_ = width; + p->dirtyLines_.insert(di); + } } void GeoLines::SetLineVisible(const std::shared_ptr& di, bool visible) { - di->visible_ = visible; + if (di->visible_ != visible) + { + di->visible_ = visible; + p->dirtyLines_.insert(di); + } } void GeoLines::SetLineHoverText(const std::shared_ptr& di, const std::string& text) { - di->hoverText_ = text; + if (di->hoverText_ != text) + { + di->hoverText_ = text; + p->dirtyLines_.insert(di); + } +} + +void GeoLines::SetLineStartTime(const std::shared_ptr& di, + std::chrono::system_clock::time_point startTime) +{ + if (di->startTime_ != startTime) + { + di->startTime_ = + std::chrono::time_point_cast(startTime); + p->dirtyLines_.insert(di); + } +} + +void GeoLines::SetLineEndTime(const std::shared_ptr& di, + std::chrono::system_clock::time_point endTime) +{ + if (di->endTime_ != endTime) + { + di->endTime_ = + std::chrono::time_point_cast(endTime); + p->dirtyLines_.insert(di); + } } void GeoLines::FinishLines() @@ -379,20 +448,63 @@ void GeoLines::FinishLines() void GeoLines::Impl::UpdateBuffers() { newLinesBuffer_.clear(); - newLinesBuffer_.reserve(newLineList_.size() * kBufferLength); + newLinesBuffer_.reserve(newLineList_.size() * kLineBufferLength_); newIntegerBuffer_.clear(); newIntegerBuffer_.reserve(newLineList_.size() * kVerticesPerRectangle * kIntegersPerVertex_); newHoverLines_.clear(); - for (auto& di : newLineList_) + for (std::size_t i = 0; i < newLineList_.size(); ++i) { - BufferLine(di); + auto& di = newLineList_[i]; + + // Update line buffer + UpdateSingleBuffer( + di, i, newLinesBuffer_, newIntegerBuffer_, newHoverLines_); + } + + // All lines have been updated + dirtyLines_.clear(); +} + +void GeoLines::Impl::UpdateModifiedLineBuffers() +{ + // Update buffers for modified lines + for (auto& di : dirtyLines_) + { + // Find modified line in the current list + auto it = + std::find(currentLineList_.cbegin(), currentLineList_.cend(), di); + + // Ignore invalid lines + if (it == currentLineList_.cend()) + { + continue; + } + + auto lineIndex = std::distance(currentLineList_.cbegin(), it); + + UpdateSingleBuffer(di, + lineIndex, + currentLinesBuffer_, + currentIntegerBuffer_, + currentHoverLines_); + } + + // Clear list of modified lines + if (!dirtyLines_.empty()) + { + dirtyLines_.clear(); + dirty_ = true; } } -void GeoLines::Impl::BufferLine( - const std::shared_ptr& di) +void GeoLines::Impl::UpdateSingleBuffer( + const std::shared_ptr& di, + std::size_t lineIndex, + std::vector& lineBuffer, + std::vector& integerBuffer, + std::vector& hoverLines) { // Threshold value units::length::nautical_miles threshold = di->threshold_; @@ -438,38 +550,65 @@ void GeoLines::Impl::BufferLine( const float mc2 = di->modulate_[2]; const float mc3 = di->modulate_[3]; - // Update buffers - newLinesBuffer_.insert(newLinesBuffer_.end(), - { - // Line - lat1, lon1, lx, by, mc0, mc1, mc2, mc3, a, // BL - lat2, lon2, lx, ty, mc0, mc1, mc2, mc3, a, // TL - lat1, lon1, rx, by, mc0, mc1, mc2, mc3, a, // BR - lat1, lon1, rx, by, mc0, mc1, mc2, mc3, a, // BR - lat2, lon2, rx, ty, mc0, mc1, mc2, mc3, a, // TR - lat2, lon2, lx, ty, mc0, mc1, mc2, mc3, a // TL - }); - newIntegerBuffer_.insert(newIntegerBuffer_.end(), - {thresholdValue, - startTime, - endTime, - thresholdValue, - startTime, - endTime, - thresholdValue, - startTime, - endTime, - thresholdValue, - startTime, - endTime, - thresholdValue, - startTime, - endTime, - thresholdValue, - startTime, - endTime}); + // Visibility + const GLint v = static_cast(di->visible_); - if (!di->hoverText_.empty()) + // Initiailize line data + const auto lineData = { + // Line + lat1, lon1, lx, by, mc0, mc1, mc2, mc3, a, // BL + lat2, lon2, lx, ty, mc0, mc1, mc2, mc3, a, // TL + lat1, lon1, rx, by, mc0, mc1, mc2, mc3, a, // BR + lat1, lon1, rx, by, mc0, mc1, mc2, mc3, a, // BR + lat2, lon2, rx, ty, mc0, mc1, mc2, mc3, a, // TR + lat2, lon2, lx, ty, mc0, mc1, mc2, mc3, a // TL + }; + const auto integerData = {thresholdValue, startTime, endTime, v, + thresholdValue, startTime, endTime, v, + thresholdValue, startTime, endTime, v, + thresholdValue, startTime, endTime, v, + thresholdValue, startTime, endTime, v, + thresholdValue, startTime, endTime, v}; + + // Buffer position data + auto lineBufferPosition = lineBuffer.end(); + auto lineBufferOffset = lineIndex * kLineBufferLength_; + + auto integerBufferPosition = integerBuffer.end(); + auto integerBufferOffset = lineIndex * kIntegerBufferLength_; + + if (lineBufferOffset < lineBuffer.size()) + { + lineBufferPosition = lineBuffer.begin() + lineBufferOffset; + } + if (integerBufferOffset < integerBuffer.size()) + { + integerBufferPosition = integerBuffer.begin() + integerBufferOffset; + } + + if (lineBufferPosition == lineBuffer.cend()) + { + lineBuffer.insert(lineBufferPosition, lineData); + } + else + { + std::copy(lineData.begin(), lineData.end(), lineBufferPosition); + } + + if (integerBufferPosition == integerBuffer.cend()) + { + integerBuffer.insert(integerBufferPosition, integerData); + } + else + { + std::copy(integerData.begin(), integerData.end(), integerBufferPosition); + } + + auto hoverIt = std::find_if(hoverLines.begin(), + hoverLines.end(), + [&di](auto& entry) { return entry.di_ == di; }); + + if (di->visible_ && !di->hoverText_.empty()) { const units::angle::radians radians = angle; @@ -486,13 +625,31 @@ void GeoLines::Impl::BufferLine( const glm::vec2 obl = rotate * glm::vec2 {-hw, -hw}; const glm::vec2 obr = rotate * glm::vec2 {+hw, -hw}; - newHoverLines_.emplace_back( - LineHoverEntry {di, sc1, sc2, otl, otr, obl, obr}); + if (hoverIt == hoverLines.end()) + { + hoverLines.emplace_back( + LineHoverEntry {di, sc1, sc2, otl, otr, obl, obr}); + } + else + { + hoverIt->p1_ = sc1; + hoverIt->p2_ = sc2; + hoverIt->otl_ = otl; + hoverIt->otr_ = otr; + hoverIt->obl_ = obl; + hoverIt->obr_ = obr; + } + } + else if (hoverIt != hoverLines.end()) + { + hoverLines.erase(hoverIt); } } void GeoLines::Impl::Update() { + UpdateModifiedLineBuffers(); + // If the lines have been updated if (dirty_) { diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp b/scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp index 6422ab4a..78f6a5b0 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp @@ -75,11 +75,11 @@ public: * @param [in] longitude2 The longitude of the second endpoint of the geo * line in degrees. */ - static void SetLineLocation(const std::shared_ptr& di, - float latitude1, - float longitude1, - float latitude2, - float longitude2); + void SetLineLocation(const std::shared_ptr& di, + float latitude1, + float longitude1, + float latitude2, + float longitude2); /** * Sets the modulate color of a geo line. @@ -87,8 +87,8 @@ public: * @param [in] di Geo line draw item * @param [in] modulate Modulate color */ - static void SetLineModulate(const std::shared_ptr& di, - boost::gil::rgba8_pixel_t color); + void SetLineModulate(const std::shared_ptr& di, + boost::gil::rgba8_pixel_t color); /** * Sets the modulate color of a geo line. @@ -96,24 +96,23 @@ public: * @param [in] di Geo line draw item * @param [in] modulate Modulate color */ - static void SetLineModulate(const std::shared_ptr& di, - boost::gil::rgba32f_pixel_t modulate); + void SetLineModulate(const std::shared_ptr& di, + boost::gil::rgba32f_pixel_t modulate); /** * Sets the width of the geo line. * * @param [in] width Width in pixels */ - static void SetLineWidth(const std::shared_ptr& di, - float width); + void SetLineWidth(const std::shared_ptr& di, float width); /** * Sets the visibility of the geo line. * * @param [in] visible */ - static void SetLineVisible(const std::shared_ptr& di, - bool visible); + void SetLineVisible(const std::shared_ptr& di, + bool visible); /** * Sets the hover text of a geo line. @@ -121,8 +120,26 @@ public: * @param [in] di Geo line draw item * @param [in] text Hover text */ - static void SetLineHoverText(const std::shared_ptr& di, - const std::string& text); + void SetLineHoverText(const std::shared_ptr& di, + const std::string& text); + + /** + * Sets the start time of a geo line. + * + * @param [in] di Geo line draw item + * @param [in] startTime Start time + */ + void SetLineStartTime(const std::shared_ptr& di, + std::chrono::system_clock::time_point startTime); + + /** + * Sets the end time of a geo line. + * + * @param [in] di Geo line draw item + * @param [in] endTime End time + */ + void SetLineEndTime(const std::shared_ptr& di, + std::chrono::system_clock::time_point endTime); /** * Finalizes the draw item after adding new lines. diff --git a/scwx-qt/source/scwx/qt/gl/draw/linked_vectors.cpp b/scwx-qt/source/scwx/qt/gl/draw/linked_vectors.cpp index be053e00..3dbab117 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/linked_vectors.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/linked_vectors.cpp @@ -219,13 +219,13 @@ void LinkedVectors::FinishVectors() const double& latitude2 = coordinate2.latitude_; const double& longitude2 = coordinate2.longitude_; - GeoLines::SetLineLocation( + p->geoLines_->SetLineLocation( borderLine, latitude1, longitude1, latitude2, longitude2); - GeoLines::SetLineModulate(borderLine, kBlack); - GeoLines::SetLineWidth(borderLine, di->width_ + 2.0f); - GeoLines::SetLineVisible(borderLine, di->visible_); - GeoLines::SetLineHoverText(borderLine, di->hoverText_); + p->geoLines_->SetLineModulate(borderLine, kBlack); + p->geoLines_->SetLineWidth(borderLine, di->width_ + 2.0f); + p->geoLines_->SetLineVisible(borderLine, di->visible_); + p->geoLines_->SetLineHoverText(borderLine, di->hoverText_); di->borderDrawItems_.emplace_back(std::move(borderLine)); @@ -248,13 +248,13 @@ void LinkedVectors::FinishVectors() auto tickBorderLine = p->geoLines_->AddLine(); - GeoLines::SetLineLocation( + p->geoLines_->SetLineLocation( tickBorderLine, tickLat1, tickLon1, tickLat2, tickLon2); - GeoLines::SetLineModulate(tickBorderLine, kBlack); - GeoLines::SetLineWidth(tickBorderLine, di->width_ + 2.0f); - GeoLines::SetLineVisible(tickBorderLine, di->visible_); - GeoLines::SetLineHoverText(tickBorderLine, di->hoverText_); + p->geoLines_->SetLineModulate(tickBorderLine, kBlack); + p->geoLines_->SetLineWidth(tickBorderLine, di->width_ + 2.0f); + p->geoLines_->SetLineVisible(tickBorderLine, di->visible_); + p->geoLines_->SetLineHoverText(tickBorderLine, di->hoverText_); tickRadius += di->tickRadiusIncrement_; } @@ -279,17 +279,17 @@ void LinkedVectors::FinishVectors() const double& latitude2 = coordinate2.latitude_; const double& longitude2 = coordinate2.longitude_; - GeoLines::SetLineLocation( + p->geoLines_->SetLineLocation( geoLine, latitude1, longitude1, latitude2, longitude2); - GeoLines::SetLineModulate(geoLine, di->modulate_); - GeoLines::SetLineWidth(geoLine, di->width_); - GeoLines::SetLineVisible(geoLine, di->visible_); + p->geoLines_->SetLineModulate(geoLine, di->modulate_); + p->geoLines_->SetLineWidth(geoLine, di->width_); + p->geoLines_->SetLineVisible(geoLine, di->visible_); // If the border is not enabled, this line must have hover text instead if (!p->borderEnabled_) { - GeoLines::SetLineHoverText(geoLine, di->hoverText_); + p->geoLines_->SetLineHoverText(geoLine, di->hoverText_); } di->lineDrawItems_.emplace_back(std::move(geoLine)); @@ -313,17 +313,17 @@ void LinkedVectors::FinishVectors() auto tickGeoLine = p->geoLines_->AddLine(); - GeoLines::SetLineLocation( + p->geoLines_->SetLineLocation( tickGeoLine, tickLat1, tickLon1, tickLat2, tickLon2); - GeoLines::SetLineModulate(tickGeoLine, di->modulate_); - GeoLines::SetLineWidth(tickGeoLine, di->width_); - GeoLines::SetLineVisible(tickGeoLine, di->visible_); + p->geoLines_->SetLineModulate(tickGeoLine, di->modulate_); + p->geoLines_->SetLineWidth(tickGeoLine, di->width_); + p->geoLines_->SetLineVisible(tickGeoLine, di->visible_); // If the border is not enabled, this line must have hover text if (!p->borderEnabled_) { - GeoLines::SetLineHoverText(tickGeoLine, di->hoverText_); + p->geoLines_->SetLineHoverText(tickGeoLine, di->hoverText_); } tickRadius += di->tickRadiusIncrement_;