From 77ba92ce7f5796ba289ec314ef99cad60f9ed25e Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 14 Nov 2021 00:25:17 -0600 Subject: [PATCH] Adding reflectivity declutter capability --- scwx-qt/gl/radar.frag | 8 +++ scwx-qt/gl/radar.vert | 3 + .../scwx/qt/map/radar_product_layer.cpp | 67 +++++++++++++++++-- .../scwx/qt/view/level2_product_view.cpp | 46 +++++++++++++ .../scwx/qt/view/level2_product_view.hpp | 1 + .../scwx/qt/view/radar_product_view.cpp | 10 +++ .../scwx/qt/view/radar_product_view.hpp | 1 + 7 files changed, 130 insertions(+), 6 deletions(-) diff --git a/scwx-qt/gl/radar.frag b/scwx-qt/gl/radar.frag index 81645061..0c605b8a 100644 --- a/scwx-qt/gl/radar.frag +++ b/scwx-qt/gl/radar.frag @@ -7,7 +7,10 @@ uniform sampler1D uTexture; uniform uint uDataMomentOffset; uniform float uDataMomentScale; +uniform bool uCFPEnabled; + flat in uint dataMoment; +flat in uint cfpMoment; layout (location = 0) out vec4 fragColor; @@ -15,5 +18,10 @@ void main() { float texCoord = float(dataMoment - uDataMomentOffset) / uDataMomentScale; + if (uCFPEnabled && cfpMoment > 8u) + { + texCoord = texCoord - float(cfpMoment - 8u) / 2.0f; + } + fragColor = texture(uTexture, texCoord); } diff --git a/scwx-qt/gl/radar.vert b/scwx-qt/gl/radar.vert index 8ea09c42..b4da9f17 100644 --- a/scwx-qt/gl/radar.vert +++ b/scwx-qt/gl/radar.vert @@ -8,11 +8,13 @@ layout (location = 0) in vec2 aLatLong; layout (location = 1) in uint aDataMoment; +layout (location = 2) in uint aCfpMoment; uniform mat4 uMVPMatrix; uniform vec2 uMapScreenCoord; flat out uint dataMoment; +flat out uint cfpMoment; vec2 latLngToScreenCoordinate(in vec2 latLng) { @@ -27,6 +29,7 @@ void main() { // Pass the coded data moment to the fragment shader dataMoment = aDataMoment; + cfpMoment = aCfpMoment; vec2 p = latLngToScreenCoordinate(aLatLong) - uMapScreenCoord; diff --git a/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp b/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp index 4abb5a1c..3e7a9530 100644 --- a/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp @@ -37,10 +37,14 @@ public: shaderProgram_(gl), uMVPMatrixLocation_(GL_INVALID_INDEX), uMapScreenCoordLocation_(GL_INVALID_INDEX), + uDataMomentOffsetLocation_(GL_INVALID_INDEX), + uDataMomentScaleLocation_(GL_INVALID_INDEX), + uCFPEnabledLocation_(GL_INVALID_INDEX), vbo_ {GL_INVALID_INDEX}, vao_ {GL_INVALID_INDEX}, texture_ {GL_INVALID_INDEX}, numVertices_ {0}, + cfpEnabled_ {false}, colorTableNeedsUpdate_ {false}, sweepNeedsUpdate_ {false} { @@ -55,12 +59,15 @@ public: GLint uMapScreenCoordLocation_; GLint uDataMomentOffsetLocation_; GLint uDataMomentScaleLocation_; - std::array vbo_; + GLint uCFPEnabledLocation_; + std::array vbo_; GLuint vao_; GLuint texture_; GLsizeiptr numVertices_; + bool cfpEnabled_; + bool colorTableNeedsUpdate_; bool sweepNeedsUpdate_; }; @@ -113,6 +120,13 @@ void RadarProductLayer::initialize() << logPrefix_ << "Could not find uDataMomentScale"; } + p->uCFPEnabledLocation_ = + gl.glGetUniformLocation(p->shaderProgram_.id(), "uCFPEnabled"); + if (p->uCFPEnabledLocation_ == -1) + { + BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Could not find uCFPEnabled"; + } + p->shaderProgram_.Use(); // Generate a vertex array object @@ -155,7 +169,7 @@ void RadarProductLayer::UpdateSweep() gl.glBindVertexArray(p->vao_); // Generate vertex buffer objects - gl.glGenBuffers(2, p->vbo_.data()); + gl.glGenBuffers(3, p->vbo_.data()); // Buffer vertices gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); @@ -199,6 +213,41 @@ void RadarProductLayer::UpdateSweep() gl.glVertexAttribIPointer(1, 1, type, 0, static_cast(0)); gl.glEnableVertexAttribArray(1); + // Buffer CFP data + const GLvoid* cfpData; + GLsizeiptr cfpDataSize; + size_t cfpComponentSize; + GLenum cfpType; + + std::tie(cfpData, cfpDataSize, cfpComponentSize) = + p->radarProductView_->GetCfpMomentData(); + + if (cfpData != nullptr) + { + if (cfpComponentSize == 1) + { + cfpType = GL_UNSIGNED_BYTE; + } + else + { + cfpType = GL_UNSIGNED_SHORT; + } + + gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[2]); + timer.start(); + gl.glBufferData(GL_ARRAY_BUFFER, cfpDataSize, cfpData, GL_STATIC_DRAW); + timer.stop(); + BOOST_LOG_TRIVIAL(debug) + << logPrefix_ << "CFP moments buffered in " << timer.format(6, "%ws"); + + gl.glVertexAttribIPointer(2, 1, cfpType, 0, static_cast(0)); + gl.glEnableVertexAttribArray(2); + } + else + { + gl.glDisableVertexAttribArray(2); + } + p->numVertices_ = vertices.size() / 2; } @@ -238,6 +287,8 @@ void RadarProductLayer::render( gl.glUniformMatrix4fv( p->uMVPMatrixLocation_, 1, GL_FALSE, glm::value_ptr(uMVPMatrix)); + gl.glUniform1i(p->uCFPEnabledLocation_, p->cfpEnabled_ ? 1 : 0); + gl.glActiveTexture(GL_TEXTURE0); gl.glBindTexture(GL_TEXTURE_1D, p->texture_); gl.glBindVertexArray(p->vao_); @@ -253,10 +304,14 @@ void RadarProductLayer::deinitialize() gl.glDeleteVertexArrays(1, &p->vao_); gl.glDeleteBuffers(2, p->vbo_.data()); - p->uMVPMatrixLocation_ = GL_INVALID_INDEX; - p->vao_ = GL_INVALID_INDEX; - p->vbo_ = {GL_INVALID_INDEX}; - p->texture_ = GL_INVALID_INDEX; + p->uMVPMatrixLocation_ = GL_INVALID_INDEX; + p->uMapScreenCoordLocation_ = GL_INVALID_INDEX; + p->uDataMomentOffsetLocation_ = GL_INVALID_INDEX; + p->uDataMomentScaleLocation_ = GL_INVALID_INDEX; + p->uCFPEnabledLocation_ = GL_INVALID_INDEX; + p->vao_ = GL_INVALID_INDEX; + p->vbo_ = {GL_INVALID_INDEX}; + p->texture_ = GL_INVALID_INDEX; disconnect(p->radarProductView_.get(), &view::RadarProductView::ColorTableUpdated, diff --git a/scwx-qt/source/scwx/qt/view/level2_product_view.cpp b/scwx-qt/source/scwx/qt/view/level2_product_view.cpp index cba3b24b..c5860aa9 100644 --- a/scwx-qt/source/scwx/qt/view/level2_product_view.cpp +++ b/scwx-qt/source/scwx/qt/view/level2_product_view.cpp @@ -76,6 +76,7 @@ public: std::vector vertices_; std::vector dataMoments8_; std::vector dataMoments16_; + std::vector cfpMoments_; float latitude_; float longitude_; @@ -151,6 +152,22 @@ std::tuple Level2ProductView::GetMomentData() const return std::tie(data, dataSize, componentSize); } +std::tuple +Level2ProductView::GetCfpMomentData() const +{ + const void* data = nullptr; + size_t dataSize = 0; + size_t componentSize = 1; + + if (p->cfpMoments_.size() > 0) + { + data = p->cfpMoments_.data(); + dataSize = p->cfpMoments_.size() * sizeof(uint8_t); + } + + return std::tie(data, dataSize, componentSize); +} + void Level2ProductView::LoadColorTable( std::shared_ptr colorTable) { @@ -297,6 +314,7 @@ void Level2ProductView::ComputeSweep() // Setup data moment vector std::vector& dataMoments8 = p->dataMoments8_; std::vector& dataMoments16 = p->dataMoments16_; + std::vector& cfpMoments = p->cfpMoments_; size_t mIndex = 0; if (momentData0->data_word_size() == 8) @@ -314,6 +332,16 @@ void Level2ProductView::ComputeSweep() dataMoments16.resize(radials * gates * VERTICES_PER_BIN); } + if (p->dataBlockType_ == wsr88d::rda::DataBlockType::MomentRef) + { + cfpMoments.resize(radials * gates * VERTICES_PER_BIN); + } + else + { + cfpMoments.resize(0); + cfpMoments.shrink_to_fit(); + } + // Compute threshold at which to display an individual bin const float scale = momentData0->scale(); const float offset = momentData0->offset(); @@ -361,6 +389,7 @@ void Level2ProductView::ComputeSweep() const uint8_t* dataMomentsArray8 = nullptr; const uint16_t* dataMomentsArray16 = nullptr; + const uint8_t* cfpMomentsArray = nullptr; if (momentData->data_word_size() == 8) { @@ -373,6 +402,13 @@ void Level2ProductView::ComputeSweep() reinterpret_cast(momentData->data_moments()); } + if (cfpMoments.size() > 0) + { + cfpMomentsArray = reinterpret_cast( + radialData->moment_data_block(wsr88d::rda::DataBlockType::MomentCfp) + ->data_moments()); + } + for (uint16_t gate = startGate, i = 0; gate + gateSize <= endGate; gate += gateSize, ++i) { @@ -390,6 +426,11 @@ void Level2ProductView::ComputeSweep() for (size_t m = 0; m < vertexCount; m++) { dataMoments8[mIndex++] = dataMomentsArray8[i]; + + if (cfpMomentsArray != nullptr) + { + cfpMoments[mIndex - 1] = cfpMomentsArray[i]; + } } } else @@ -481,6 +522,11 @@ void Level2ProductView::ComputeSweep() dataMoments16.resize(mIndex); } + if (cfpMoments.size() > 0) + { + cfpMoments.resize(mIndex); + } + timer.stop(); BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Vertices calculated in " << timer.format(6, "%ws"); diff --git a/scwx-qt/source/scwx/qt/view/level2_product_view.hpp b/scwx-qt/source/scwx/qt/view/level2_product_view.hpp index d8a2808b..7e48b4f9 100644 --- a/scwx-qt/source/scwx/qt/view/level2_product_view.hpp +++ b/scwx-qt/source/scwx/qt/view/level2_product_view.hpp @@ -36,6 +36,7 @@ public: void LoadColorTable(std::shared_ptr colorTable) override; std::tuple GetMomentData() const override; + std::tuple GetCfpMomentData() const override; static std::shared_ptr Create(common::Level2Product product, diff --git a/scwx-qt/source/scwx/qt/view/radar_product_view.cpp b/scwx-qt/source/scwx/qt/view/radar_product_view.cpp index 7bff5ea2..0e892f34 100644 --- a/scwx-qt/source/scwx/qt/view/radar_product_view.cpp +++ b/scwx-qt/source/scwx/qt/view/radar_product_view.cpp @@ -50,6 +50,16 @@ void RadarProductView::Initialize() ComputeSweep(); } +std::tuple +RadarProductView::GetCfpMomentData() const +{ + const void* data = nullptr; + size_t dataSize = 0; + size_t componentSize = 0; + + return std::tie(data, dataSize, componentSize); +} + void RadarProductView::ComputeSweep() { BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "ComputeSweep()"; diff --git a/scwx-qt/source/scwx/qt/view/radar_product_view.hpp b/scwx-qt/source/scwx/qt/view/radar_product_view.hpp index 589f19c9..63d8b240 100644 --- a/scwx-qt/source/scwx/qt/view/radar_product_view.hpp +++ b/scwx-qt/source/scwx/qt/view/radar_product_view.hpp @@ -35,6 +35,7 @@ public: LoadColorTable(std::shared_ptr colorTable) = 0; virtual std::tuple GetMomentData() const = 0; + virtual std::tuple GetCfpMomentData() const; protected: virtual void UpdateColorTable() = 0;