diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_icons.cpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_icons.cpp index b9e68983..150a8985 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_icons.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_icons.cpp @@ -32,6 +32,9 @@ static constexpr std::size_t kIconBufferLength = static constexpr std::size_t kTextureBufferLength = kNumTriangles * kVerticesPerTriangle * kPointsPerTexCoord; +// Threshold, start time, end time +static constexpr std::size_t kIntegersPerVertex_ = 3; + struct PlacefileIconInfo { PlacefileIconInfo( @@ -78,6 +81,7 @@ public: uMapMatrixLocation_(GL_INVALID_INDEX), uMapScreenCoordLocation_(GL_INVALID_INDEX), uMapDistanceLocation_(GL_INVALID_INDEX), + uSelectedTimeLocation_(GL_INVALID_INDEX), vao_ {GL_INVALID_INDEX}, vbo_ {GL_INVALID_INDEX}, numVertices_ {0} @@ -111,9 +115,9 @@ public: newValidIconList_ {}; std::vector currentIconBuffer_ {}; - std::vector currentThresholdBuffer_ {}; + std::vector currentIntegerBuffer_ {}; std::vector newIconBuffer_ {}; - std::vector newThresholdBuffer_ {}; + std::vector newIntegerBuffer_ {}; std::vector textureBuffer_ {}; @@ -125,6 +129,7 @@ public: GLint uMapMatrixLocation_; GLint uMapScreenCoordLocation_; GLint uMapDistanceLocation_; + GLint uSelectedTimeLocation_; GLuint vao_; std::array vbo_; @@ -167,6 +172,8 @@ void PlacefileIcons::Initialize() p->shaderProgram_->GetUniformLocation("uMapScreenCoord"); p->uMapDistanceLocation_ = p->shaderProgram_->GetUniformLocation("uMapDistance"); + p->uSelectedTimeLocation_ = + p->shaderProgram_->GetUniformLocation("uSelectedTime"); gl.glGenVertexArrays(1, &p->vao_); gl.glGenBuffers(static_cast(p->vbo_.size()), p->vbo_.data()); @@ -234,6 +241,14 @@ void PlacefileIcons::Initialize() static_cast(0)); gl.glEnableVertexAttribArray(5); + // aTimeRange + gl.glVertexAttribIPointer(6, // + 2, + GL_INT, + kIntegersPerVertex_ * sizeof(GLint), + reinterpret_cast(1 * sizeof(GLint))); + gl.glEnableVertexAttribArray(6); + p->dirty_ = true; } @@ -268,6 +283,17 @@ void PlacefileIcons::Render( gl.glUniform1f(p->uMapDistanceLocation_, 0.0f); } + // Selected time + std::chrono::system_clock::time_point selectedTime = + (p->selectedTime_ == std::chrono::system_clock::time_point {}) ? + std::chrono::system_clock::now() : + p->selectedTime_; + gl.glUniform1i( + p->uSelectedTimeLocation_, + static_cast(std::chrono::duration_cast( + selectedTime.time_since_epoch()) + .count())); + // Interpolate texture coordinates gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl.glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -290,7 +316,7 @@ void PlacefileIcons::Deinitialize() p->currentIconFiles_.clear(); p->currentHoverIcons_.clear(); p->currentIconBuffer_.clear(); - p->currentThresholdBuffer_.clear(); + p->currentIntegerBuffer_.clear(); p->textureBuffer_.clear(); } @@ -332,7 +358,7 @@ void PlacefileIcons::StartIcons() p->newValidIconList_.clear(); p->newIconFiles_.clear(); p->newIconBuffer_.clear(); - p->newThresholdBuffer_.clear(); + p->newIntegerBuffer_.clear(); p->newHoverIcons_.clear(); } @@ -376,7 +402,7 @@ void PlacefileIcons::FinishIcons() p->currentIconList_.swap(p->newValidIconList_); p->currentIconFiles_.swap(p->newIconFiles_); p->currentIconBuffer_.swap(p->newIconBuffer_); - p->currentThresholdBuffer_.swap(p->newThresholdBuffer_); + p->currentIntegerBuffer_.swap(p->newIntegerBuffer_); p->currentHoverIcons_.swap(p->newHoverIcons_); // Clear the new buffers @@ -384,7 +410,7 @@ void PlacefileIcons::FinishIcons() p->newValidIconList_.clear(); p->newIconFiles_.clear(); p->newIconBuffer_.clear(); - p->newThresholdBuffer_.clear(); + p->newIntegerBuffer_.clear(); p->newHoverIcons_.clear(); // Mark the draw item dirty @@ -395,8 +421,9 @@ void PlacefileIcons::Impl::UpdateBuffers() { newIconBuffer_.clear(); newIconBuffer_.reserve(newIconList_.size() * kIconBufferLength); - newThresholdBuffer_.clear(); - newThresholdBuffer_.reserve(newIconList_.size() * kVerticesPerRectangle); + newIntegerBuffer_.clear(); + newIntegerBuffer_.reserve(newIconList_.size() * kVerticesPerRectangle * + kIntegersPerVertex_); for (auto& di : newIconList_) { @@ -425,6 +452,16 @@ void PlacefileIcons::Impl::UpdateBuffers() units::length::nautical_miles threshold = di->threshold_; GLint thresholdValue = static_cast(std::round(threshold.value())); + // Start and end time + GLint startTime = + static_cast(std::chrono::duration_cast( + di->startTime_.time_since_epoch()) + .count()); + GLint endTime = + static_cast(std::chrono::duration_cast( + di->endTime_.time_since_epoch()) + .count()); + // Latitude and longitude coordinates in degrees const float lat = static_cast(di->latitude_); const float lon = static_cast(di->longitude_); @@ -467,13 +504,25 @@ void PlacefileIcons::Impl::UpdateBuffers() lat, lon, rx, ty, mc0, mc1, mc2, mc3, a, // TR lat, lon, lx, ty, mc0, mc1, mc2, mc3, a // TL }); - newThresholdBuffer_.insert(newThresholdBuffer_.end(), - {thresholdValue, // - thresholdValue, - thresholdValue, - thresholdValue, - thresholdValue, - thresholdValue}); + newIntegerBuffer_.insert(newIntegerBuffer_.end(), + {thresholdValue, + startTime, + endTime, + thresholdValue, + startTime, + endTime, + thresholdValue, + startTime, + endTime, + thresholdValue, + startTime, + endTime, + thresholdValue, + startTime, + endTime, + thresholdValue, + startTime, + endTime}); if (!di->hoverText_.empty()) { @@ -622,8 +671,8 @@ void PlacefileIcons::Impl::Update(bool textureAtlasChanged) // Buffer threshold data gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[2]); gl.glBufferData(GL_ARRAY_BUFFER, - sizeof(GLint) * currentThresholdBuffer_.size(), - currentThresholdBuffer_.data(), + sizeof(GLint) * currentIntegerBuffer_.size(), + currentIntegerBuffer_.data(), GL_DYNAMIC_DRAW); numVertices_ = static_cast(currentIconBuffer_.size() / @@ -656,24 +705,41 @@ bool PlacefileIcons::RunMousePicking( (p->thresholded_) ? util::maplibre::GetMapDistance(params) : units::length::meters {0.0}; + // If no time has been selected, use the current time + std::chrono::system_clock::time_point selectedTime = + (p->selectedTime_ == std::chrono::system_clock::time_point {}) ? + std::chrono::system_clock::now() : + p->selectedTime_; + // For each pickable icon auto it = std::find_if( std::execution::par_unseq, p->currentHoverIcons_.crbegin(), p->currentHoverIcons_.crend(), - [&mapDistance, &mapMatrix, &mousePos](const auto& icon) + [&mapDistance, &selectedTime, &mapMatrix, &mousePos](const auto& icon) { - if ( - // Placefile is thresholded - mapDistance > units::length::meters {0.0} && + if (( + // Placefile is thresholded + mapDistance > units::length::meters {0.0} && - // Placefile threshold is < 999 nmi - static_cast(std::round( - units::length::nautical_miles {icon.di_->threshold_} - .value())) < 999 && + // Placefile threshold is < 999 nmi + static_cast(std::round( + units::length::nautical_miles {icon.di_->threshold_} + .value())) < 999 && - // Map distance is beyond the threshold - icon.di_->threshold_ < mapDistance) + // Map distance is beyond the threshold + icon.di_->threshold_ < mapDistance) || + + ( + // Line has a start time + icon.di_->startTime_ != + std::chrono::system_clock::time_point {} && + + // The time range has not yet started + (selectedTime < icon.di_->startTime_ || + + // The time range has ended + icon.di_->endTime_ <= selectedTime))) { // Icon is not pickable return false;