diff --git a/scwx-qt/gl/geo_texture2d.vert b/scwx-qt/gl/geo_texture2d.vert index ee93a12a..7977af95 100644 --- a/scwx-qt/gl/geo_texture2d.vert +++ b/scwx-qt/gl/geo_texture2d.vert @@ -13,6 +13,7 @@ layout (location = 2) in vec3 aTexCoord; layout (location = 3) in vec4 aModulate; layout (location = 4) in float aAngleDeg; layout (location = 5) in int aThreshold; +layout (location = 6) in ivec2 aTimeRange; uniform mat4 uMVPMatrix; uniform mat4 uMapMatrix; @@ -20,9 +21,10 @@ uniform vec2 uMapScreenCoord; out VertexData { - int threshold; - vec3 texCoord; - vec4 color; + int threshold; + vec3 texCoord; + vec4 color; + ivec2 timeRange; } vsOut; smooth out vec3 texCoord; @@ -39,8 +41,9 @@ vec2 latLngToScreenCoordinate(in vec2 latLng) void main() { - // Pass the threshold to the geometry shader + // Pass the threshold and time range to the geometry shader vsOut.threshold = aThreshold; + vsOut.timeRange = aTimeRange; // Pass the texture coordinate and color modulate to the geometry and // fragment shaders diff --git a/scwx-qt/gl/map_color.vert b/scwx-qt/gl/map_color.vert index b2749a02..4319310f 100644 --- a/scwx-qt/gl/map_color.vert +++ b/scwx-qt/gl/map_color.vert @@ -1,9 +1,10 @@ #version 330 core -layout (location = 0) in vec2 aScreenCoord; -layout (location = 1) in vec2 aXYOffset; -layout (location = 2) in vec4 aColor; -layout (location = 3) in int aThreshold; +layout (location = 0) in vec2 aScreenCoord; +layout (location = 1) in vec2 aXYOffset; +layout (location = 2) in vec4 aColor; +layout (location = 3) in int aThreshold; +layout (location = 4) in ivec2 aTimeRange; uniform mat4 uMVPMatrix; uniform mat4 uMapMatrix; @@ -11,17 +12,19 @@ uniform vec2 uMapScreenCoord; out VertexData { - int threshold; - vec3 texCoord; - vec4 color; + int threshold; + vec3 texCoord; + vec4 color; + ivec2 timeRange; } vsOut; smooth out vec4 color; void main() { - // Pass the threshold and color to the geometry shader + // Pass the threshold and time range to the geometry shader vsOut.threshold = aThreshold; + vsOut.timeRange = aTimeRange; // Pass the color to the geometry and fragment shaders vsOut.color = aColor; diff --git a/scwx-qt/gl/threshold.geom b/scwx-qt/gl/threshold.geom index 1f64b368..dec09b01 100644 --- a/scwx-qt/gl/threshold.geom +++ b/scwx-qt/gl/threshold.geom @@ -4,12 +4,14 @@ layout (triangles) in; layout (triangle_strip, max_vertices = 3) out; uniform float uMapDistance; +uniform int uSelectedTime; in VertexData { - int threshold; - vec3 texCoord; - vec4 color; + int threshold; + vec3 texCoord; + vec4 color; + ivec2 timeRange; } gsIn[]; smooth out vec3 texCoord; @@ -17,9 +19,12 @@ smooth out vec4 color; void main() { - if (gsIn[0].threshold <= 0 || // If Threshold: 0 was specified, no threshold - gsIn[0].threshold >= uMapDistance || // If Threshold is above current map distance - gsIn[0].threshold >= 999) // If Threshold: 999 was specified (or greater), no threshold + if ((gsIn[0].threshold <= 0 || // If Threshold: 0 was specified, no threshold + gsIn[0].threshold >= uMapDistance || // If Threshold is above current map distance + gsIn[0].threshold >= 999) && // If Threshold: 999 was specified (or greater), no threshold + (gsIn[0].timeRange[0] == 0 || // If there is no start time specified + (gsIn[0].timeRange[0] <= uSelectedTime && // If the selected time is after the start time + uSelectedTime < gsIn[0].timeRange[1]))) // If the selected time is before the end time { gl_Position = gl_in[0].gl_Position; texCoord = gsIn[0].texCoord; diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_polygons.cpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_polygons.cpp index 5fa0c6ac..24a96fe6 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_polygons.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_polygons.cpp @@ -26,6 +26,9 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_); static constexpr std::size_t kVerticesPerTriangle = 3; static constexpr std::size_t kPointsPerVertex = 8; +// Threshold, start time, end time +static constexpr std::size_t kIntegersPerVertex_ = 3; + static constexpr std::size_t kTessVertexScreenX_ = 0; static constexpr std::size_t kTessVertexScreenY_ = 1; static constexpr std::size_t kTessVertexScreenZ_ = 2; @@ -49,6 +52,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} @@ -97,9 +101,9 @@ public: std::mutex bufferMutex_ {}; std::vector currentBuffer_ {}; - std::vector currentThresholdBuffer_ {}; + std::vector currentIntegerBuffer_ {}; std::vector newBuffer_ {}; - std::vector newThresholdBuffer_ {}; + std::vector newIntegerBuffer_ {}; GLUtesselator* tessellator_; @@ -108,13 +112,16 @@ public: GLint uMapMatrixLocation_; GLint uMapScreenCoordLocation_; GLint uMapDistanceLocation_; + GLint uSelectedTimeLocation_; GLuint vao_; std::array vbo_; GLsizei numVertices_; - GLint currentThreshold_; + GLint currentThreshold_ {}; + GLint currentStartTime_ {}; + GLint currentEndTime_ {}; }; PlacefilePolygons::PlacefilePolygons( @@ -154,6 +161,8 @@ void PlacefilePolygons::Initialize() p->shaderProgram_->GetUniformLocation("uMapScreenCoord"); p->uMapDistanceLocation_ = p->shaderProgram_->GetUniformLocation("uMapDistance"); + p->uSelectedTimeLocation_ = + p->shaderProgram_->GetUniformLocation("uSelectedTime"); gl.glGenVertexArrays(1, &p->vao_); gl.glGenBuffers(2, p->vbo_.data()); @@ -196,10 +205,18 @@ void PlacefilePolygons::Initialize() gl.glVertexAttribIPointer(3, // 1, GL_INT, - 0, + kIntegersPerVertex_ * sizeof(GLint), static_cast(0)); gl.glEnableVertexAttribArray(3); + // aTimeRange + gl.glVertexAttribIPointer(4, // + 2, + GL_INT, + kIntegersPerVertex_ * sizeof(GLint), + reinterpret_cast(1 * sizeof(GLint))); + gl.glEnableVertexAttribArray(4); + p->dirty_ = true; } @@ -231,6 +248,17 @@ void PlacefilePolygons::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())); + // Draw icons gl.glDrawArrays(GL_TRIANGLES, 0, p->numVertices_); } @@ -247,14 +275,14 @@ void PlacefilePolygons::Deinitialize() // Clear the current buffers p->currentBuffer_.clear(); - p->currentThresholdBuffer_.clear(); + p->currentIntegerBuffer_.clear(); } void PlacefilePolygons::StartPolygons() { // Clear the new buffers p->newBuffer_.clear(); - p->newThresholdBuffer_.clear(); + p->newIntegerBuffer_.clear(); } void PlacefilePolygons::AddPolygon( @@ -272,11 +300,11 @@ void PlacefilePolygons::FinishPolygons() // Swap buffers p->currentBuffer_.swap(p->newBuffer_); - p->currentThresholdBuffer_.swap(p->newThresholdBuffer_); + p->currentIntegerBuffer_.swap(p->newIntegerBuffer_); // Clear the new buffers p->newBuffer_.clear(); - p->newThresholdBuffer_.clear(); + p->newIntegerBuffer_.clear(); // Mark the draw item dirty p->dirty_ = true; @@ -300,8 +328,8 @@ void PlacefilePolygons::Impl::Update() // Buffer threshold data gl.glBindBuffer(GL_ARRAY_BUFFER, vbo_[1]); gl.glBufferData(GL_ARRAY_BUFFER, - sizeof(GLint) * currentThresholdBuffer_.size(), - currentThresholdBuffer_.data(), + sizeof(GLint) * currentIntegerBuffer_.size(), + currentIntegerBuffer_.data(), GL_DYNAMIC_DRAW); numVertices_ = @@ -324,6 +352,16 @@ void PlacefilePolygons::Impl::Tessellate( units::length::nautical_miles threshold = di->threshold_; currentThreshold_ = static_cast(std::round(threshold.value())); + // Start and end time + currentStartTime_ = + static_cast(std::chrono::duration_cast( + di->startTime_.time_since_epoch()) + .count()); + currentEndTime_ = + static_cast(std::chrono::duration_cast( + di->endTime_.time_since_epoch()) + .count()); + gluTessBeginPolygon(tessellator_, this); for (auto& contour : di->contours_) @@ -370,7 +408,7 @@ void PlacefilePolygons::Impl::Tessellate( while (newBuffer_.size() % kVerticesPerTriangle != 0) { newBuffer_.pop_back(); - newThresholdBuffer_.pop_back(); + newIntegerBuffer_.pop_back(); } } @@ -431,7 +469,10 @@ void PlacefilePolygons::Impl::TessellateVertexCallback(void* vertexData, static_cast(data[kTessVertexG_]), static_cast(data[kTessVertexB_]), static_cast(data[kTessVertexA_])}); - self->newThresholdBuffer_.push_back(self->currentThreshold_); + self->newIntegerBuffer_.insert(self->newIntegerBuffer_.end(), + {self->currentThreshold_, + self->currentStartTime_, + self->currentEndTime_}); } void PlacefilePolygons::Impl::TessellateErrorCallback(GLenum errorCode)