From bee167764a5c77c9ead044ce8edb3dd39266517f Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 24 Sep 2022 16:02:15 -0500 Subject: [PATCH 01/24] Add geo line shaders --- scwx-qt/gl/geo_line.vert | 39 +++++++++++++++++++++++++++++++++++++++ scwx-qt/gl/texture2d.frag | 16 ++++++++++++++++ scwx-qt/scwx-qt.cmake | 4 +++- scwx-qt/scwx-qt.qrc | 2 ++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 scwx-qt/gl/geo_line.vert create mode 100644 scwx-qt/gl/texture2d.frag diff --git a/scwx-qt/gl/geo_line.vert b/scwx-qt/gl/geo_line.vert new file mode 100644 index 00000000..e232df95 --- /dev/null +++ b/scwx-qt/gl/geo_line.vert @@ -0,0 +1,39 @@ +#version 330 core + +#define DEGREES_MAX 360.0f +#define LATITUDE_MAX 85.051128779806604f +#define LONGITUDE_MAX 180.0f +#define PI 3.1415926535897932384626433f +#define RAD2DEG 57.295779513082320876798156332941f + +layout (location = 0) in vec2 aLatLong; +layout (location = 1) in vec2 aXYOffset; +layout (location = 2) in vec2 aTexCoord; +layout (location = 3) in vec4 aModulate; + +uniform mat4 uMVPMatrix; +uniform vec2 uMapScreenCoord; + +flat out vec2 texCoord; +flat out vec4 modulate; + +vec2 latLngToScreenCoordinate(in vec2 latLng) +{ + vec2 p; + latLng.x = clamp(latLng.x, -LATITUDE_MAX, LATITUDE_MAX); + p.xy = vec2(LONGITUDE_MAX + latLng.y, + -(LONGITUDE_MAX - RAD2DEG * log(tan(PI / 4 + latLng.x * PI / DEGREES_MAX)))); + return p; +} + +void main() +{ + // Pass the texture coordinate and color modulate to the fragment shader + texCoord = aTexCoord; + modulate = aModulate; + + vec2 p = latLngToScreenCoordinate(aLatLong) + aXYOffset - uMapScreenCoord; + + // Transform the position to screen coordinates + gl_Position = uMVPMatrix * vec4(p, 0.0f, 1.0f); +} diff --git a/scwx-qt/gl/texture2d.frag b/scwx-qt/gl/texture2d.frag new file mode 100644 index 00000000..3a41c720 --- /dev/null +++ b/scwx-qt/gl/texture2d.frag @@ -0,0 +1,16 @@ +#version 330 core + +// Lower the default precision to medium +precision mediump float; + +uniform sampler2D uTexture; + +flat in vec2 texCoord; +flat in vec4 modulate; + +layout (location = 0) out vec4 fragColor; + +void main() +{ + fragColor = texture(uTexture, texCoord) * modulate; +} diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 00abbaf4..90d3c574 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -122,12 +122,14 @@ set(RESOURCE_FILES scwx-qt.qrc) set(SHADER_FILES gl/color.frag gl/color.vert + gl/geo_line.vert gl/radar.frag gl/radar.vert gl/text.frag gl/text.vert gl/texture1d.frag - gl/texture1d.vert) + gl/texture1d.vert + gl/texture2d.frag) set(CMAKE_FILES scwx-qt.cmake) diff --git a/scwx-qt/scwx-qt.qrc b/scwx-qt/scwx-qt.qrc index d3386855..bf64e1fd 100644 --- a/scwx-qt/scwx-qt.qrc +++ b/scwx-qt/scwx-qt.qrc @@ -2,12 +2,14 @@ gl/color.frag gl/color.vert + gl/geo_line.vert gl/radar.frag gl/radar.vert gl/text.frag gl/text.vert gl/texture1d.frag gl/texture1d.vert + gl/texture2d.frag res/config/radar_sites.json res/fonts/din1451alt.ttf res/fonts/din1451alt_g.ttf From 7a07e0f698670281e7faac730db6261b263f1144 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 24 Sep 2022 16:12:30 -0500 Subject: [PATCH 02/24] Untested geo line implementation without texture --- scwx-qt/scwx-qt.cmake | 2 + scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp | 241 ++++++++++++++++++++ scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp | 77 +++++++ wxdata/include/scwx/common/geographic.hpp | 2 + 4 files changed, 322 insertions(+) create mode 100644 scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp create mode 100644 scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 90d3c574..535151d7 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -46,8 +46,10 @@ set(HDR_GL source/scwx/qt/gl/gl.hpp set(SRC_GL source/scwx/qt/gl/shader_program.cpp source/scwx/qt/gl/text_shader.cpp) set(HDR_GL_DRAW source/scwx/qt/gl/draw/draw_item.hpp + source/scwx/qt/gl/draw/geo_line.hpp source/scwx/qt/gl/draw/rectangle.hpp) set(SRC_GL_DRAW source/scwx/qt/gl/draw/draw_item.cpp + source/scwx/qt/gl/draw/geo_line.cpp source/scwx/qt/gl/draw/rectangle.cpp) set(HDR_MANAGER source/scwx/qt/manager/radar_product_manager.hpp source/scwx/qt/manager/radar_product_manager_notifier.hpp diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp new file mode 100644 index 00000000..7834022f --- /dev/null +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp @@ -0,0 +1,241 @@ +#include +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace gl +{ +namespace draw +{ + +static const std::string logPrefix_ = "scwx::qt::gl::draw::geo_line"; + +static constexpr size_t kNumRectangles = 1; +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 = 10; +static constexpr size_t kBufferLength = + kNumTriangles * kVerticesPerTriangle * kPointsPerVertex; + +class GeoLine::Impl +{ +public: + explicit Impl(OpenGLFunctions& gl) : + gl_ {gl}, + dirty_ {false}, + visible_ {true}, + points_ {}, + width_ {1.0f}, + modulateColor_ {std::nullopt}, + vao_ {GL_INVALID_INDEX}, + vbo_ {GL_INVALID_INDEX} + { + } + + ~Impl() {} + + OpenGLFunctions& gl_; + + bool dirty_; + + bool visible_; + std::array points_; + float width_; + + std::optional modulateColor_; + + // TODO: Texture + + GLuint vao_; + GLuint vbo_; + + void Update(); +}; + +// TODO: OpenGL context with shaders +GeoLine::GeoLine(OpenGLFunctions& gl) : + DrawItem(), p(std::make_unique(gl)) +{ +} +GeoLine::~GeoLine() = default; + +GeoLine::GeoLine(GeoLine&&) noexcept = default; +GeoLine& GeoLine::operator=(GeoLine&&) noexcept = default; + +void GeoLine::Initialize() +{ + gl::OpenGLFunctions& gl = p->gl_; + + gl.glGenVertexArrays(1, &p->vao_); + gl.glGenBuffers(1, &p->vbo_); + + gl.glBindVertexArray(p->vao_); + gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_); + gl.glBufferData( + GL_ARRAY_BUFFER, sizeof(float) * kBufferLength, nullptr, GL_DYNAMIC_DRAW); + + // aLatLong + gl.glVertexAttribPointer(0, + 2, + GL_FLOAT, + GL_FALSE, + kPointsPerVertex * sizeof(float), + static_cast(0)); + gl.glEnableVertexAttribArray(0); + + // aXYOffset + gl.glVertexAttribPointer(1, + 2, + GL_FLOAT, + GL_FALSE, + kPointsPerVertex * sizeof(float), + reinterpret_cast(2 * sizeof(float))); + gl.glEnableVertexAttribArray(1); + + // aTexCoord + gl.glVertexAttribPointer(2, + 2, + GL_FLOAT, + GL_FALSE, + kPointsPerVertex * sizeof(float), + reinterpret_cast(4 * sizeof(float))); + gl.glEnableVertexAttribArray(2); + + // aModulate + gl.glVertexAttribPointer(3, + 4, + GL_FLOAT, + GL_FALSE, + kPointsPerVertex * sizeof(float), + reinterpret_cast(6 * sizeof(float))); + gl.glEnableVertexAttribArray(3); + + p->dirty_ = true; +} + +void GeoLine::Render() +{ + if (p->visible_) + { + gl::OpenGLFunctions& gl = p->gl_; + + gl.glBindVertexArray(p->vao_); + gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_); + + p->Update(); + + // Draw line + gl.glDrawArrays(GL_TRIANGLES, 0, 6); + } +} + +void GeoLine::Deinitialize() +{ + gl::OpenGLFunctions& gl = p->gl_; + + gl.glDeleteVertexArrays(1, &p->vao_); + gl.glDeleteBuffers(1, &p->vbo_); +} + +void GeoLine::SetPoints(float latitude1, + float longitude1, + float latitude2, + float longitude2) +{ + if (p->points_[0].latitude_ != latitude1 || + p->points_[0].longitude_ != longitude1 || + p->points_[1].latitude_ != latitude2 || + p->points_[1].longitude_ != longitude2) + { + p->points_[0] = {latitude1, longitude1}; + p->points_[1] = {latitude2, longitude2}; + p->dirty_ = true; + } +} + +void GeoLine::SetModulateColor(boost::gil::rgba8_pixel_t color) +{ + if (p->modulateColor_ != color) + { + p->modulateColor_ = color; + p->dirty_ = true; + } +} + +void GeoLine::SetWidth(float width) +{ + if (p->width_ != width) + { + p->width_ = width; + p->dirty_ = true; + } +} + +void GeoLine::SetVisible(bool visible) +{ + p->visible_ = visible; +} + +void GeoLine::Impl::Update() +{ + if (dirty_) + { + gl::OpenGLFunctions& gl = gl_; + + const float lx = points_[0].latitude_; + const float rx = points_[1].latitude_; + const float by = points_[0].longitude_; + const float ty = points_[1].longitude_; + + const double i = points_[1].longitude_ - points_[0].longitude_; + const double j = points_[1].latitude_ - points_[0].latitude_; + const double angle = std::atan2(i, j) * 180.0 / M_PI; + const float ox = width_ * 0.5f * std::cosf(angle); + const float oy = width_ * 0.5f * std::sinf(angle); + + float mc0 = 1.0f; + float mc1 = 1.0f; + float mc2 = 1.0f; + float mc3 = 1.0f; + + if (modulateColor_.has_value()) + { + boost::gil::rgba8_pixel_t& mc = modulateColor_.value(); + + mc0 = mc[0] / 255.0f; + mc1 = mc[1] / 255.0f; + mc2 = mc[2] / 255.0f; + mc3 = mc[3] / 255.0f; + } + + const float buffer[kNumRectangles][kVerticesPerRectangle] + [kPointsPerVertex] = // + { // + // Line + { + {lx, by, -ox, -oy, 0.0f, 0.0f, mc0, mc1, mc2, mc3}, // BL + {lx, by, +ox, +oy, 0.0f, 1.0f, mc0, mc1, mc2, mc3}, // TL + {rx, ty, -ox, -oy, 1.0f, 0.0f, mc0, mc1, mc2, mc3}, // BR + {rx, ty, -ox, -oy, 1.0f, 0.0f, mc0, mc1, mc2, mc3}, // BR + {rx, ty, +ox, +oy, 1.0f, 1.0f, mc0, mc1, mc2, mc3}, // TR + {lx, by, +ox, +oy, 0.0f, 1.0f, mc0, mc1, mc2, mc3} // TL + }}; + + gl.glBufferData(GL_ARRAY_BUFFER, + sizeof(float) * kBufferLength, + buffer, + GL_DYNAMIC_DRAW); + + dirty_ = false; + } +} + +} // namespace draw +} // namespace gl +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp b/scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp new file mode 100644 index 00000000..a1b6ec8f --- /dev/null +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace gl +{ +namespace draw +{ + +class GeoLine : public DrawItem +{ +public: + explicit GeoLine(OpenGLFunctions& gl); + ~GeoLine(); + + GeoLine(const GeoLine&) = delete; + GeoLine& operator=(const GeoLine&) = delete; + + GeoLine(GeoLine&&) noexcept; + GeoLine& operator=(GeoLine&&) noexcept; + + void Initialize() override; + void Render() override; + void Deinitialize() override; + + /** + * Sets the geographic coordinate endpoints associated with the line. + * + * @param latitude1 Latitude of the first endpoint in degrees + * @param longitude1 Longitude of the first endpoint in degrees + * @param latitude2 Latitude of the second endpoint in degrees + * @param longitude2 Longitude of the second endpoint in degrees + */ + void SetPoints(float latitude1, + float longitude1, + float latitude2, + float longitude2); + + /** + * Sets the modulate color of the line. If specified, the texture color will + * be multiplied by the modulate color to produce the result. + * + * @param color Modulate color (RGBA) + */ + void SetModulateColor(boost::gil::rgba8_pixel_t color); + + /** + * Sets the width of the line. + * + * @param width Width in pixels + */ + void SetWidth(float width); + + /** + * Sets the visibility of the line. + * + * @param visible + */ + void SetVisible(bool visible); + +private: + class Impl; + + std::unique_ptr p; +}; + +} // namespace draw +} // namespace gl +} // namespace qt +} // namespace scwx diff --git a/wxdata/include/scwx/common/geographic.hpp b/wxdata/include/scwx/common/geographic.hpp index 639114f0..66a9233f 100644 --- a/wxdata/include/scwx/common/geographic.hpp +++ b/wxdata/include/scwx/common/geographic.hpp @@ -13,6 +13,8 @@ struct Coordinate double latitude_; ///< Latitude in degrees double longitude_; ///< Longitude in degrees + Coordinate() : Coordinate(0.0, 0.0) {} + Coordinate(double latitude, double longitude) : latitude_ {latitude}, longitude_ {longitude} { From 8d2fcf38025cfc98885bc3892aa1ed6321dee91b Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 2 Oct 2022 22:28:56 -0500 Subject: [PATCH 03/24] Shader program cleanup --- scwx-qt/source/scwx/qt/gl/shader_program.cpp | 22 +++++++++----------- scwx-qt/source/scwx/qt/gl/shader_program.hpp | 8 +++---- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/scwx-qt/source/scwx/qt/gl/shader_program.cpp b/scwx-qt/source/scwx/qt/gl/shader_program.cpp index bbf0a73b..1d9e2143 100644 --- a/scwx-qt/source/scwx/qt/gl/shader_program.cpp +++ b/scwx-qt/source/scwx/qt/gl/shader_program.cpp @@ -13,19 +13,18 @@ namespace gl static const std::string logPrefix_ = "scwx::qt::gl::shader_program"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); -static constexpr GLsizei INFO_LOG_BUF_SIZE = 512; +static constexpr GLsizei kInfoLogBufSize = 512; -class ShaderProgramImpl +class ShaderProgram::Impl { public: - explicit ShaderProgramImpl(OpenGLFunctions& gl) : - gl_(gl), id_ {GL_INVALID_INDEX} + explicit Impl(OpenGLFunctions& gl) : gl_(gl), id_ {GL_INVALID_INDEX} { // Create shader program id_ = gl_.glCreateProgram(); } - ~ShaderProgramImpl() + ~Impl() { // Delete shader program gl_.glDeleteProgram(id_); @@ -37,12 +36,12 @@ public: }; ShaderProgram::ShaderProgram(OpenGLFunctions& gl) : - p(std::make_unique(gl)) + p(std::make_unique(gl)) { } ShaderProgram::~ShaderProgram() = default; -ShaderProgram::ShaderProgram(ShaderProgram&&) noexcept = default; +ShaderProgram::ShaderProgram(ShaderProgram&&) noexcept = default; ShaderProgram& ShaderProgram::operator=(ShaderProgram&&) noexcept = default; GLuint ShaderProgram::id() const @@ -59,7 +58,7 @@ bool ShaderProgram::Load(const std::string& vertexPath, GLint glSuccess; bool success = true; - char infoLog[INFO_LOG_BUF_SIZE]; + char infoLog[kInfoLogBufSize]; GLsizei logLength; QFile vertexFile(vertexPath.c_str()); @@ -102,7 +101,7 @@ bool ShaderProgram::Load(const std::string& vertexPath, // Check for errors gl.glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &glSuccess); - gl.glGetShaderInfoLog(vertexShader, INFO_LOG_BUF_SIZE, &logLength, infoLog); + gl.glGetShaderInfoLog(vertexShader, kInfoLogBufSize, &logLength, infoLog); if (!glSuccess) { logger_->error("Vertex shader compilation failed: {}", infoLog); @@ -122,8 +121,7 @@ bool ShaderProgram::Load(const std::string& vertexPath, // Check for errors gl.glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &glSuccess); - gl.glGetShaderInfoLog( - fragmentShader, INFO_LOG_BUF_SIZE, &logLength, infoLog); + gl.glGetShaderInfoLog(fragmentShader, kInfoLogBufSize, &logLength, infoLog); if (!glSuccess) { logger_->error("Fragment shader compilation failed: {}", infoLog); @@ -142,7 +140,7 @@ bool ShaderProgram::Load(const std::string& vertexPath, // Check for errors gl.glGetProgramiv(p->id_, GL_LINK_STATUS, &glSuccess); - gl.glGetProgramInfoLog(p->id_, INFO_LOG_BUF_SIZE, &logLength, infoLog); + gl.glGetProgramInfoLog(p->id_, kInfoLogBufSize, &logLength, infoLog); if (!glSuccess) { logger_->error("Shader program link failed: {}", infoLog); diff --git a/scwx-qt/source/scwx/qt/gl/shader_program.hpp b/scwx-qt/source/scwx/qt/gl/shader_program.hpp index 386cb627..9f84053e 100644 --- a/scwx-qt/source/scwx/qt/gl/shader_program.hpp +++ b/scwx-qt/source/scwx/qt/gl/shader_program.hpp @@ -16,15 +16,13 @@ namespace qt namespace gl { -class ShaderProgramImpl; - class ShaderProgram { public: explicit ShaderProgram(OpenGLFunctions& gl); virtual ~ShaderProgram(); - ShaderProgram(const ShaderProgram&) = delete; + ShaderProgram(const ShaderProgram&) = delete; ShaderProgram& operator=(const ShaderProgram&) = delete; ShaderProgram(ShaderProgram&&) noexcept; @@ -37,7 +35,9 @@ public: void Use() const; private: - std::unique_ptr p; + class Impl; + + std::unique_ptr p; }; } // namespace gl From 32e8ca72a05ba336ab561608c0abe054c9b6e825 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 2 Oct 2022 23:12:41 -0500 Subject: [PATCH 04/24] Hash utility --- wxdata/include/scwx/util/hash.hpp | 21 +++++++++++++++++++++ wxdata/source/scwx/util/hash.cpp | 20 ++++++++++++++++++++ wxdata/wxdata.cmake | 2 ++ 3 files changed, 43 insertions(+) create mode 100644 wxdata/include/scwx/util/hash.hpp create mode 100644 wxdata/source/scwx/util/hash.cpp diff --git a/wxdata/include/scwx/util/hash.hpp b/wxdata/include/scwx/util/hash.hpp new file mode 100644 index 00000000..6559b6a4 --- /dev/null +++ b/wxdata/include/scwx/util/hash.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace scwx +{ +namespace util +{ + +template +struct hash; + +template<> +struct hash> +{ + size_t operator()(const std::pair& x) const; +}; + +} // namespace util +} // namespace scwx diff --git a/wxdata/source/scwx/util/hash.cpp b/wxdata/source/scwx/util/hash.cpp new file mode 100644 index 00000000..31d928a4 --- /dev/null +++ b/wxdata/source/scwx/util/hash.cpp @@ -0,0 +1,20 @@ +#include + +#include + +namespace scwx +{ +namespace util +{ + +size_t hash>::operator()( + const std::pair& x) const +{ + size_t seed = 0; + boost::hash_combine(seed, x.first); + boost::hash_combine(seed, x.second); + return seed; +} + +} // namespace util +} // namespace scwx diff --git a/wxdata/wxdata.cmake b/wxdata/wxdata.cmake index 4adbc60d..de57a39b 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -46,6 +46,7 @@ set(SRC_PROVIDER source/scwx/provider/aws_level2_data_provider.cpp source/scwx/provider/nexrad_data_provider_factory.cpp) set(HDR_UTIL include/scwx/util/environment.hpp include/scwx/util/float.hpp + include/scwx/util/hash.hpp include/scwx/util/iterator.hpp include/scwx/util/logger.hpp include/scwx/util/map.hpp @@ -56,6 +57,7 @@ set(HDR_UTIL include/scwx/util/environment.hpp include/scwx/util/vectorbuf.hpp) set(SRC_UTIL source/scwx/util/environment.cpp source/scwx/util/float.cpp + source/scwx/util/hash.cpp source/scwx/util/logger.cpp source/scwx/util/rangebuf.cpp source/scwx/util/streams.cpp From a45e99687228d6115b214a8f5eb42ac658d1132e Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 2 Oct 2022 23:16:35 -0500 Subject: [PATCH 05/24] Create shader programs through map context in order to cache programs through re-initialization --- scwx-qt/scwx-qt.cmake | 1 + scwx-qt/source/scwx/qt/gl/text_shader.cpp | 32 +++-- scwx-qt/source/scwx/qt/gl/text_shader.hpp | 8 +- .../source/scwx/qt/map/color_table_layer.cpp | 34 ++--- scwx-qt/source/scwx/qt/map/draw_layer.cpp | 26 ++-- scwx-qt/source/scwx/qt/map/map_context.cpp | 131 ++++++++++++++++++ scwx-qt/source/scwx/qt/map/map_context.hpp | 49 ++++--- scwx-qt/source/scwx/qt/map/map_widget.cpp | 106 ++++++++------ scwx-qt/source/scwx/qt/map/overlay_layer.cpp | 40 +++--- .../scwx/qt/map/radar_product_layer.cpp | 41 +++--- 10 files changed, 324 insertions(+), 144 deletions(-) create mode 100644 scwx-qt/source/scwx/qt/map/map_context.cpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 535151d7..d3c2b421 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -73,6 +73,7 @@ set(SRC_MAP source/scwx/qt/map/color_table_layer.cpp source/scwx/qt/map/draw_layer.cpp source/scwx/qt/map/generic_layer.cpp source/scwx/qt/map/layer_wrapper.cpp + source/scwx/qt/map/map_context.cpp source/scwx/qt/map/map_widget.cpp source/scwx/qt/map/overlay_layer.cpp source/scwx/qt/map/radar_product_layer.cpp diff --git a/scwx-qt/source/scwx/qt/gl/text_shader.cpp b/scwx-qt/source/scwx/qt/gl/text_shader.cpp index 2014da68..20f3a60a 100644 --- a/scwx-qt/source/scwx/qt/gl/text_shader.cpp +++ b/scwx-qt/source/scwx/qt/gl/text_shader.cpp @@ -1,4 +1,5 @@ #include +#include #include #pragma warning(push, 0) @@ -18,41 +19,46 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_); class TextShaderImpl { public: - explicit TextShaderImpl(OpenGLFunctions& gl) : - gl_ {gl}, projectionLocation_(GL_INVALID_INDEX) + explicit TextShaderImpl(std::shared_ptr context) : + context_ {context}, + shaderProgram_ {nullptr}, + projectionLocation_(GL_INVALID_INDEX) { } ~TextShaderImpl() {} - OpenGLFunctions& gl_; + std::shared_ptr context_; + std::shared_ptr shaderProgram_; GLint projectionLocation_; }; -TextShader::TextShader(OpenGLFunctions& gl) : - ShaderProgram(gl), p(std::make_unique(gl)) +TextShader::TextShader(std::shared_ptr context) : + p(std::make_unique(context)) { } TextShader::~TextShader() = default; -TextShader::TextShader(TextShader&&) noexcept = default; +TextShader::TextShader(TextShader&&) noexcept = default; TextShader& TextShader::operator=(TextShader&&) noexcept = default; bool TextShader::Initialize() { - OpenGLFunctions& gl = p->gl_; + OpenGLFunctions& gl = p->context_->gl(); // Load and configure shader - bool success = Load(":/gl/text.vert", ":/gl/text.frag"); + p->shaderProgram_ = + p->context_->GetShaderProgram(":/gl/text.vert", ":/gl/text.frag"); - p->projectionLocation_ = gl.glGetUniformLocation(id(), "projection"); + p->projectionLocation_ = + gl.glGetUniformLocation(p->shaderProgram_->id(), "projection"); if (p->projectionLocation_ == -1) { logger_->warn("Could not find projection"); } - return success; + return true; } void TextShader::RenderText(const std::string& text, @@ -65,9 +71,9 @@ void TextShader::RenderText(const std::string& text, GLuint textureId, TextAlign align) { - OpenGLFunctions& gl = p->gl_; + OpenGLFunctions& gl = p->context_->gl(); - Use(); + p->shaderProgram_->Use(); gl.glEnable(GL_BLEND); gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -103,7 +109,7 @@ void TextShader::RenderText(const std::string& text, void TextShader::SetProjection(const glm::mat4& projection) { - p->gl_.glUniformMatrix4fv( + p->context_->gl().glUniformMatrix4fv( p->projectionLocation_, 1, GL_FALSE, glm::value_ptr(projection)); } diff --git a/scwx-qt/source/scwx/qt/gl/text_shader.hpp b/scwx-qt/source/scwx/qt/gl/text_shader.hpp index a64f6d79..83553a08 100644 --- a/scwx-qt/source/scwx/qt/gl/text_shader.hpp +++ b/scwx-qt/source/scwx/qt/gl/text_shader.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -24,13 +24,13 @@ enum class TextAlign class TextShaderImpl; -class TextShader : public ShaderProgram +class TextShader { public: - explicit TextShader(OpenGLFunctions& gl); + explicit TextShader(std::shared_ptr context); ~TextShader(); - TextShader(const TextShader&) = delete; + TextShader(const TextShader&) = delete; TextShader& operator=(const TextShader&) = delete; TextShader(TextShader&&) noexcept; diff --git a/scwx-qt/source/scwx/qt/map/color_table_layer.cpp b/scwx-qt/source/scwx/qt/map/color_table_layer.cpp index c307c463..07512fd7 100644 --- a/scwx-qt/source/scwx/qt/map/color_table_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/color_table_layer.cpp @@ -21,7 +21,7 @@ class ColorTableLayerImpl { public: explicit ColorTableLayerImpl(std::shared_ptr context) : - shaderProgram_(context->gl_), + shaderProgram_(nullptr), uMVPMatrixLocation_(GL_INVALID_INDEX), vbo_ {GL_INVALID_INDEX}, vao_ {GL_INVALID_INDEX}, @@ -31,7 +31,8 @@ public: } ~ColorTableLayerImpl() = default; - gl::ShaderProgram shaderProgram_; + std::shared_ptr shaderProgram_; + GLint uMVPMatrixLocation_; std::array vbo_; GLuint vao_; @@ -52,13 +53,14 @@ void ColorTableLayer::Initialize() { logger_->debug("Initialize()"); - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); // Load and configure overlay shader - p->shaderProgram_.Load(":/gl/texture1d.vert", ":/gl/texture1d.frag"); + p->shaderProgram_ = + context()->GetShaderProgram(":/gl/texture1d.vert", ":/gl/texture1d.frag"); p->uMVPMatrixLocation_ = - gl.glGetUniformLocation(p->shaderProgram_.id(), "uMVPMatrix"); + gl.glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix"); if (p->uMVPMatrixLocation_ == -1) { logger_->warn("Could not find uMVPMatrix"); @@ -66,7 +68,7 @@ void ColorTableLayer::Initialize() gl.glGenTextures(1, &p->texture_); - p->shaderProgram_.Use(); + p->shaderProgram_->Use(); // Generate a vertex array object gl.glGenVertexArrays(1, &p->vao_); @@ -99,7 +101,7 @@ void ColorTableLayer::Initialize() gl.glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, static_cast(0)); gl.glEnableVertexAttribArray(1); - connect(context()->radarProductView_.get(), + connect(context()->radar_product_view().get(), &view::RadarProductView::ColorTableUpdated, this, [=]() { p->colorTableNeedsUpdate_ = true; }); @@ -107,10 +109,11 @@ void ColorTableLayer::Initialize() void ColorTableLayer::Render(const QMapbox::CustomLayerRenderParameters& params) { - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); + auto radarProductView = context()->radar_product_view(); - if (context()->radarProductView_ == nullptr || - !context()->radarProductView_->IsInitialized()) + if (context()->radar_product_view() == nullptr || + !context()->radar_product_view()->IsInitialized()) { // Defer rendering until view is initialized return; @@ -121,14 +124,14 @@ void ColorTableLayer::Render(const QMapbox::CustomLayerRenderParameters& params) 0.0f, static_cast(params.height)); - p->shaderProgram_.Use(); + p->shaderProgram_->Use(); gl.glUniformMatrix4fv( p->uMVPMatrixLocation_, 1, GL_FALSE, glm::value_ptr(projection)); if (p->colorTableNeedsUpdate_) { - p->colorTable_ = context()->radarProductView_->color_table(); + p->colorTable_ = radarProductView->color_table(); gl.glActiveTexture(GL_TEXTURE0); gl.glBindTexture(GL_TEXTURE_1D, p->texture_); @@ -145,9 +148,8 @@ void ColorTableLayer::Render(const QMapbox::CustomLayerRenderParameters& params) gl.glGenerateMipmap(GL_TEXTURE_1D); } - if (p->colorTable_.size() > 0 && - context()->radarProductView_->sweep_time() != - std::chrono::system_clock::time_point()) + if (p->colorTable_.size() > 0 && radarProductView->sweep_time() != + std::chrono::system_clock::time_point()) { // Color table panel vertices const float vertexLX = 0.0f; @@ -176,7 +178,7 @@ void ColorTableLayer::Deinitialize() { logger_->debug("Deinitialize()"); - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); gl.glDeleteVertexArrays(1, &p->vao_); gl.glDeleteBuffers(2, p->vbo_.data()); diff --git a/scwx-qt/source/scwx/qt/map/draw_layer.cpp b/scwx-qt/source/scwx/qt/map/draw_layer.cpp index 16e1311d..c9dab283 100644 --- a/scwx-qt/source/scwx/qt/map/draw_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/draw_layer.cpp @@ -22,14 +22,15 @@ class DrawLayerImpl { public: explicit DrawLayerImpl(std::shared_ptr context) : - shaderProgram_ {context->gl_}, uMVPMatrixLocation_(GL_INVALID_INDEX) + shaderProgram_ {nullptr}, uMVPMatrixLocation_(GL_INVALID_INDEX) { } ~DrawLayerImpl() {} - gl::ShaderProgram shaderProgram_; - GLint uMVPMatrixLocation_; + std::shared_ptr shaderProgram_; + + GLint uMVPMatrixLocation_; std::vector> drawList_; }; @@ -42,20 +43,21 @@ DrawLayer::~DrawLayer() = default; void DrawLayer::Initialize() { - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); - p->shaderProgram_.Load(":/gl/color.vert", ":/gl/color.frag"); + p->shaderProgram_ = + context()->GetShaderProgram(":/gl/color.vert", ":/gl/color.frag"); p->uMVPMatrixLocation_ = - gl.glGetUniformLocation(p->shaderProgram_.id(), "uMVPMatrix"); + gl.glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix"); if (p->uMVPMatrixLocation_ == -1) { logger_->warn("Could not find uMVPMatrix"); } - p->shaderProgram_.Use(); + p->shaderProgram_->Use(); - for (auto item : p->drawList_) + for (auto& item : p->drawList_) { item->Initialize(); } @@ -63,9 +65,9 @@ void DrawLayer::Initialize() void DrawLayer::Render(const QMapbox::CustomLayerRenderParameters& params) { - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); - p->shaderProgram_.Use(); + p->shaderProgram_->Use(); glm::mat4 projection = glm::ortho(0.0f, static_cast(params.width), @@ -75,7 +77,7 @@ void DrawLayer::Render(const QMapbox::CustomLayerRenderParameters& params) gl.glUniformMatrix4fv( p->uMVPMatrixLocation_, 1, GL_FALSE, glm::value_ptr(projection)); - for (auto item : p->drawList_) + for (auto& item : p->drawList_) { item->Render(); } @@ -83,7 +85,7 @@ void DrawLayer::Render(const QMapbox::CustomLayerRenderParameters& params) void DrawLayer::Deinitialize() { - for (auto item : p->drawList_) + for (auto& item : p->drawList_) { item->Deinitialize(); } diff --git a/scwx-qt/source/scwx/qt/map/map_context.cpp b/scwx-qt/source/scwx/qt/map/map_context.cpp new file mode 100644 index 00000000..1e19d9e6 --- /dev/null +++ b/scwx-qt/source/scwx/qt/map/map_context.cpp @@ -0,0 +1,131 @@ +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace map +{ + +class MapContext::Impl +{ +public: + explicit Impl(std::shared_ptr radarProductView) : + gl_ {}, + settings_ {}, + radarProductView_ {radarProductView}, + radarProductGroup_ {common::RadarProductGroup::Unknown}, + radarProduct_ {"???"}, + radarProductCode_ {0}, + shaderProgramMap_ {}, + shaderProgramMutex_ {} + { + } + + ~Impl() {} + + gl::OpenGLFunctions gl_; + MapSettings settings_; + std::shared_ptr radarProductView_; + common::RadarProductGroup radarProductGroup_; + std::string radarProduct_; + int16_t radarProductCode_; + + std::unordered_map, + std::shared_ptr, + util::hash>> + shaderProgramMap_; + std::mutex shaderProgramMutex_; +}; + +MapContext::MapContext( + std::shared_ptr radarProductView) : + p(std::make_unique(radarProductView)) +{ +} +MapContext::~MapContext() = default; + +MapContext::MapContext(MapContext&&) noexcept = default; +MapContext& MapContext::operator=(MapContext&&) noexcept = default; + +gl::OpenGLFunctions& MapContext::gl() +{ + return p->gl_; +} + +MapSettings& MapContext::settings() +{ + return p->settings_; +} + +std::shared_ptr MapContext::radar_product_view() const +{ + return p->radarProductView_; +} + +common::RadarProductGroup MapContext::radar_product_group() const +{ + return p->radarProductGroup_; +} + +std::string MapContext::radar_product() const +{ + return p->radarProduct_; +} + +int16_t MapContext::radar_product_code() const +{ + return p->radarProductCode_; +} + +void MapContext::set_radar_product_view( + std::shared_ptr radarProductView) +{ + p->radarProductView_ = radarProductView; +} + +void MapContext::set_radar_product_group( + common::RadarProductGroup radarProductGroup) +{ + p->radarProductGroup_ = radarProductGroup; +} + +void MapContext::set_radar_product(const std::string& radarProduct) +{ + p->radarProduct_ = radarProduct; +} + +void MapContext::set_radar_product_code(int16_t radarProductCode) +{ + p->radarProductCode_ = radarProductCode; +} + +std::shared_ptr +MapContext::GetShaderProgram(const std::string& vertexPath, + const std::string& fragmentPath) +{ + const std::pair key {vertexPath, fragmentPath}; + std::shared_ptr shaderProgram; + + std::unique_lock lock(p->shaderProgramMutex_); + + auto it = p->shaderProgramMap_.find(key); + + if (it == p->shaderProgramMap_.end()) + { + shaderProgram = std::make_shared(p->gl_); + shaderProgram->Load(vertexPath, fragmentPath); + p->shaderProgramMap_[key] = shaderProgram; + } + else + { + shaderProgram = it->second; + } + + return shaderProgram; +} + +} // namespace map +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/map/map_context.hpp b/scwx-qt/source/scwx/qt/map/map_context.hpp index 7a249286..95703f4a 100644 --- a/scwx-qt/source/scwx/qt/map/map_context.hpp +++ b/scwx-qt/source/scwx/qt/map/map_context.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -11,32 +12,40 @@ namespace qt namespace map { -struct MapContext +class MapContext { +public: explicit MapContext( - std::shared_ptr radarProductView = nullptr) : - gl_ {}, - settings_ {}, - radarProductView_ {radarProductView}, - radarProductGroup_ {common::RadarProductGroup::Unknown}, - radarProduct_ {"???"}, - radarProductCode_ {0} - { - } - ~MapContext() = default; + std::shared_ptr radarProductView = nullptr); + ~MapContext(); - MapContext(const MapContext&) = delete; + MapContext(const MapContext&) = delete; MapContext& operator=(const MapContext&) = delete; - MapContext(MapContext&&) noexcept = default; - MapContext& operator=(MapContext&&) noexcept = default; + MapContext(MapContext&&) noexcept; + MapContext& operator=(MapContext&&) noexcept; - gl::OpenGLFunctions gl_; - MapSettings settings_; - std::shared_ptr radarProductView_; - common::RadarProductGroup radarProductGroup_; - std::string radarProduct_; - int16_t radarProductCode_; + gl::OpenGLFunctions& gl(); + MapSettings& settings(); + std::shared_ptr radar_product_view() const; + common::RadarProductGroup radar_product_group() const; + std::string radar_product() const; + int16_t radar_product_code() const; + + void set_radar_product_view( + std::shared_ptr radarProductView); + void set_radar_product_group(common::RadarProductGroup radarProductGroup); + void set_radar_product(const std::string& radarProduct); + void set_radar_product_code(int16_t radarProductCode); + + std::shared_ptr + GetShaderProgram(const std::string& vertexPath, + const std::string& fragmentPath); + +private: + class Impl; + + std::unique_ptr p; }; } // namespace map diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index 1b60c240..b6f348cf 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -153,9 +153,11 @@ common::Level3ProductCategoryMap MapWidget::GetAvailableLevel3Categories() float MapWidget::GetElevation() const { - if (p->context_->radarProductView_ != nullptr) + auto radarProductView = p->context_->radar_product_view(); + + if (radarProductView != nullptr) { - return p->context_->radarProductView_->elevation(); + return radarProductView->elevation(); } else { @@ -165,9 +167,11 @@ float MapWidget::GetElevation() const std::vector MapWidget::GetElevationCuts() const { - if (p->context_->radarProductView_ != nullptr) + auto radarProductView = p->context_->radar_product_view(); + + if (radarProductView != nullptr) { - return p->context_->radarProductView_->GetElevationCuts(); + return radarProductView->GetElevationCuts(); } else { @@ -182,10 +186,12 @@ MapWidgetImpl::GetLevel2ProductOrDefault(const std::string& productName) const if (level2Product == common::Level2Product::Unknown) { - if (context_->radarProductView_ != nullptr) + auto radarProductView = context_->radar_product_view(); + + if (radarProductView != nullptr) { - level2Product = common::GetLevel2Product( - context_->radarProductView_->GetRadarProductName()); + level2Product = + common::GetLevel2Product(radarProductView->GetRadarProductName()); } } @@ -218,9 +224,11 @@ std::vector MapWidget::GetLevel3Products() common::RadarProductGroup MapWidget::GetRadarProductGroup() const { - if (p->context_->radarProductView_ != nullptr) + auto radarProductView = p->context_->radar_product_view(); + + if (radarProductView != nullptr) { - return p->context_->radarProductView_->GetRadarProductGroup(); + return radarProductView->GetRadarProductGroup(); } else { @@ -230,10 +238,11 @@ common::RadarProductGroup MapWidget::GetRadarProductGroup() const std::string MapWidget::GetRadarProductName() const { + auto radarProductView = p->context_->radar_product_view(); - if (p->context_->radarProductView_ != nullptr) + if (radarProductView != nullptr) { - return p->context_->radarProductView_->GetRadarProductName(); + return radarProductView->GetRadarProductName(); } else { @@ -255,9 +264,11 @@ std::shared_ptr MapWidget::GetRadarSite() const uint16_t MapWidget::GetVcp() const { - if (p->context_->radarProductView_ != nullptr) + auto radarProductView = p->context_->radar_product_view(); + + if (radarProductView != nullptr) { - return p->context_->radarProductView_->vcp(); + return radarProductView->vcp(); } else { @@ -267,10 +278,12 @@ uint16_t MapWidget::GetVcp() const void MapWidget::SelectElevation(float elevation) { - if (p->context_->radarProductView_ != nullptr) + auto radarProductView = p->context_->radar_product_view(); + + if (radarProductView != nullptr) { - p->context_->radarProductView_->SelectElevation(elevation); - p->context_->radarProductView_->Update(); + radarProductView->SelectElevation(elevation); + radarProductView->Update(); } } @@ -280,8 +293,7 @@ void MapWidget::SelectRadarProduct(common::RadarProductGroup group, { bool radarProductViewCreated = false; - std::shared_ptr& radarProductView = - p->context_->radarProductView_; + auto radarProductView = p->context_->radar_product_view(); std::string productName {product}; @@ -304,12 +316,13 @@ void MapWidget::SelectRadarProduct(common::RadarProductGroup group, (radarProductView->GetRadarProductGroup() == common::RadarProductGroup::Level2 && radarProductView->GetRadarProductName() != productName) || - p->context_->radarProductCode_ != productCode) + p->context_->radar_product_code() != productCode) { p->RadarProductViewDisconnect(); radarProductView = view::RadarProductViewFactory::Create( group, productName, productCode, p->radarProductManager_); + p->context_->set_radar_product_view(radarProductView); p->RadarProductViewConnect(); @@ -320,9 +333,9 @@ void MapWidget::SelectRadarProduct(common::RadarProductGroup group, radarProductView->SelectProduct(productName); } - p->context_->radarProductGroup_ = group; - p->context_->radarProduct_ = productName; - p->context_->radarProductCode_ = productCode; + p->context_->set_radar_product_group(group); + p->context_->set_radar_product(productName); + p->context_->set_radar_product_code(productCode); if (radarProductView != nullptr) { @@ -372,7 +385,7 @@ void MapWidget::SelectRadarProduct( void MapWidget::SetActive(bool isActive) { - p->context_->settings_.isActive_ = isActive; + p->context_->settings().isActive_ = isActive; update(); } @@ -382,11 +395,13 @@ void MapWidget::SetAutoRefresh(bool enabled) { p->autoRefreshEnabled_ = enabled; - if (p->autoRefreshEnabled_ && p->context_->radarProductView_ != nullptr) + auto radarProductView = p->context_->radar_product_view(); + + if (p->autoRefreshEnabled_ && radarProductView != nullptr) { p->radarProductManager_->EnableRefresh( - p->context_->radarProductView_->GetRadarProductGroup(), - p->context_->radarProductView_->GetRadarProductName(), + radarProductView->GetRadarProductGroup(), + radarProductView->GetRadarProductName(), true); } } @@ -430,7 +445,9 @@ void MapWidget::AddLayers() } p->layerList_.clear(); - if (p->context_->radarProductView_ != nullptr) + auto radarProductView = p->context_->radar_product_view(); + + if (radarProductView != nullptr) { p->radarProductLayer_ = std::make_shared(p->context_); p->colorTableLayer_ = std::make_shared(p->context_); @@ -453,7 +470,7 @@ void MapWidget::AddLayers() p->AddLayer("radar", p->radarProductLayer_, before); RadarRangeLayer::Add(p->map_, - p->context_->radarProductView_->range(), + radarProductView->range(), {radarSite->latitude(), radarSite->longitude()}); p->AddLayer("colorTable", p->colorTableLayer_); } @@ -572,7 +589,7 @@ void MapWidget::initializeGL() logger_->debug("initializeGL()"); makeCurrent(); - p->context_->gl_.initializeOpenGLFunctions(); + p->context_->gl().initializeOpenGLFunctions(); p->map_.reset(new QMapboxGL(nullptr, p->settings_, size(), pixelRatio())); connect(p->map_.get(), @@ -637,9 +654,10 @@ void MapWidgetImpl::RadarProductManagerConnect() const std::string& product, std::chrono::system_clock::time_point latestTime) { - if (autoRefreshEnabled_ && context_->radarProductGroup_ == group && + if (autoRefreshEnabled_ && + context_->radar_product_group() == group && (group == common::RadarProductGroup::Level2 || - context_->radarProduct_ == product)) + context_->radar_product() == product)) { // Create file request std::shared_ptr request = @@ -698,16 +716,18 @@ void MapWidgetImpl::InitializeNewRadarProductView( util::async( [=]() { + auto radarProductView = context_->radar_product_view(); + std::string colorTableFile = manager::SettingsManager::palette_settings()->palette(colorPalette); if (!colorTableFile.empty()) { std::shared_ptr colorTable = common::ColorTable::Load(colorTableFile); - context_->radarProductView_->LoadColorTable(colorTable); + radarProductView->LoadColorTable(colorTable); } - context_->radarProductView_->Initialize(); + radarProductView->Initialize(); }); if (map_ != nullptr) @@ -718,26 +738,28 @@ void MapWidgetImpl::InitializeNewRadarProductView( void MapWidgetImpl::RadarProductViewConnect() { - if (context_->radarProductView_ != nullptr) + auto radarProductView = context_->radar_product_view(); + + if (radarProductView != nullptr) { connect( - context_->radarProductView_.get(), + radarProductView.get(), &view::RadarProductView::ColorTableUpdated, this, [&]() { widget_->update(); }, Qt::QueuedConnection); connect( - context_->radarProductView_.get(), + radarProductView.get(), &view::RadarProductView::SweepComputed, this, - [&]() + [=]() { std::shared_ptr radarSite = radarProductManager_->radar_site(); RadarRangeLayer::Update( map_, - context_->radarProductView_->range(), + radarProductView->range(), {radarSite->latitude(), radarSite->longitude()}); widget_->update(); emit widget_->RadarSweepUpdated(); @@ -748,13 +770,15 @@ void MapWidgetImpl::RadarProductViewConnect() void MapWidgetImpl::RadarProductViewDisconnect() { - if (context_->radarProductView_ != nullptr) + auto radarProductView = context_->radar_product_view(); + + if (radarProductView != nullptr) { - disconnect(context_->radarProductView_.get(), + disconnect(radarProductView.get(), &view::RadarProductView::ColorTableUpdated, this, nullptr); - disconnect(context_->radarProductView_.get(), + disconnect(radarProductView.get(), &view::RadarProductView::SweepComputed, this, nullptr); diff --git a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp index 91ef54ef..e8049e1c 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp @@ -34,12 +34,12 @@ class OverlayLayerImpl { public: explicit OverlayLayerImpl(std::shared_ptr context) : - textShader_(context->gl_), + textShader_(context), 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_)}, + activeBoxOuter_ {std::make_shared(context->gl())}, + activeBoxInner_ {std::make_shared(context->gl())}, + timeBox_ {std::make_shared(context->gl())}, sweepTimeString_ {}, sweepTimeNeedsUpdate_ {true} { @@ -81,7 +81,8 @@ void OverlayLayer::Initialize() DrawLayer::Initialize(); - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); + auto radarProductView = context()->radar_product_view(); p->textShader_.Initialize(); @@ -90,9 +91,9 @@ void OverlayLayer::Initialize() p->texture_ = p->font_->GenerateTexture(gl); } - if (context()->radarProductView_ != nullptr) + if (radarProductView != nullptr) { - connect(context()->radarProductView_.get(), + connect(radarProductView.get(), &view::RadarProductView::SweepComputed, this, &OverlayLayer::UpdateSweepTimeNextFrame); @@ -103,14 +104,14 @@ void OverlayLayer::Render(const QMapbox::CustomLayerRenderParameters& params) { constexpr float fontSize = 16.0f; - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); + auto radarProductView = context()->radar_product_view(); + auto& settings = context()->settings(); - if (p->sweepTimeNeedsUpdate_ && context()->radarProductView_ != nullptr) + if (p->sweepTimeNeedsUpdate_ && radarProductView != nullptr) { - p->sweepTimeString_ = - scwx::util::TimeString(context()->radarProductView_->sweep_time(), - std::chrono::current_zone(), - false); + p->sweepTimeString_ = scwx::util::TimeString( + radarProductView->sweep_time(), std::chrono::current_zone(), false); p->sweepTimeNeedsUpdate_ = false; } @@ -120,9 +121,9 @@ void OverlayLayer::Render(const QMapbox::CustomLayerRenderParameters& params) static_cast(params.height)); // Active Box - p->activeBoxOuter_->SetVisible(context()->settings_.isActive_); - p->activeBoxInner_->SetVisible(context()->settings_.isActive_); - if (context()->settings_.isActive_) + p->activeBoxOuter_->SetVisible(settings.isActive_); + p->activeBoxInner_->SetVisible(settings.isActive_); + if (settings.isActive_) { p->activeBoxOuter_->SetSize(params.width, params.height); p->activeBoxInner_->SetSize(params.width - 2.0f, params.height - 2.0f); @@ -164,15 +165,16 @@ void OverlayLayer::Deinitialize() DrawLayer::Deinitialize(); - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); + auto radarProductView = context()->radar_product_view(); gl.glDeleteTextures(1, &p->texture_); p->texture_ = GL_INVALID_INDEX; - if (context()->radarProductView_ != nullptr) + if (radarProductView != nullptr) { - disconnect(context()->radarProductView_.get(), + disconnect(radarProductView.get(), &view::RadarProductView::SweepComputed, this, &OverlayLayer::UpdateSweepTimeNextFrame); 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 2f47b777..c7b501ac 100644 --- a/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp @@ -33,7 +33,7 @@ class RadarProductLayerImpl { public: explicit RadarProductLayerImpl(std::shared_ptr context) : - shaderProgram_(context->gl_), + shaderProgram_(nullptr), uMVPMatrixLocation_(GL_INVALID_INDEX), uMapScreenCoordLocation_(GL_INVALID_INDEX), uDataMomentOffsetLocation_(GL_INVALID_INDEX), @@ -50,7 +50,8 @@ public: } ~RadarProductLayerImpl() = default; - gl::ShaderProgram shaderProgram_; + std::shared_ptr shaderProgram_; + GLint uMVPMatrixLocation_; GLint uMapScreenCoordLocation_; GLint uDataMomentOffsetLocation_; @@ -78,47 +79,48 @@ void RadarProductLayer::Initialize() { logger_->debug("Initialize()"); - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); // Load and configure radar shader - p->shaderProgram_.Load(":/gl/radar.vert", ":/gl/radar.frag"); + p->shaderProgram_ = + context()->GetShaderProgram(":/gl/radar.vert", ":/gl/radar.frag"); p->uMVPMatrixLocation_ = - gl.glGetUniformLocation(p->shaderProgram_.id(), "uMVPMatrix"); + gl.glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix"); if (p->uMVPMatrixLocation_ == -1) { logger_->warn("Could not find uMVPMatrix"); } p->uMapScreenCoordLocation_ = - gl.glGetUniformLocation(p->shaderProgram_.id(), "uMapScreenCoord"); + gl.glGetUniformLocation(p->shaderProgram_->id(), "uMapScreenCoord"); if (p->uMapScreenCoordLocation_ == -1) { logger_->warn("Could not find uMapScreenCoord"); } p->uDataMomentOffsetLocation_ = - gl.glGetUniformLocation(p->shaderProgram_.id(), "uDataMomentOffset"); + gl.glGetUniformLocation(p->shaderProgram_->id(), "uDataMomentOffset"); if (p->uDataMomentOffsetLocation_ == -1) { logger_->warn("Could not find uDataMomentOffset"); } p->uDataMomentScaleLocation_ = - gl.glGetUniformLocation(p->shaderProgram_.id(), "uDataMomentScale"); + gl.glGetUniformLocation(p->shaderProgram_->id(), "uDataMomentScale"); if (p->uDataMomentScaleLocation_ == -1) { logger_->warn("Could not find uDataMomentScale"); } p->uCFPEnabledLocation_ = - gl.glGetUniformLocation(p->shaderProgram_.id(), "uCFPEnabled"); + gl.glGetUniformLocation(p->shaderProgram_->id(), "uCFPEnabled"); if (p->uCFPEnabledLocation_ == -1) { logger_->warn("Could not find uCFPEnabled"); } - p->shaderProgram_.Use(); + p->shaderProgram_->Use(); // Generate a vertex array object gl.glGenVertexArrays(1, &p->vao_); @@ -138,11 +140,12 @@ void RadarProductLayer::Initialize() gl.glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl.glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - connect(context()->radarProductView_.get(), + auto radarProductView = context()->radar_product_view(); + connect(radarProductView.get(), &view::RadarProductView::ColorTableUpdated, this, [=]() { p->colorTableNeedsUpdate_ = true; }); - connect(context()->radarProductView_.get(), + connect(radarProductView.get(), &view::RadarProductView::SweepComputed, this, [=]() { p->sweepNeedsUpdate_ = true; }); @@ -152,12 +155,12 @@ void RadarProductLayer::UpdateSweep() { logger_->debug("UpdateSweep()"); - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); boost::timer::cpu_timer timer; std::shared_ptr radarProductView = - context()->radarProductView_; + context()->radar_product_view(); std::unique_lock sweepLock(radarProductView->sweep_mutex(), std::try_to_lock); @@ -253,9 +256,9 @@ void RadarProductLayer::UpdateSweep() void RadarProductLayer::Render( const QMapbox::CustomLayerRenderParameters& params) { - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); - p->shaderProgram_.Use(); + p->shaderProgram_->Use(); if (p->colorTableNeedsUpdate_) { @@ -300,7 +303,7 @@ void RadarProductLayer::Deinitialize() { logger_->debug("Deinitialize()"); - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); gl.glDeleteVertexArrays(1, &p->vao_); gl.glDeleteBuffers(3, p->vbo_.data()); @@ -321,9 +324,9 @@ void RadarProductLayer::UpdateColorTable() p->colorTableNeedsUpdate_ = false; - gl::OpenGLFunctions& gl = context()->gl_; + gl::OpenGLFunctions& gl = context()->gl(); std::shared_ptr radarProductView = - context()->radarProductView_; + context()->radar_product_view(); const std::vector& colorTable = radarProductView->color_table(); From d84a618d3d724062073fb499dc183e71abccafd9 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 2 Oct 2022 23:44:09 -0500 Subject: [PATCH 06/24] Add GlContext base class for MapContext --- scwx-qt/scwx-qt.cmake | 4 +- scwx-qt/source/scwx/qt/gl/gl_context.cpp | 64 ++++++++++++++++++++++ scwx-qt/source/scwx/qt/gl/gl_context.hpp | 39 +++++++++++++ scwx-qt/source/scwx/qt/gl/text_shader.cpp | 8 +-- scwx-qt/source/scwx/qt/gl/text_shader.hpp | 4 +- scwx-qt/source/scwx/qt/map/map_context.cpp | 43 +-------------- scwx-qt/source/scwx/qt/map/map_context.hpp | 10 +--- 7 files changed, 115 insertions(+), 57 deletions(-) create mode 100644 scwx-qt/source/scwx/qt/gl/gl_context.cpp create mode 100644 scwx-qt/source/scwx/qt/gl/gl_context.hpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index d3c2b421..1c4a0366 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -41,9 +41,11 @@ set(UI_MAIN source/scwx/qt/main/main_window.ui) set(HDR_CONFIG source/scwx/qt/config/radar_site.hpp) set(SRC_CONFIG source/scwx/qt/config/radar_site.cpp) set(HDR_GL source/scwx/qt/gl/gl.hpp + source/scwx/qt/gl/gl_context.hpp source/scwx/qt/gl/shader_program.hpp source/scwx/qt/gl/text_shader.hpp) -set(SRC_GL source/scwx/qt/gl/shader_program.cpp +set(SRC_GL source/scwx/qt/gl/gl_context.cpp + source/scwx/qt/gl/shader_program.cpp source/scwx/qt/gl/text_shader.cpp) set(HDR_GL_DRAW source/scwx/qt/gl/draw/draw_item.hpp source/scwx/qt/gl/draw/geo_line.hpp diff --git a/scwx-qt/source/scwx/qt/gl/gl_context.cpp b/scwx-qt/source/scwx/qt/gl/gl_context.cpp new file mode 100644 index 00000000..3db875a8 --- /dev/null +++ b/scwx-qt/source/scwx/qt/gl/gl_context.cpp @@ -0,0 +1,64 @@ +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace gl +{ + +class GlContext::Impl +{ +public: + explicit Impl() : gl_ {}, shaderProgramMap_ {}, shaderProgramMutex_ {} {} + ~Impl() {} + + gl::OpenGLFunctions gl_; + + std::unordered_map, + std::shared_ptr, + util::hash>> + shaderProgramMap_; + std::mutex shaderProgramMutex_; +}; + +GlContext::GlContext() : p(std::make_unique()) {} +GlContext::~GlContext() = default; + +GlContext::GlContext(GlContext&&) noexcept = default; +GlContext& GlContext::operator=(GlContext&&) noexcept = default; + +gl::OpenGLFunctions& GlContext::gl() +{ + return p->gl_; +} + +std::shared_ptr +GlContext::GetShaderProgram(const std::string& vertexPath, + const std::string& fragmentPath) +{ + const std::pair key {vertexPath, fragmentPath}; + std::shared_ptr shaderProgram; + + std::unique_lock lock(p->shaderProgramMutex_); + + auto it = p->shaderProgramMap_.find(key); + + if (it == p->shaderProgramMap_.end()) + { + shaderProgram = std::make_shared(p->gl_); + shaderProgram->Load(vertexPath, fragmentPath); + p->shaderProgramMap_[key] = shaderProgram; + } + else + { + shaderProgram = it->second; + } + + return shaderProgram; +} + +} // namespace gl +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/gl/gl_context.hpp b/scwx-qt/source/scwx/qt/gl/gl_context.hpp new file mode 100644 index 00000000..cf81262f --- /dev/null +++ b/scwx-qt/source/scwx/qt/gl/gl_context.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace gl +{ + +class GlContext +{ +public: + explicit GlContext(); + virtual ~GlContext(); + + GlContext(const GlContext&) = delete; + GlContext& operator=(const GlContext&) = delete; + + GlContext(GlContext&&) noexcept; + GlContext& operator=(GlContext&&) noexcept; + + gl::OpenGLFunctions& gl(); + + std::shared_ptr + GetShaderProgram(const std::string& vertexPath, + const std::string& fragmentPath); + +private: + class Impl; + + std::unique_ptr p; +}; + +} // namespace gl +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/gl/text_shader.cpp b/scwx-qt/source/scwx/qt/gl/text_shader.cpp index 20f3a60a..ec8cdcf1 100644 --- a/scwx-qt/source/scwx/qt/gl/text_shader.cpp +++ b/scwx-qt/source/scwx/qt/gl/text_shader.cpp @@ -19,7 +19,7 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_); class TextShaderImpl { public: - explicit TextShaderImpl(std::shared_ptr context) : + explicit TextShaderImpl(std::shared_ptr context) : context_ {context}, shaderProgram_ {nullptr}, projectionLocation_(GL_INVALID_INDEX) @@ -28,13 +28,13 @@ public: ~TextShaderImpl() {} - std::shared_ptr context_; - std::shared_ptr shaderProgram_; + std::shared_ptr context_; + std::shared_ptr shaderProgram_; GLint projectionLocation_; }; -TextShader::TextShader(std::shared_ptr context) : +TextShader::TextShader(std::shared_ptr context) : p(std::make_unique(context)) { } diff --git a/scwx-qt/source/scwx/qt/gl/text_shader.hpp b/scwx-qt/source/scwx/qt/gl/text_shader.hpp index 83553a08..ed81907a 100644 --- a/scwx-qt/source/scwx/qt/gl/text_shader.hpp +++ b/scwx-qt/source/scwx/qt/gl/text_shader.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -27,7 +27,7 @@ class TextShaderImpl; class TextShader { public: - explicit TextShader(std::shared_ptr context); + explicit TextShader(std::shared_ptr context); ~TextShader(); TextShader(const TextShader&) = delete; diff --git a/scwx-qt/source/scwx/qt/map/map_context.cpp b/scwx-qt/source/scwx/qt/map/map_context.cpp index 1e19d9e6..68b94e8e 100644 --- a/scwx-qt/source/scwx/qt/map/map_context.cpp +++ b/scwx-qt/source/scwx/qt/map/map_context.cpp @@ -1,5 +1,4 @@ #include -#include namespace scwx { @@ -12,31 +11,21 @@ class MapContext::Impl { public: explicit Impl(std::shared_ptr radarProductView) : - gl_ {}, settings_ {}, radarProductView_ {radarProductView}, radarProductGroup_ {common::RadarProductGroup::Unknown}, radarProduct_ {"???"}, - radarProductCode_ {0}, - shaderProgramMap_ {}, - shaderProgramMutex_ {} + radarProductCode_ {0} { } ~Impl() {} - gl::OpenGLFunctions gl_; MapSettings settings_; std::shared_ptr radarProductView_; common::RadarProductGroup radarProductGroup_; std::string radarProduct_; int16_t radarProductCode_; - - std::unordered_map, - std::shared_ptr, - util::hash>> - shaderProgramMap_; - std::mutex shaderProgramMutex_; }; MapContext::MapContext( @@ -49,11 +38,6 @@ MapContext::~MapContext() = default; MapContext::MapContext(MapContext&&) noexcept = default; MapContext& MapContext::operator=(MapContext&&) noexcept = default; -gl::OpenGLFunctions& MapContext::gl() -{ - return p->gl_; -} - MapSettings& MapContext::settings() { return p->settings_; @@ -101,31 +85,6 @@ void MapContext::set_radar_product_code(int16_t radarProductCode) p->radarProductCode_ = radarProductCode; } -std::shared_ptr -MapContext::GetShaderProgram(const std::string& vertexPath, - const std::string& fragmentPath) -{ - const std::pair key {vertexPath, fragmentPath}; - std::shared_ptr shaderProgram; - - std::unique_lock lock(p->shaderProgramMutex_); - - auto it = p->shaderProgramMap_.find(key); - - if (it == p->shaderProgramMap_.end()) - { - shaderProgram = std::make_shared(p->gl_); - shaderProgram->Load(vertexPath, fragmentPath); - p->shaderProgramMap_[key] = shaderProgram; - } - else - { - shaderProgram = it->second; - } - - return shaderProgram; -} - } // namespace map } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/map/map_context.hpp b/scwx-qt/source/scwx/qt/map/map_context.hpp index 95703f4a..47f3cc11 100644 --- a/scwx-qt/source/scwx/qt/map/map_context.hpp +++ b/scwx-qt/source/scwx/qt/map/map_context.hpp @@ -1,7 +1,6 @@ #pragma once -#include -#include +#include #include #include @@ -12,7 +11,7 @@ namespace qt namespace map { -class MapContext +class MapContext : public gl::GlContext { public: explicit MapContext( @@ -25,7 +24,6 @@ public: MapContext(MapContext&&) noexcept; MapContext& operator=(MapContext&&) noexcept; - gl::OpenGLFunctions& gl(); MapSettings& settings(); std::shared_ptr radar_product_view() const; common::RadarProductGroup radar_product_group() const; @@ -38,10 +36,6 @@ public: void set_radar_product(const std::string& radarProduct); void set_radar_product_code(int16_t radarProductCode); - std::shared_ptr - GetShaderProgram(const std::string& vertexPath, - const std::string& fragmentPath); - private: class Impl; From 224d36bae58d3018acfaaf9e1c598fac7528a290 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 3 Oct 2022 00:11:39 -0500 Subject: [PATCH 07/24] Define draw item shaders in draw items, not the generic draw layer --- scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp | 29 ++++++++++-- scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp | 24 ++++++---- scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp | 4 +- scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp | 2 +- scwx-qt/source/scwx/qt/gl/draw/rectangle.cpp | 48 ++++++++++++++------ scwx-qt/source/scwx/qt/gl/draw/rectangle.hpp | 14 +++--- scwx-qt/source/scwx/qt/map/draw_layer.cpp | 44 +----------------- scwx-qt/source/scwx/qt/map/overlay_layer.cpp | 6 +-- 8 files changed, 88 insertions(+), 83 deletions(-) diff --git a/scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp b/scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp index ca4533b6..f4b37fd0 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp @@ -2,6 +2,12 @@ #include +#pragma warning(push, 0) +#include +#include +#include +#pragma warning(pop) + namespace scwx { namespace qt @@ -13,20 +19,33 @@ namespace draw static const std::string logPrefix_ = "scwx::qt::gl::draw::draw_item"; -class DrawItemImpl +class DrawItem::Impl { public: - explicit DrawItemImpl() {} + explicit Impl(OpenGLFunctions& gl) : gl_ {gl} {} + ~Impl() {} - ~DrawItemImpl() {} + OpenGLFunctions& gl_; }; -DrawItem::DrawItem() : p(std::make_unique()) {} +DrawItem::DrawItem(OpenGLFunctions& gl) : p(std::make_unique(gl)) {} DrawItem::~DrawItem() = default; -DrawItem::DrawItem(DrawItem&&) noexcept = default; +DrawItem::DrawItem(DrawItem&&) noexcept = default; DrawItem& DrawItem::operator=(DrawItem&&) noexcept = default; +void DrawItem::UseDefaultProjection( + const QMapbox::CustomLayerRenderParameters& params, GLint uMVPMatrixLocation) +{ + glm::mat4 projection = glm::ortho(0.0f, + static_cast(params.width), + 0.0f, + static_cast(params.height)); + + p->gl_.glUniformMatrix4fv( + uMVPMatrixLocation, 1, GL_FALSE, glm::value_ptr(projection)); +} + } // namespace draw } // namespace gl } // namespace qt diff --git a/scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp b/scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp index 09e98092..32a221eb 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp @@ -1,7 +1,11 @@ #pragma once +#include + #include +#include + namespace scwx { namespace qt @@ -11,26 +15,30 @@ namespace gl namespace draw { -class DrawItemImpl; - class DrawItem { public: - explicit DrawItem(); + explicit DrawItem(OpenGLFunctions& gl); ~DrawItem(); - DrawItem(const DrawItem&) = delete; + DrawItem(const DrawItem&) = delete; DrawItem& operator=(const DrawItem&) = delete; DrawItem(DrawItem&&) noexcept; DrawItem& operator=(DrawItem&&) noexcept; - virtual void Initialize() = 0; - virtual void Render() = 0; - virtual void Deinitialize() = 0; + virtual void Initialize() = 0; + virtual void Render(const QMapbox::CustomLayerRenderParameters& params) = 0; + virtual void Deinitialize() = 0; + +protected: + void UseDefaultProjection(const QMapbox::CustomLayerRenderParameters& params, + GLint uMVPMatrixLocation); private: - std::unique_ptr p; + class Impl; + + std::unique_ptr p; }; } // namespace draw diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp index 7834022f..0c65d3fc 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp @@ -59,7 +59,7 @@ public: // TODO: OpenGL context with shaders GeoLine::GeoLine(OpenGLFunctions& gl) : - DrawItem(), p(std::make_unique(gl)) + DrawItem(gl), p(std::make_unique(gl)) { } GeoLine::~GeoLine() = default; @@ -118,7 +118,7 @@ void GeoLine::Initialize() p->dirty_ = true; } -void GeoLine::Render() +void GeoLine::Render(const QMapbox::CustomLayerRenderParameters&) { if (p->visible_) { diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp b/scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp index a1b6ec8f..7b5d6284 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp @@ -27,7 +27,7 @@ public: GeoLine& operator=(GeoLine&&) noexcept; void Initialize() override; - void Render() override; + void Render(const QMapbox::CustomLayerRenderParameters& params) override; void Deinitialize() override; /** diff --git a/scwx-qt/source/scwx/qt/gl/draw/rectangle.cpp b/scwx-qt/source/scwx/qt/gl/draw/rectangle.cpp index 10988613..f8b5756a 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/rectangle.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/rectangle.cpp @@ -1,4 +1,5 @@ #include +#include #include @@ -12,6 +13,7 @@ namespace draw { static const std::string logPrefix_ = "scwx::qt::gl::draw::rectangle"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); static constexpr size_t NUM_RECTANGLES = 5; static constexpr size_t NUM_TRIANGLES = NUM_RECTANGLES * 2; @@ -21,11 +23,11 @@ static constexpr size_t POINTS_PER_VERTEX = 7; static constexpr size_t BUFFER_LENGTH = NUM_TRIANGLES * VERTICES_PER_TRIANGLE * POINTS_PER_VERTEX; -class RectangleImpl +class Rectangle::Impl { public: - explicit RectangleImpl(OpenGLFunctions& gl) : - gl_ {gl}, + explicit Impl(std::shared_ptr context) : + context_ {context}, dirty_ {false}, visible_ {true}, x_ {0.0f}, @@ -36,14 +38,16 @@ public: borderColor_ {0, 0, 0, 0}, borderWidth_ {0.0f}, fillColor_ {std::nullopt}, + shaderProgram_ {nullptr}, + uMVPMatrixLocation_(GL_INVALID_INDEX), vao_ {GL_INVALID_INDEX}, vbo_ {GL_INVALID_INDEX} { } - ~RectangleImpl() {} + ~Impl() {} - OpenGLFunctions& gl_; + std::shared_ptr context_; bool dirty_; @@ -59,25 +63,37 @@ public: std::optional fillColor_; + std::shared_ptr shaderProgram_; + GLint uMVPMatrixLocation_; + GLuint vao_; GLuint vbo_; void Update(); }; -// TODO: OpenGL context with shaders -Rectangle::Rectangle(OpenGLFunctions& gl) : - DrawItem(), p(std::make_unique(gl)) +Rectangle::Rectangle(std::shared_ptr context) : + DrawItem(context->gl()), p(std::make_unique(context)) { } Rectangle::~Rectangle() = default; -Rectangle::Rectangle(Rectangle&&) noexcept = default; +Rectangle::Rectangle(Rectangle&&) noexcept = default; Rectangle& Rectangle::operator=(Rectangle&&) noexcept = default; void Rectangle::Initialize() { - gl::OpenGLFunctions& gl = p->gl_; + gl::OpenGLFunctions& gl = p->context_->gl(); + + p->shaderProgram_ = + p->context_->GetShaderProgram(":/gl/color.vert", ":/gl/color.frag"); + + p->uMVPMatrixLocation_ = + gl.glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix"); + if (p->uMVPMatrixLocation_ == -1) + { + logger_->warn("Could not find uMVPMatrix"); + } gl.glGenVertexArrays(1, &p->vao_); gl.glGenBuffers(1, &p->vbo_); @@ -106,16 +122,18 @@ void Rectangle::Initialize() p->dirty_ = true; } -void Rectangle::Render() +void Rectangle::Render(const QMapbox::CustomLayerRenderParameters& params) { if (p->visible_) { - gl::OpenGLFunctions& gl = p->gl_; + gl::OpenGLFunctions& gl = p->context_->gl(); gl.glBindVertexArray(p->vao_); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_); p->Update(); + p->shaderProgram_->Use(); + UseDefaultProjection(params, p->uMVPMatrixLocation_); if (p->fillColor_.has_value()) { @@ -133,7 +151,7 @@ void Rectangle::Render() void Rectangle::Deinitialize() { - gl::OpenGLFunctions& gl = p->gl_; + gl::OpenGLFunctions& gl = p->context_->gl(); gl.glDeleteVertexArrays(1, &p->vao_); gl.glDeleteBuffers(1, &p->vbo_); @@ -184,11 +202,11 @@ void Rectangle::SetVisible(bool visible) p->visible_ = visible; } -void RectangleImpl::Update() +void Rectangle::Impl::Update() { if (dirty_) { - gl::OpenGLFunctions& gl = gl_; + gl::OpenGLFunctions& gl = context_->gl(); const float lox = x_; const float rox = x_ + width_; diff --git a/scwx-qt/source/scwx/qt/gl/draw/rectangle.hpp b/scwx-qt/source/scwx/qt/gl/draw/rectangle.hpp index f1214309..481f7507 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/rectangle.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/rectangle.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -14,22 +14,20 @@ namespace gl namespace draw { -class RectangleImpl; - class Rectangle : public DrawItem { public: - explicit Rectangle(OpenGLFunctions& gl); + explicit Rectangle(std::shared_ptr context); ~Rectangle(); - Rectangle(const Rectangle&) = delete; + Rectangle(const Rectangle&) = delete; Rectangle& operator=(const Rectangle&) = delete; Rectangle(Rectangle&&) noexcept; Rectangle& operator=(Rectangle&&) noexcept; void Initialize() override; - void Render() override; + void Render(const QMapbox::CustomLayerRenderParameters& params) override; void Deinitialize() override; void SetBorder(float width, boost::gil::rgba8_pixel_t color); @@ -39,7 +37,9 @@ public: void SetVisible(bool visible); private: - std::unique_ptr p; + class Impl; + + std::unique_ptr p; }; } // namespace draw diff --git a/scwx-qt/source/scwx/qt/map/draw_layer.cpp b/scwx-qt/source/scwx/qt/map/draw_layer.cpp index c9dab283..970bf89c 100644 --- a/scwx-qt/source/scwx/qt/map/draw_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/draw_layer.cpp @@ -2,12 +2,6 @@ #include #include -#pragma warning(push, 0) -#include -#include -#include -#pragma warning(pop) - namespace scwx { namespace qt @@ -21,17 +15,9 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_); class DrawLayerImpl { public: - explicit DrawLayerImpl(std::shared_ptr context) : - shaderProgram_ {nullptr}, uMVPMatrixLocation_(GL_INVALID_INDEX) - { - } - + explicit DrawLayerImpl(std::shared_ptr context) {} ~DrawLayerImpl() {} - std::shared_ptr shaderProgram_; - - GLint uMVPMatrixLocation_; - std::vector> drawList_; }; @@ -43,20 +29,6 @@ DrawLayer::~DrawLayer() = default; void DrawLayer::Initialize() { - gl::OpenGLFunctions& gl = context()->gl(); - - p->shaderProgram_ = - context()->GetShaderProgram(":/gl/color.vert", ":/gl/color.frag"); - - p->uMVPMatrixLocation_ = - gl.glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix"); - if (p->uMVPMatrixLocation_ == -1) - { - logger_->warn("Could not find uMVPMatrix"); - } - - p->shaderProgram_->Use(); - for (auto& item : p->drawList_) { item->Initialize(); @@ -65,21 +37,9 @@ void DrawLayer::Initialize() void DrawLayer::Render(const QMapbox::CustomLayerRenderParameters& params) { - gl::OpenGLFunctions& gl = context()->gl(); - - p->shaderProgram_->Use(); - - glm::mat4 projection = glm::ortho(0.0f, - static_cast(params.width), - 0.0f, - static_cast(params.height)); - - gl.glUniformMatrix4fv( - p->uMVPMatrixLocation_, 1, GL_FALSE, glm::value_ptr(projection)); - for (auto& item : p->drawList_) { - item->Render(); + item->Render(params); } } diff --git a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp index e8049e1c..a6e136fa 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp @@ -37,9 +37,9 @@ public: textShader_(context), 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())}, + activeBoxOuter_ {std::make_shared(context)}, + activeBoxInner_ {std::make_shared(context)}, + timeBox_ {std::make_shared(context)}, sweepTimeString_ {}, sweepTimeNeedsUpdate_ {true} { From ca9331cf7c93008b9079c307e38622e02bec6240 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 3 Oct 2022 00:21:31 -0500 Subject: [PATCH 08/24] Add shader programs to Geo Line class --- scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp | 39 +++++++++++++++------ scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp | 4 +-- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp index 0c65d3fc..9b5d1ebd 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp @@ -1,5 +1,6 @@ #include #include +#include #include @@ -13,6 +14,7 @@ namespace draw { static const std::string logPrefix_ = "scwx::qt::gl::draw::geo_line"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); static constexpr size_t kNumRectangles = 1; static constexpr size_t kNumTriangles = kNumRectangles * 2; @@ -25,13 +27,15 @@ static constexpr size_t kBufferLength = class GeoLine::Impl { public: - explicit Impl(OpenGLFunctions& gl) : - gl_ {gl}, + explicit Impl(std::shared_ptr context) : + context_ {context}, dirty_ {false}, visible_ {true}, points_ {}, width_ {1.0f}, modulateColor_ {std::nullopt}, + shaderProgram_ {nullptr}, + uMVPMatrixLocation_(GL_INVALID_INDEX), vao_ {GL_INVALID_INDEX}, vbo_ {GL_INVALID_INDEX} { @@ -39,7 +43,7 @@ public: ~Impl() {} - OpenGLFunctions& gl_; + std::shared_ptr context_; bool dirty_; @@ -51,6 +55,9 @@ public: // TODO: Texture + std::shared_ptr shaderProgram_; + GLint uMVPMatrixLocation_; + GLuint vao_; GLuint vbo_; @@ -58,8 +65,8 @@ public: }; // TODO: OpenGL context with shaders -GeoLine::GeoLine(OpenGLFunctions& gl) : - DrawItem(gl), p(std::make_unique(gl)) +GeoLine::GeoLine(std::shared_ptr context) : + DrawItem(context->gl()), p(std::make_unique(context)) { } GeoLine::~GeoLine() = default; @@ -69,7 +76,17 @@ GeoLine& GeoLine::operator=(GeoLine&&) noexcept = default; void GeoLine::Initialize() { - gl::OpenGLFunctions& gl = p->gl_; + gl::OpenGLFunctions& gl = p->context_->gl(); + + p->shaderProgram_ = p->context_->GetShaderProgram(":/gl/geo_line.vert", + ":/gl/texture2d.frag"); + + p->uMVPMatrixLocation_ = + gl.glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix"); + if (p->uMVPMatrixLocation_ == -1) + { + logger_->warn("Could not find uMVPMatrix"); + } gl.glGenVertexArrays(1, &p->vao_); gl.glGenBuffers(1, &p->vbo_); @@ -118,16 +135,18 @@ void GeoLine::Initialize() p->dirty_ = true; } -void GeoLine::Render(const QMapbox::CustomLayerRenderParameters&) +void GeoLine::Render(const QMapbox::CustomLayerRenderParameters& params) { if (p->visible_) { - gl::OpenGLFunctions& gl = p->gl_; + gl::OpenGLFunctions& gl = p->context_->gl(); gl.glBindVertexArray(p->vao_); gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_); p->Update(); + p->shaderProgram_->Use(); + UseDefaultProjection(params, p->uMVPMatrixLocation_); // Draw line gl.glDrawArrays(GL_TRIANGLES, 0, 6); @@ -136,7 +155,7 @@ void GeoLine::Render(const QMapbox::CustomLayerRenderParameters&) void GeoLine::Deinitialize() { - gl::OpenGLFunctions& gl = p->gl_; + gl::OpenGLFunctions& gl = p->context_->gl(); gl.glDeleteVertexArrays(1, &p->vao_); gl.glDeleteBuffers(1, &p->vbo_); @@ -185,7 +204,7 @@ void GeoLine::Impl::Update() { if (dirty_) { - gl::OpenGLFunctions& gl = gl_; + gl::OpenGLFunctions& gl = context_->gl(); const float lx = points_[0].latitude_; const float rx = points_[1].latitude_; diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp b/scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp index 7b5d6284..9ae14efb 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -17,7 +17,7 @@ namespace draw class GeoLine : public DrawItem { public: - explicit GeoLine(OpenGLFunctions& gl); + explicit GeoLine(std::shared_ptr context); ~GeoLine(); GeoLine(const GeoLine&) = delete; From 4aad9fd3d4333b777ad196e375123263e11c970b Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 3 Oct 2022 00:39:59 -0500 Subject: [PATCH 09/24] Use map projection with geo line --- scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp | 44 ++++++++++++++++++++ scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp | 3 ++ scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp | 12 +++++- 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp b/scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp index f4b37fd0..23ddbc8a 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #pragma warning(pop) namespace scwx @@ -46,6 +47,49 @@ void DrawItem::UseDefaultProjection( uMVPMatrixLocation, 1, GL_FALSE, glm::value_ptr(projection)); } +// TODO: Refactor to utility class +static glm::vec2 +LatLongToScreenCoordinate(const QMapbox::Coordinate& coordinate) +{ + double latitude = std::clamp( + coordinate.first, -mbgl::util::LATITUDE_MAX, mbgl::util::LATITUDE_MAX); + glm::vec2 screen { + mbgl::util::LONGITUDE_MAX + coordinate.second, + -(mbgl::util::LONGITUDE_MAX - + mbgl::util::RAD2DEG * + std::log(std::tan(M_PI / 4.0 + + latitude * M_PI / mbgl::util::DEGREES_MAX)))}; + return screen; +} + +void DrawItem::UseMapProjection( + const QMapbox::CustomLayerRenderParameters& params, + GLint uMVPMatrixLocation, + GLint uMapScreenCoordLocation) +{ + OpenGLFunctions& gl = p->gl_; + + // TODO: Refactor to utility class + const float scale = std::pow(2.0, params.zoom) * 2.0f * + mbgl::util::tileSize / mbgl::util::DEGREES_MAX; + const float xScale = scale / params.width; + const float yScale = scale / params.height; + + glm::mat4 uMVPMatrix(1.0f); + uMVPMatrix = glm::scale(uMVPMatrix, glm::vec3(xScale, yScale, 1.0f)); + uMVPMatrix = glm::rotate(uMVPMatrix, + glm::radians(params.bearing), + glm::vec3(0.0f, 0.0f, 1.0f)); + + gl.glUniform2fv(uMapScreenCoordLocation, + 1, + glm::value_ptr(LatLongToScreenCoordinate( + {params.latitude, params.longitude}))); + + gl.glUniformMatrix4fv( + uMVPMatrixLocation, 1, GL_FALSE, glm::value_ptr(uMVPMatrix)); +} + } // namespace draw } // namespace gl } // namespace qt diff --git a/scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp b/scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp index 32a221eb..02086c45 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp @@ -34,6 +34,9 @@ public: protected: void UseDefaultProjection(const QMapbox::CustomLayerRenderParameters& params, GLint uMVPMatrixLocation); + void UseMapProjection(const QMapbox::CustomLayerRenderParameters& params, + GLint uMVPMatrixLocation, + GLint uMapScreenCoordLocation); private: class Impl; diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp index 9b5d1ebd..2ab6047f 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp @@ -36,6 +36,7 @@ public: modulateColor_ {std::nullopt}, shaderProgram_ {nullptr}, uMVPMatrixLocation_(GL_INVALID_INDEX), + uMapScreenCoordLocation_(GL_INVALID_INDEX), vao_ {GL_INVALID_INDEX}, vbo_ {GL_INVALID_INDEX} { @@ -57,6 +58,7 @@ public: std::shared_ptr shaderProgram_; GLint uMVPMatrixLocation_; + GLint uMapScreenCoordLocation_; GLuint vao_; GLuint vbo_; @@ -88,6 +90,13 @@ void GeoLine::Initialize() logger_->warn("Could not find uMVPMatrix"); } + p->uMapScreenCoordLocation_ = + gl.glGetUniformLocation(p->shaderProgram_->id(), "uMapScreenCoord"); + if (p->uMapScreenCoordLocation_ == -1) + { + logger_->warn("Could not find uMapScreenCoord"); + } + gl.glGenVertexArrays(1, &p->vao_); gl.glGenBuffers(1, &p->vbo_); @@ -146,7 +155,8 @@ void GeoLine::Render(const QMapbox::CustomLayerRenderParameters& params) p->Update(); p->shaderProgram_->Use(); - UseDefaultProjection(params, p->uMVPMatrixLocation_); + UseMapProjection( + params, p->uMVPMatrixLocation_, p->uMapScreenCoordLocation_); // Draw line gl.glDrawArrays(GL_TRIANGLES, 0, 6); From 5ae098daff2097ffe3514a1ed06c8b007c4b02c8 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 3 Oct 2022 01:02:05 -0500 Subject: [PATCH 10/24] Geo line requires two projection matrices --- scwx-qt/gl/geo_line.vert | 6 ++++-- scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp | 13 +++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/scwx-qt/gl/geo_line.vert b/scwx-qt/gl/geo_line.vert index e232df95..4fea6910 100644 --- a/scwx-qt/gl/geo_line.vert +++ b/scwx-qt/gl/geo_line.vert @@ -12,6 +12,7 @@ layout (location = 2) in vec2 aTexCoord; layout (location = 3) in vec4 aModulate; uniform mat4 uMVPMatrix; +uniform mat4 uMapMatrix; uniform vec2 uMapScreenCoord; flat out vec2 texCoord; @@ -32,8 +33,9 @@ void main() texCoord = aTexCoord; modulate = aModulate; - vec2 p = latLngToScreenCoordinate(aLatLong) + aXYOffset - uMapScreenCoord; + vec2 p = latLngToScreenCoordinate(aLatLong) - uMapScreenCoord; // Transform the position to screen coordinates - gl_Position = uMVPMatrix * vec4(p, 0.0f, 1.0f); + gl_Position = uMapMatrix * vec4(p, 0.0f, 1.0f) - + uMVPMatrix * vec4(aXYOffset, 0.0f, 0.0f); } diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp index 2ab6047f..56f8c16b 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp @@ -36,6 +36,7 @@ public: modulateColor_ {std::nullopt}, shaderProgram_ {nullptr}, uMVPMatrixLocation_(GL_INVALID_INDEX), + uMapMatrixLocation_(GL_INVALID_INDEX), uMapScreenCoordLocation_(GL_INVALID_INDEX), vao_ {GL_INVALID_INDEX}, vbo_ {GL_INVALID_INDEX} @@ -58,6 +59,7 @@ public: std::shared_ptr shaderProgram_; GLint uMVPMatrixLocation_; + GLint uMapMatrixLocation_; GLint uMapScreenCoordLocation_; GLuint vao_; @@ -66,7 +68,6 @@ public: void Update(); }; -// TODO: OpenGL context with shaders GeoLine::GeoLine(std::shared_ptr context) : DrawItem(context->gl()), p(std::make_unique(context)) { @@ -90,6 +91,13 @@ void GeoLine::Initialize() logger_->warn("Could not find uMVPMatrix"); } + p->uMapMatrixLocation_ = + gl.glGetUniformLocation(p->shaderProgram_->id(), "uMapMatrix"); + if (p->uMapMatrixLocation_ == -1) + { + logger_->warn("Could not find uMapMatrix"); + } + p->uMapScreenCoordLocation_ = gl.glGetUniformLocation(p->shaderProgram_->id(), "uMapScreenCoord"); if (p->uMapScreenCoordLocation_ == -1) @@ -155,8 +163,9 @@ void GeoLine::Render(const QMapbox::CustomLayerRenderParameters& params) p->Update(); p->shaderProgram_->Use(); + UseDefaultProjection(params, p->uMVPMatrixLocation_); UseMapProjection( - params, p->uMVPMatrixLocation_, p->uMapScreenCoordLocation_); + params, p->uMapMatrixLocation_, p->uMapScreenCoordLocation_); // Draw line gl.glDrawArrays(GL_TRIANGLES, 0, 6); From 7b565d9c7695ada727cb68714f30f289e8264411 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 4 Oct 2022 23:09:36 -0500 Subject: [PATCH 11/24] Add stream support class for QIODevice to boost::iostreams::stream --- scwx-qt/scwx-qt.cmake | 3 ++- scwx-qt/source/scwx/qt/util/streams.hpp | 33 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 scwx-qt/source/scwx/qt/util/streams.hpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 1c4a0366..5901935e 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -106,7 +106,8 @@ set(SRC_UI source/scwx/qt/ui/flow_layout.cpp source/scwx/qt/ui/level3_products_widget.cpp) set(HDR_UTIL source/scwx/qt/util/font.hpp source/scwx/qt/util/font_buffer.hpp - source/scwx/qt/util/json.hpp) + source/scwx/qt/util/json.hpp + source/scwx/qt/util/streams.hpp) set(SRC_UTIL source/scwx/qt/util/font.cpp source/scwx/qt/util/font_buffer.cpp source/scwx/qt/util/json.cpp) diff --git a/scwx-qt/source/scwx/qt/util/streams.hpp b/scwx-qt/source/scwx/qt/util/streams.hpp new file mode 100644 index 00000000..ca3a3d9c --- /dev/null +++ b/scwx-qt/source/scwx/qt/util/streams.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace util +{ + +class IoDeviceSource +{ +public: + typedef char char_type; + typedef boost::iostreams::source_tag category; + + IoDeviceSource(QIODevice& source) : source_ {source} {} + ~IoDeviceSource() {} + + std::streamsize read(char* buffer, std::streamsize n) + { + return source_.read(buffer, n); + } + +private: + QIODevice& source_; +}; + +} // namespace util +} // namespace qt +} // namespace scwx From 82d761c93993e67cb42d6699281c1f52871db6ea Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 4 Oct 2022 23:10:05 -0500 Subject: [PATCH 12/24] Texture coordinate should be smooth, not flat --- scwx-qt/gl/geo_line.vert | 4 ++-- scwx-qt/gl/texture2d.frag | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scwx-qt/gl/geo_line.vert b/scwx-qt/gl/geo_line.vert index 4fea6910..ea7d6351 100644 --- a/scwx-qt/gl/geo_line.vert +++ b/scwx-qt/gl/geo_line.vert @@ -15,8 +15,8 @@ uniform mat4 uMVPMatrix; uniform mat4 uMapMatrix; uniform vec2 uMapScreenCoord; -flat out vec2 texCoord; -flat out vec4 modulate; +smooth out vec2 texCoord; +flat out vec4 modulate; vec2 latLngToScreenCoordinate(in vec2 latLng) { diff --git a/scwx-qt/gl/texture2d.frag b/scwx-qt/gl/texture2d.frag index 3a41c720..16ab8960 100644 --- a/scwx-qt/gl/texture2d.frag +++ b/scwx-qt/gl/texture2d.frag @@ -5,8 +5,8 @@ precision mediump float; uniform sampler2D uTexture; -flat in vec2 texCoord; -flat in vec4 modulate; +smooth in vec2 texCoord; +flat in vec4 modulate; layout (location = 0) out vec4 fragColor; From ab50f0b9a2f0f266dc3dd051602b5c0c3a7eae35 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 4 Oct 2022 23:15:52 -0500 Subject: [PATCH 13/24] Add texture loading in GlContext --- scwx-qt/source/scwx/qt/gl/gl_context.cpp | 120 ++++++++++++++++++++++- scwx-qt/source/scwx/qt/gl/gl_context.hpp | 2 + 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/scwx-qt/source/scwx/qt/gl/gl_context.cpp b/scwx-qt/source/scwx/qt/gl/gl_context.cpp index 3db875a8..8384a8ef 100644 --- a/scwx-qt/source/scwx/qt/gl/gl_context.cpp +++ b/scwx-qt/source/scwx/qt/gl/gl_context.cpp @@ -1,5 +1,14 @@ #include +#include #include +#include + +#pragma warning(push, 0) +#include +#include +#include +#include +#pragma warning(pop) namespace scwx { @@ -8,19 +17,34 @@ namespace qt namespace gl { +static const std::string logPrefix_ = "scwx::qt::gl::gl_context"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + class GlContext::Impl { public: - explicit Impl() : gl_ {}, shaderProgramMap_ {}, shaderProgramMutex_ {} {} + explicit Impl() : + gl_ {}, + shaderProgramMap_ {}, + shaderProgramMutex_ {}, + textureMap_ {}, + textureMutex_ {} + { + } ~Impl() {} + GLuint CreateTexture(const std::string& texturePath); + gl::OpenGLFunctions gl_; std::unordered_map, std::shared_ptr, - util::hash>> + scwx::util::hash>> shaderProgramMap_; std::mutex shaderProgramMutex_; + + std::unordered_map textureMap_; + std::mutex textureMutex_; }; GlContext::GlContext() : p(std::make_unique()) {} @@ -59,6 +83,98 @@ GlContext::GetShaderProgram(const std::string& vertexPath, return shaderProgram; } +GLuint GlContext::GetTexture(const std::string& texturePath) +{ + GLuint texture = GL_INVALID_INDEX; + + std::unique_lock lock(p->textureMutex_); + + auto it = p->textureMap_.find(texturePath); + + if (it == p->textureMap_.end()) + { + texture = p->CreateTexture(texturePath); + p->textureMap_[texturePath] = texture; + } + else + { + texture = it->second; + } + + return texture; +} + +// TODO: Move to dedicated file +GLuint GlContext::Impl::CreateTexture(const std::string& texturePath) +{ + logger_->warn("Create Texture: {}", texturePath); + + GLuint texture; + + QFile textureFile(texturePath.c_str()); + + textureFile.open(QIODevice::ReadOnly); + + if (!textureFile.isOpen()) + { + logger_->error("Could not load texture: {}", texturePath); + return GL_INVALID_INDEX; + } + + boost::iostreams::stream dataStream(textureFile); + + boost::gil::rgba8_image_t image; + + try + { + boost::gil::read_and_convert_image( + dataStream, image, boost::gil::png_tag()); + } + catch (const std::exception& ex) + { + logger_->error("Error reading texture: {}", ex.what()); + return GL_INVALID_INDEX; + } + + boost::gil::rgba8_view_t view = boost::gil::view(image); + + std::vector pixelData(view.width() * + view.height()); + + boost::gil::copy_pixels( + view, + boost::gil::interleaved_view(view.width(), + view.height(), + pixelData.data(), + view.width() * + sizeof(boost::gil::rgba8_pixel_t))); + + OpenGLFunctions& gl = gl_; + + gl.glGenTextures(1, &texture); + gl.glBindTexture(GL_TEXTURE_2D, texture); + + // TODO: Change to GL_REPEAT once a texture atlas is used + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl.glTexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + gl.glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + view.width(), + view.height(), + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + pixelData.data()); + gl.glGenerateMipmap(GL_TEXTURE_2D); + + return texture; +} + } // namespace gl } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/gl/gl_context.hpp b/scwx-qt/source/scwx/qt/gl/gl_context.hpp index cf81262f..d1fb6645 100644 --- a/scwx-qt/source/scwx/qt/gl/gl_context.hpp +++ b/scwx-qt/source/scwx/qt/gl/gl_context.hpp @@ -28,6 +28,8 @@ public: GetShaderProgram(const std::string& vertexPath, const std::string& fragmentPath); + GLuint GetTexture(const std::string& texturePath); + private: class Impl; From 4b1d63ea6216abe8dd2d078e317f8f4a74ff0df4 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 4 Oct 2022 23:16:57 -0500 Subject: [PATCH 14/24] Adding default texture to line, fixing texture coordinates --- scwx-qt/res/textures/lines/default-1x7.png | Bin 0 -> 486 bytes scwx-qt/res/textures/lines/test-pattern.png | Bin 0 -> 479 bytes scwx-qt/scwx-qt.qrc | 2 ++ scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp | 24 ++++++++++++-------- 4 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 scwx-qt/res/textures/lines/default-1x7.png create mode 100644 scwx-qt/res/textures/lines/test-pattern.png diff --git a/scwx-qt/res/textures/lines/default-1x7.png b/scwx-qt/res/textures/lines/default-1x7.png new file mode 100644 index 0000000000000000000000000000000000000000..0b72d67c1e88ef1ed732ed3d3834e913794c6db1 GIT binary patch literal 486 zcmV@P)EX>4Tx04R}tkv&MmKpe$iKcrGBB6bjQ$WR@`f>aSlsbUcFVPW-reS>)G@?ahO;rb+OdNtgI`<)5H;3Q7PY> zb6DoQ#aXG=S^J*+g`tAFlHoed5hSpLBvKF{p^gfwFcGCyCB;CR_Tw)8VcVY~mqe}# z7&#VDg96d^ga5(rZjItp%t;Exfu0x3`WOWQyFja9S>MN&)j9!u&%l-1@z?i4s zjutrr`nQ3L>y9Sv0hc?#(32+WqAmGodW%Ki{fxdT4-DP{!8ND1_C8J@fGl;jd;=UD z0%Il0UUzwSZ+CD1o@w{@1HxT$$2hp7I{*Lx97#k$R0!8C#IX$k00_V!;{QL_K^fpR cmB9sp1!Xn`0+>P{0RR91 literal 0 HcmV?d00001 diff --git a/scwx-qt/res/textures/lines/test-pattern.png b/scwx-qt/res/textures/lines/test-pattern.png new file mode 100644 index 0000000000000000000000000000000000000000..b9a0224e943aec2d703c4606d3ea9c58a5df89d6 GIT binary patch literal 479 zcmV<50U-W~P)EX>4Tx04R}tkv&MmKpe$iKcrGBB6bjQ$WR@`f>aSlsbUcFVPW-reS>)G@?ahO;rb+OdNtgI`<)5H;3Q7PY> zb6DoQ#aXG=S^J*+g`tAFlHoed5hSpLBvKF{p^gfwFcGCyCB;CR_Tw)8VcVY~mqe}# z7&#VDg96d^ga5(rZjItp%t;Exfu0x3`WOWQyFja9S>MN&)j9!u&%l-1@z?i4s zjutrr`nQ3L>y9Sv0hc?#(32+WqAmGodW%Ki{fxdT4-DP{!8ND1_C8J@fGl;jd;=UD z0%Il0UUzwSZ+CD1o@w{@1HxT$$2hp7I{*Lx6-h)vR0!7v!2tmP004jx|4$b}P#GTY V1pJFeHCO-u002ovPDHLkV1l7j(enTR literal 0 HcmV?d00001 diff --git a/scwx-qt/scwx-qt.qrc b/scwx-qt/scwx-qt.qrc index bf64e1fd..cf31a039 100644 --- a/scwx-qt/scwx-qt.qrc +++ b/scwx-qt/scwx-qt.qrc @@ -15,5 +15,7 @@ res/fonts/din1451alt_g.ttf res/icons/font-awesome-6/square-minus-regular.svg res/icons/font-awesome-6/square-plus-regular.svg + res/textures/lines/default-1x7.png + res/textures/lines/test-pattern.png diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp index 56f8c16b..47350dd2 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp @@ -32,12 +32,13 @@ public: dirty_ {false}, visible_ {true}, points_ {}, - width_ {1.0f}, + width_ {7.0f}, modulateColor_ {std::nullopt}, shaderProgram_ {nullptr}, uMVPMatrixLocation_(GL_INVALID_INDEX), uMapMatrixLocation_(GL_INVALID_INDEX), uMapScreenCoordLocation_(GL_INVALID_INDEX), + texture_ {GL_INVALID_INDEX}, vao_ {GL_INVALID_INDEX}, vbo_ {GL_INVALID_INDEX} { @@ -55,13 +56,12 @@ public: std::optional modulateColor_; - // TODO: Texture - std::shared_ptr shaderProgram_; GLint uMVPMatrixLocation_; GLint uMapMatrixLocation_; GLint uMapScreenCoordLocation_; + GLuint texture_; GLuint vao_; GLuint vbo_; @@ -105,6 +105,9 @@ void GeoLine::Initialize() logger_->warn("Could not find uMapScreenCoord"); } + p->texture_ = + p->context_->GetTexture(":/res/textures/lines/default-1x7.png"); + gl.glGenVertexArrays(1, &p->vao_); gl.glGenBuffers(1, &p->vbo_); @@ -167,6 +170,9 @@ void GeoLine::Render(const QMapbox::CustomLayerRenderParameters& params) UseMapProjection( params, p->uMapMatrixLocation_, p->uMapScreenCoordLocation_); + gl.glActiveTexture(GL_TEXTURE0); + gl.glBindTexture(GL_TEXTURE_2D, p->texture_); + // Draw line gl.glDrawArrays(GL_TRIANGLES, 0, 6); } @@ -256,12 +262,12 @@ void GeoLine::Impl::Update() { // // Line { - {lx, by, -ox, -oy, 0.0f, 0.0f, mc0, mc1, mc2, mc3}, // BL - {lx, by, +ox, +oy, 0.0f, 1.0f, mc0, mc1, mc2, mc3}, // TL - {rx, ty, -ox, -oy, 1.0f, 0.0f, mc0, mc1, mc2, mc3}, // BR - {rx, ty, -ox, -oy, 1.0f, 0.0f, mc0, mc1, mc2, mc3}, // BR - {rx, ty, +ox, +oy, 1.0f, 1.0f, mc0, mc1, mc2, mc3}, // TR - {lx, by, +ox, +oy, 0.0f, 1.0f, mc0, mc1, mc2, mc3} // TL + {lx, by, -ox, -oy, 0.0f, 1.0f, mc0, mc1, mc2, mc3}, // BL + {lx, by, +ox, +oy, 0.0f, 0.0f, mc0, mc1, mc2, mc3}, // TL + {rx, ty, -ox, -oy, 1.0f, 1.0f, mc0, mc1, mc2, mc3}, // BR + {rx, ty, -ox, -oy, 1.0f, 1.0f, mc0, mc1, mc2, mc3}, // BR + {rx, ty, +ox, +oy, 1.0f, 0.0f, mc0, mc1, mc2, mc3}, // TR + {lx, by, +ox, +oy, 0.0f, 0.0f, mc0, mc1, mc2, mc3} // TL }}; gl.glBufferData(GL_ARRAY_BUFFER, From 365cc7c02c7f42576813d583c89a63d662d4e167 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 4 Oct 2022 23:24:21 -0500 Subject: [PATCH 15/24] Add stb header library for texture atlas dependency --- .gitmodules | 3 +++ external/CMakeLists.txt | 4 +++- external/stb | 1 + external/stb.cmake | 4 ++++ scwx-qt/scwx-qt.cmake | 3 ++- 5 files changed, 13 insertions(+), 2 deletions(-) create mode 160000 external/stb create mode 100644 external/stb.cmake diff --git a/.gitmodules b/.gitmodules index 81c8ed32..2bba2042 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "external/freetype-gl"] path = external/freetype-gl url = https://github.com/rougier/freetype-gl.git +[submodule "external/stb"] + path = external/stb + url = https://github.com/nothings/stb.git diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 37fbfe4c..221957b0 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -6,8 +6,10 @@ set_property(DIRECTORY PROPERTY CMAKE_CONFIGURE_DEPENDS freetype-gl.cmake hsluv-c.cmake - mapbox-gl-native.cmake) + mapbox-gl-native.cmake + stb.cmake) include(freetype-gl.cmake) include(hsluv-c.cmake) include(mapbox-gl-native.cmake) +include(stb.cmake) diff --git a/external/stb b/external/stb new file mode 160000 index 00000000..8b5f1f37 --- /dev/null +++ b/external/stb @@ -0,0 +1 @@ +Subproject commit 8b5f1f37b5b75829fc72d38e7b5d4bcbf8a26d55 diff --git a/external/stb.cmake b/external/stb.cmake new file mode 100644 index 00000000..52bbf5f2 --- /dev/null +++ b/external/stb.cmake @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.19) +set(PROJECT_NAME scwx-stb) + +set(STB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/stb PARENT_SCOPE) diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 5901935e..7fef2526 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -231,7 +231,8 @@ endif() target_include_directories(scwx-qt PUBLIC ${scwx-qt_SOURCE_DIR}/source ${FTGL_INCLUDE_DIR} - ${MBGL_INCLUDE_DIR}) + ${MBGL_INCLUDE_DIR} + ${STB_INCLUDE_DIR}) target_include_directories(supercell-wx PUBLIC ${scwx-qt_SOURCE_DIR}/source) From 49eba4e8398432c10e1a29925433d00cb51a5adb Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 4 Oct 2022 23:33:33 -0500 Subject: [PATCH 16/24] Fixing MSVC compile error due to warning in boost::gil --- scwx-qt/source/scwx/qt/gl/gl_context.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/scwx-qt/source/scwx/qt/gl/gl_context.cpp b/scwx-qt/source/scwx/qt/gl/gl_context.cpp index 8384a8ef..31f65de3 100644 --- a/scwx-qt/source/scwx/qt/gl/gl_context.cpp +++ b/scwx-qt/source/scwx/qt/gl/gl_context.cpp @@ -4,6 +4,7 @@ #include #pragma warning(push, 0) +#pragma warning(disable : 4714) #include #include #include From 031e175fed9501b6c39db0ecb194141ccb09dc0f Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 4 Oct 2022 23:46:43 -0500 Subject: [PATCH 17/24] Add stb_rect_pack implementation --- scwx-qt/scwx-qt.cmake | 3 +++ scwx-qt/source/scwx/qt/external/stb_rect_pack.cpp | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 scwx-qt/source/scwx/qt/external/stb_rect_pack.cpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 7fef2526..3a239c22 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -40,6 +40,7 @@ set(SRC_MAIN source/scwx/qt/main/main_window.cpp) set(UI_MAIN source/scwx/qt/main/main_window.ui) set(HDR_CONFIG source/scwx/qt/config/radar_site.hpp) set(SRC_CONFIG source/scwx/qt/config/radar_site.cpp) +set(SRC_EXTERNAL source/scwx/qt/external/stb_rect_pack.cpp) set(HDR_GL source/scwx/qt/gl/gl.hpp source/scwx/qt/gl/gl_context.hpp source/scwx/qt/gl/shader_program.hpp @@ -147,6 +148,7 @@ set(PROJECT_SOURCES ${HDR_MAIN} ${SRC_MAIN} ${HDR_CONFIG} ${SRC_CONFIG} + ${SRC_EXTERNAL} ${HDR_GL} ${SRC_GL} ${HDR_GL_DRAW} @@ -181,6 +183,7 @@ source_group("Header Files\\main" FILES ${HDR_MAIN}) source_group("Source Files\\main" FILES ${SRC_MAIN}) source_group("Header Files\\config" FILES ${HDR_CONFIG}) source_group("Source Files\\config" FILES ${SRC_CONFIG}) +source_group("Source Files\\external" FILES ${SRC_EXTERNAL}) source_group("Header Files\\gl" FILES ${HDR_GL}) source_group("Source Files\\gl" FILES ${SRC_GL}) source_group("Header Files\\gl\\draw" FILES ${HDR_GL_DRAW}) diff --git a/scwx-qt/source/scwx/qt/external/stb_rect_pack.cpp b/scwx-qt/source/scwx/qt/external/stb_rect_pack.cpp new file mode 100644 index 00000000..32d48134 --- /dev/null +++ b/scwx-qt/source/scwx/qt/external/stb_rect_pack.cpp @@ -0,0 +1,2 @@ +#define STB_RECT_PACK_IMPLEMENTATION +#include From 17192470ec7afea39356a711c2ef30469d16f6dd Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 5 Oct 2022 22:41:39 -0500 Subject: [PATCH 18/24] Initial texture atlas creation implementation --- scwx-qt/scwx-qt.cmake | 6 +- scwx-qt/source/scwx/qt/util/texture_atlas.cpp | 268 ++++++++++++++++++ scwx-qt/source/scwx/qt/util/texture_atlas.hpp | 41 +++ 3 files changed, 313 insertions(+), 2 deletions(-) create mode 100644 scwx-qt/source/scwx/qt/util/texture_atlas.cpp create mode 100644 scwx-qt/source/scwx/qt/util/texture_atlas.hpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 3a239c22..51ba42cf 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -108,10 +108,12 @@ set(SRC_UI source/scwx/qt/ui/flow_layout.cpp set(HDR_UTIL source/scwx/qt/util/font.hpp source/scwx/qt/util/font_buffer.hpp source/scwx/qt/util/json.hpp - source/scwx/qt/util/streams.hpp) + source/scwx/qt/util/streams.hpp + source/scwx/qt/util/texture_atlas.hpp) set(SRC_UTIL source/scwx/qt/util/font.cpp source/scwx/qt/util/font_buffer.cpp - source/scwx/qt/util/json.cpp) + source/scwx/qt/util/json.cpp + source/scwx/qt/util/texture_atlas.cpp) set(HDR_VIEW source/scwx/qt/view/level2_product_view.hpp source/scwx/qt/view/level3_product_view.hpp source/scwx/qt/view/level3_radial_view.hpp diff --git a/scwx-qt/source/scwx/qt/util/texture_atlas.cpp b/scwx-qt/source/scwx/qt/util/texture_atlas.cpp new file mode 100644 index 00000000..6047550e --- /dev/null +++ b/scwx-qt/source/scwx/qt/util/texture_atlas.cpp @@ -0,0 +1,268 @@ +#include +#include +#include + +#include +#include + +#pragma warning(push, 0) +#pragma warning(disable : 4714) +#include +#include +#include +#include +#pragma warning(pop) + +namespace scwx +{ +namespace qt +{ +namespace util +{ + +static const std::string logPrefix_ = "scwx::qt::util::texture_atlas"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + +struct TextureInfo +{ + TextureInfo(boost::gil::point_t position, boost::gil::point_t size) : + position_ {position}, size_ {size} + { + } + + boost::gil::point_t position_; + boost::gil::point_t size_; +}; + +class TextureAtlas::Impl +{ +public: + explicit Impl() : + texturePathMap_ {}, + texturePathMutex_ {}, + atlas_ {}, + atlasMap_ {}, + atlasMutex_ {} + { + } + ~Impl() {} + + static boost::gil::rgba8_image_t LoadImage(const std::string& imagePath); + + std::unordered_map texturePathMap_; + std::shared_mutex texturePathMutex_; + + boost::gil::rgba8_image_t atlas_; + std::unordered_map atlasMap_; + std::shared_mutex atlasMutex_; +}; + +TextureAtlas::TextureAtlas() : p(std::make_unique()) {} +TextureAtlas::~TextureAtlas() = default; + +TextureAtlas::TextureAtlas(TextureAtlas&&) noexcept = default; +TextureAtlas& TextureAtlas::operator=(TextureAtlas&&) noexcept = default; + +void TextureAtlas::RegisterTexture(const std::string& name, + const std::string& path) +{ + std::unique_lock lock(p->texturePathMutex_); + p->texturePathMap_.insert_or_assign(name, path); +} + +void TextureAtlas::BuildAtlas(size_t width, size_t height) +{ + logger_->debug("Building {}x{} texture atlas", width, height); + + if (width > INT_MAX || height > INT_MAX) + { + logger_->error("Cannot build texture atlas of size {}x{}", width, height); + return; + } + + std::vector> images; + std::vector stbrpRects; + + // Load images + { + // Take a read lock on the texture path map + std::shared_lock lock(p->texturePathMutex_); + + // For each registered texture + std::for_each(p->texturePathMap_.cbegin(), + p->texturePathMap_.cend(), + [&](const auto& pair) + { + // Load texture image + boost::gil::rgba8_image_t image = + Impl::LoadImage(pair.second); + + if (image.width() > 0u && image.height() > 0u) + { + // Store STB rectangle pack data in a vector + stbrpRects.push_back(stbrp_rect { + 0, + static_cast(image.width()), + static_cast(image.height()), + 0, + 0, + 0}); + + // Store image data in a vector + images.emplace_back(pair.first, std::move(image)); + } + }); + } + + // Pack images + { + logger_->trace("Packing {} images", images.size()); + + // Optimal number of nodes = width + stbrp_context stbrpContext; + std::vector stbrpNodes(width); + + stbrp_init_target(&stbrpContext, + static_cast(width), + static_cast(height), + stbrpNodes.data(), + static_cast(stbrpNodes.size())); + + // Pack loaded textures + stbrp_pack_rects( + &stbrpContext, stbrpRects.data(), static_cast(stbrpRects.size())); + } + + // Lock atlas + std::unique_lock lock(p->atlasMutex_); + + // Clear index + p->atlasMap_.clear(); + + // Clear atlas + p->atlas_.recreate(width, height); + boost::gil::rgba8_view_t atlasView = boost::gil::view(p->atlas_); + + // Populate atlas + logger_->trace("Populating atlas"); + + for (size_t i = 0; i < images.size(); i++) + { + // If the image was packed successfully + if (stbrpRects[i].was_packed != 0) + { + // Populate the atlas + boost::gil::rgba8c_view_t imageView = + boost::gil::const_view(images[i].second); + boost::gil::rgba8_view_t atlasSubView = + boost::gil::subimage_view(atlasView, + stbrpRects[i].x, + stbrpRects[i].y, + imageView.width(), + imageView.height()); + + boost::gil::copy_pixels(imageView, atlasSubView); + + // Add texture image to the index + p->atlasMap_.emplace( + std::piecewise_construct, + std::forward_as_tuple(images[i].first), + std::forward_as_tuple( + boost::gil::point_t {stbrpRects[i].x, stbrpRects[i].y}, + boost::gil::point_t {imageView.width(), imageView.height()})); + } + else + { + logger_->warn("Unable to pack texture: {}", images[i].first); + } + } +} + +GLuint TextureAtlas::BufferAtlas(gl::OpenGLFunctions& gl) +{ + GLuint texture = GL_INVALID_INDEX; + + std::shared_lock lock(p->atlasMutex_); + + if (p->atlas_.width() > 0u && p->atlas_.height() > 0u) + { + boost::gil::rgba8_view_t view = boost::gil::view(p->atlas_); + std::vector pixelData(view.width() * + view.height()); + + boost::gil::copy_pixels( + view, + boost::gil::interleaved_view(view.width(), + view.height(), + pixelData.data(), + view.width() * + sizeof(boost::gil::rgba8_pixel_t))); + + lock.unlock(); + + gl.glGenTextures(1, &texture); + gl.glBindTexture(GL_TEXTURE_2D, texture); + + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + gl.glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + view.width(), + view.height(), + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + pixelData.data()); + } + + return texture; +} + +boost::gil::rgba8_image_t +TextureAtlas::Impl::LoadImage(const std::string& imagePath) +{ + logger_->debug("Loading image: {}", imagePath); + + boost::gil::rgba8_image_t image; + + QFile imageFile(imagePath.c_str()); + + imageFile.open(QIODevice::ReadOnly); + + if (!imageFile.isOpen()) + { + logger_->error("Could not open image: {}", imagePath); + return std::move(image); + } + + boost::iostreams::stream dataStream(imageFile); + + boost::gil::image x; + + try + { + boost::gil::read_and_convert_image( + dataStream, image, boost::gil::png_tag()); + } + catch (const std::exception& ex) + { + logger_->error("Error reading image: {}", ex.what()); + return std::move(image); + } + + return std::move(image); +} + +TextureAtlas& TextureAtlas::Instance() +{ + static TextureAtlas instance_ {}; + return instance_; +} + +} // namespace util +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/util/texture_atlas.hpp b/scwx-qt/source/scwx/qt/util/texture_atlas.hpp new file mode 100644 index 00000000..b442f540 --- /dev/null +++ b/scwx-qt/source/scwx/qt/util/texture_atlas.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace util +{ + +class TextureAtlas +{ +public: + explicit TextureAtlas(); + ~TextureAtlas(); + + TextureAtlas(const TextureAtlas&) = delete; + TextureAtlas& operator=(const TextureAtlas&) = delete; + + TextureAtlas(TextureAtlas&&) noexcept; + TextureAtlas& operator=(TextureAtlas&&) noexcept; + + static TextureAtlas& Instance(); + + void RegisterTexture(const std::string& name, const std::string& path); + void BuildAtlas(size_t width, size_t height); + GLuint BufferAtlas(gl::OpenGLFunctions& gl); + +private: + class Impl; + + std::unique_ptr p; +}; + +} // namespace util +} // namespace qt +} // namespace scwx From 71d873f4b40a69b984fcb24f6e0c837517e1e6e0 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 5 Oct 2022 22:42:06 -0500 Subject: [PATCH 19/24] Populate default texture atlas --- scwx-qt/source/scwx/qt/manager/resource_manager.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp index 12d041d9..748a1194 100644 --- a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace scwx { @@ -20,6 +21,13 @@ static void LoadFonts() { util::Font::Create(":/res/fonts/din1451alt.ttf"); util::Font::Create(":/res/fonts/din1451alt_g.ttf"); + + util::TextureAtlas& textureAtlas = util::TextureAtlas::Instance(); + textureAtlas.RegisterTexture("lines/default-1x7", + ":/res/textures/lines/default-1x7.png"); + textureAtlas.RegisterTexture("lines/test-pattern", + ":/res/textures/lines/test-pattern.png"); + textureAtlas.BuildAtlas(8, 8); } } // namespace ResourceManager From e4629eb9ef1f1b22d42f03852bb914461e0b6e02 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 5 Oct 2022 23:10:23 -0500 Subject: [PATCH 20/24] Expose texture attributes in interface --- scwx-qt/source/scwx/qt/util/texture_atlas.cpp | 54 +++++++++++++------ scwx-qt/source/scwx/qt/util/texture_atlas.hpp | 42 +++++++++++++++ 2 files changed, 80 insertions(+), 16 deletions(-) diff --git a/scwx-qt/source/scwx/qt/util/texture_atlas.cpp b/scwx-qt/source/scwx/qt/util/texture_atlas.cpp index 6047550e..7ff156f4 100644 --- a/scwx-qt/source/scwx/qt/util/texture_atlas.cpp +++ b/scwx-qt/source/scwx/qt/util/texture_atlas.cpp @@ -23,17 +23,6 @@ namespace util static const std::string logPrefix_ = "scwx::qt::util::texture_atlas"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); -struct TextureInfo -{ - TextureInfo(boost::gil::point_t position, boost::gil::point_t size) : - position_ {position}, size_ {size} - { - } - - boost::gil::point_t position_; - boost::gil::point_t size_; -}; - class TextureAtlas::Impl { public: @@ -52,9 +41,9 @@ public: std::unordered_map texturePathMap_; std::shared_mutex texturePathMutex_; - boost::gil::rgba8_image_t atlas_; - std::unordered_map atlasMap_; - std::shared_mutex atlasMutex_; + boost::gil::rgba8_image_t atlas_; + std::unordered_map atlasMap_; + std::shared_mutex atlasMutex_; }; TextureAtlas::TextureAtlas() : p(std::make_unique()) {} @@ -146,6 +135,11 @@ void TextureAtlas::BuildAtlas(size_t width, size_t height) // Populate atlas logger_->trace("Populating atlas"); + const float xStep = 1.0f / width; + const float yStep = 1.0f / height; + const float xMin = xStep * 0.5f; + const float yMin = yStep * 0.5f; + for (size_t i = 0; i < images.size(); i++) { // If the image was packed successfully @@ -164,12 +158,26 @@ void TextureAtlas::BuildAtlas(size_t width, size_t height) boost::gil::copy_pixels(imageView, atlasSubView); // Add texture image to the index + const stbrp_coord x = stbrpRects[i].x; + const stbrp_coord y = stbrpRects[i].y; + + const float sLeft = x * xStep + xMin; + const float sRight = + sLeft + static_cast(imageView.width() - 1) / width; + const float tTop = y * yStep + yMin; + const float tBottom = + tTop + static_cast(imageView.height() - 1) / height; + p->atlasMap_.emplace( std::piecewise_construct, std::forward_as_tuple(images[i].first), std::forward_as_tuple( - boost::gil::point_t {stbrpRects[i].x, stbrpRects[i].y}, - boost::gil::point_t {imageView.width(), imageView.height()})); + boost::gil::point_t {x, y}, + boost::gil::point_t {imageView.width(), imageView.height()}, + sLeft, + sRight, + tTop, + tBottom)); } else { @@ -222,6 +230,20 @@ GLuint TextureAtlas::BufferAtlas(gl::OpenGLFunctions& gl) return texture; } +TextureAttributes TextureAtlas::GetTextureAttributes(const std::string& name) +{ + TextureAttributes attr {}; + std::shared_lock lock(p->atlasMutex_); + + const auto& it = p->atlasMap_.find(name); + if (it != p->atlasMap_.cend()) + { + attr = it->second; + } + + return attr; +} + boost::gil::rgba8_image_t TextureAtlas::Impl::LoadImage(const std::string& imagePath) { diff --git a/scwx-qt/source/scwx/qt/util/texture_atlas.hpp b/scwx-qt/source/scwx/qt/util/texture_atlas.hpp index b442f540..bf904e6c 100644 --- a/scwx-qt/source/scwx/qt/util/texture_atlas.hpp +++ b/scwx-qt/source/scwx/qt/util/texture_atlas.hpp @@ -5,6 +5,8 @@ #include #include +#include + namespace scwx { namespace qt @@ -12,6 +14,44 @@ namespace qt namespace util { +struct TextureAttributes +{ + TextureAttributes() : + valid_ {false}, + position_ {}, + size_ {}, + sLeft_ {}, + sRight_ {}, + tTop_ {}, + tBottom_ {} + { + } + + TextureAttributes(boost::gil::point_t position, + boost::gil::point_t size, + float sLeft, + float sRight, + float tTop, + float tBottom) : + valid_ {true}, + position_ {position}, + size_ {size}, + sLeft_ {sLeft}, + sRight_ {sRight}, + tTop_ {tTop}, + tBottom_ {tBottom} + { + } + + bool valid_; + boost::gil::point_t position_; + boost::gil::point_t size_; + float sLeft_; + float sRight_; + float tTop_; + float tBottom_; +}; + class TextureAtlas { public: @@ -30,6 +70,8 @@ public: void BuildAtlas(size_t width, size_t height); GLuint BufferAtlas(gl::OpenGLFunctions& gl); + TextureAttributes GetTextureAttributes(const std::string& name); + private: class Impl; From fb371390737dae683b775efbf7d296c37494c31c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Thu, 6 Oct 2022 00:32:15 -0500 Subject: [PATCH 21/24] Manage texture atlas in GL context --- scwx-qt/source/scwx/qt/gl/gl_context.cpp | 15 +++++++++++++++ scwx-qt/source/scwx/qt/gl/gl_context.hpp | 1 + 2 files changed, 16 insertions(+) diff --git a/scwx-qt/source/scwx/qt/gl/gl_context.cpp b/scwx-qt/source/scwx/qt/gl/gl_context.cpp index 31f65de3..e7657b03 100644 --- a/scwx-qt/source/scwx/qt/gl/gl_context.cpp +++ b/scwx-qt/source/scwx/qt/gl/gl_context.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -29,6 +30,7 @@ public: shaderProgramMap_ {}, shaderProgramMutex_ {}, textureMap_ {}, + textureAtlas_ {GL_INVALID_INDEX}, textureMutex_ {} { } @@ -45,6 +47,7 @@ public: std::mutex shaderProgramMutex_; std::unordered_map textureMap_; + GLuint textureAtlas_; std::mutex textureMutex_; }; @@ -84,6 +87,18 @@ GlContext::GetShaderProgram(const std::string& vertexPath, return shaderProgram; } +GLuint GlContext::GetTextureAtlas() +{ + std::unique_lock lock(p->textureMutex_); + + if (p->textureAtlas_ == GL_INVALID_INDEX) + { + p->textureAtlas_ = util::TextureAtlas::Instance().BufferAtlas(p->gl_); + } + + return p->textureAtlas_; +} + GLuint GlContext::GetTexture(const std::string& texturePath) { GLuint texture = GL_INVALID_INDEX; diff --git a/scwx-qt/source/scwx/qt/gl/gl_context.hpp b/scwx-qt/source/scwx/qt/gl/gl_context.hpp index d1fb6645..69802534 100644 --- a/scwx-qt/source/scwx/qt/gl/gl_context.hpp +++ b/scwx-qt/source/scwx/qt/gl/gl_context.hpp @@ -28,6 +28,7 @@ public: GetShaderProgram(const std::string& vertexPath, const std::string& fragmentPath); + GLuint GetTextureAtlas(); GLuint GetTexture(const std::string& texturePath); private: From d3f7347be0b510c99e757254bd492cf567ca67a9 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Thu, 6 Oct 2022 00:32:51 -0500 Subject: [PATCH 22/24] Texture atlas should fill unused pixels with magenta --- scwx-qt/source/scwx/qt/util/texture_atlas.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scwx-qt/source/scwx/qt/util/texture_atlas.cpp b/scwx-qt/source/scwx/qt/util/texture_atlas.cpp index 7ff156f4..22a7f0f7 100644 --- a/scwx-qt/source/scwx/qt/util/texture_atlas.cpp +++ b/scwx-qt/source/scwx/qt/util/texture_atlas.cpp @@ -131,6 +131,8 @@ void TextureAtlas::BuildAtlas(size_t width, size_t height) // Clear atlas p->atlas_.recreate(width, height); boost::gil::rgba8_view_t atlasView = boost::gil::view(p->atlas_); + boost::gil::fill_pixels(atlasView, + boost::gil::rgba8_pixel_t {255, 0, 255, 255}); // Populate atlas logger_->trace("Populating atlas"); From 0fa6ef01f0a42ae32a5d27e35beffb345e359bf7 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Thu, 6 Oct 2022 00:35:22 -0500 Subject: [PATCH 23/24] Move texture binding to layer, and reference atlas coordinates in draw item --- scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp | 31 +++++++++++++-------- scwx-qt/source/scwx/qt/map/draw_layer.cpp | 16 ++++++++++- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp index 47350dd2..b44463ff 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -38,7 +39,7 @@ public: uMVPMatrixLocation_(GL_INVALID_INDEX), uMapMatrixLocation_(GL_INVALID_INDEX), uMapScreenCoordLocation_(GL_INVALID_INDEX), - texture_ {GL_INVALID_INDEX}, + texture_ {}, vao_ {GL_INVALID_INDEX}, vbo_ {GL_INVALID_INDEX} { @@ -61,7 +62,8 @@ public: GLint uMapMatrixLocation_; GLint uMapScreenCoordLocation_; - GLuint texture_; + util::TextureAttributes texture_; + GLuint vao_; GLuint vbo_; @@ -106,7 +108,7 @@ void GeoLine::Initialize() } p->texture_ = - p->context_->GetTexture(":/res/textures/lines/default-1x7.png"); + util::TextureAtlas::Instance().GetTextureAttributes("lines/default-1x7"); gl.glGenVertexArrays(1, &p->vao_); gl.glGenBuffers(1, &p->vbo_); @@ -170,9 +172,6 @@ void GeoLine::Render(const QMapbox::CustomLayerRenderParameters& params) UseMapProjection( params, p->uMapMatrixLocation_, p->uMapScreenCoordLocation_); - gl.glActiveTexture(GL_TEXTURE0); - gl.glBindTexture(GL_TEXTURE_2D, p->texture_); - // Draw line gl.glDrawArrays(GL_TRIANGLES, 0, 6); } @@ -231,17 +230,25 @@ void GeoLine::Impl::Update() { gl::OpenGLFunctions& gl = context_->gl(); + // Latitude and longitude coordinates in degrees const float lx = points_[0].latitude_; const float rx = points_[1].latitude_; const float by = points_[0].longitude_; const float ty = points_[1].longitude_; + // Offset x/y in pixels const double i = points_[1].longitude_ - points_[0].longitude_; const double j = points_[1].latitude_ - points_[0].latitude_; const double angle = std::atan2(i, j) * 180.0 / M_PI; const float ox = width_ * 0.5f * std::cosf(angle); const float oy = width_ * 0.5f * std::sinf(angle); + // Texture coordinates + const float ls = texture_.sLeft_; + const float rs = texture_.sRight_; + const float tt = texture_.tTop_; + const float bt = texture_.tBottom_; + float mc0 = 1.0f; float mc1 = 1.0f; float mc2 = 1.0f; @@ -262,12 +269,12 @@ void GeoLine::Impl::Update() { // // Line { - {lx, by, -ox, -oy, 0.0f, 1.0f, mc0, mc1, mc2, mc3}, // BL - {lx, by, +ox, +oy, 0.0f, 0.0f, mc0, mc1, mc2, mc3}, // TL - {rx, ty, -ox, -oy, 1.0f, 1.0f, mc0, mc1, mc2, mc3}, // BR - {rx, ty, -ox, -oy, 1.0f, 1.0f, mc0, mc1, mc2, mc3}, // BR - {rx, ty, +ox, +oy, 1.0f, 0.0f, mc0, mc1, mc2, mc3}, // TR - {lx, by, +ox, +oy, 0.0f, 0.0f, mc0, mc1, mc2, mc3} // TL + {lx, by, -ox, -oy, ls, bt, mc0, mc1, mc2, mc3}, // BL + {lx, by, +ox, +oy, ls, tt, mc0, mc1, mc2, mc3}, // TL + {rx, ty, -ox, -oy, rs, bt, mc0, mc1, mc2, mc3}, // BR + {rx, ty, -ox, -oy, rs, bt, mc0, mc1, mc2, mc3}, // BR + {rx, ty, +ox, +oy, rs, tt, mc0, mc1, mc2, mc3}, // TR + {lx, by, +ox, +oy, ls, tt, mc0, mc1, mc2, mc3} // TL }}; gl.glBufferData(GL_ARRAY_BUFFER, diff --git a/scwx-qt/source/scwx/qt/map/draw_layer.cpp b/scwx-qt/source/scwx/qt/map/draw_layer.cpp index 970bf89c..47a3f6c4 100644 --- a/scwx-qt/source/scwx/qt/map/draw_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/draw_layer.cpp @@ -15,10 +15,15 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_); class DrawLayerImpl { public: - explicit DrawLayerImpl(std::shared_ptr context) {} + explicit DrawLayerImpl(std::shared_ptr context) : + context_ {context}, drawList_ {}, textureAtlas_ {GL_INVALID_INDEX} + { + } ~DrawLayerImpl() {} + std::shared_ptr context_; std::vector> drawList_; + GLuint textureAtlas_; }; DrawLayer::DrawLayer(std::shared_ptr context) : @@ -29,6 +34,8 @@ DrawLayer::~DrawLayer() = default; void DrawLayer::Initialize() { + p->textureAtlas_ = p->context_->GetTextureAtlas(); + for (auto& item : p->drawList_) { item->Initialize(); @@ -37,6 +44,11 @@ void DrawLayer::Initialize() void DrawLayer::Render(const QMapbox::CustomLayerRenderParameters& params) { + gl::OpenGLFunctions& gl = p->context_->gl(); + + gl.glActiveTexture(GL_TEXTURE0); + gl.glBindTexture(GL_TEXTURE_2D, p->textureAtlas_); + for (auto& item : p->drawList_) { item->Render(params); @@ -45,6 +57,8 @@ void DrawLayer::Render(const QMapbox::CustomLayerRenderParameters& params) void DrawLayer::Deinitialize() { + p->textureAtlas_ = GL_INVALID_INDEX; + for (auto& item : p->drawList_) { item->Deinitialize(); From 507b2c4f5958054c1d726548a95455930045e964 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Thu, 6 Oct 2022 00:40:36 -0500 Subject: [PATCH 24/24] Removing unused texture loading routines from GL context --- scwx-qt/source/scwx/qt/gl/gl_context.cpp | 110 +---------------------- scwx-qt/source/scwx/qt/gl/gl_context.hpp | 1 - 2 files changed, 2 insertions(+), 109 deletions(-) diff --git a/scwx-qt/source/scwx/qt/gl/gl_context.cpp b/scwx-qt/source/scwx/qt/gl/gl_context.cpp index e7657b03..d0e0fd80 100644 --- a/scwx-qt/source/scwx/qt/gl/gl_context.cpp +++ b/scwx-qt/source/scwx/qt/gl/gl_context.cpp @@ -1,17 +1,8 @@ #include -#include #include #include #include -#pragma warning(push, 0) -#pragma warning(disable : 4714) -#include -#include -#include -#include -#pragma warning(pop) - namespace scwx { namespace qt @@ -20,7 +11,6 @@ namespace gl { static const std::string logPrefix_ = "scwx::qt::gl::gl_context"; -static const auto logger_ = scwx::util::Logger::Create(logPrefix_); class GlContext::Impl { @@ -29,15 +19,12 @@ public: gl_ {}, shaderProgramMap_ {}, shaderProgramMutex_ {}, - textureMap_ {}, textureAtlas_ {GL_INVALID_INDEX}, textureMutex_ {} { } ~Impl() {} - GLuint CreateTexture(const std::string& texturePath); - gl::OpenGLFunctions gl_; std::unordered_map, @@ -46,9 +33,8 @@ public: shaderProgramMap_; std::mutex shaderProgramMutex_; - std::unordered_map textureMap_; - GLuint textureAtlas_; - std::mutex textureMutex_; + GLuint textureAtlas_; + std::mutex textureMutex_; }; GlContext::GlContext() : p(std::make_unique()) {} @@ -99,98 +85,6 @@ GLuint GlContext::GetTextureAtlas() return p->textureAtlas_; } -GLuint GlContext::GetTexture(const std::string& texturePath) -{ - GLuint texture = GL_INVALID_INDEX; - - std::unique_lock lock(p->textureMutex_); - - auto it = p->textureMap_.find(texturePath); - - if (it == p->textureMap_.end()) - { - texture = p->CreateTexture(texturePath); - p->textureMap_[texturePath] = texture; - } - else - { - texture = it->second; - } - - return texture; -} - -// TODO: Move to dedicated file -GLuint GlContext::Impl::CreateTexture(const std::string& texturePath) -{ - logger_->warn("Create Texture: {}", texturePath); - - GLuint texture; - - QFile textureFile(texturePath.c_str()); - - textureFile.open(QIODevice::ReadOnly); - - if (!textureFile.isOpen()) - { - logger_->error("Could not load texture: {}", texturePath); - return GL_INVALID_INDEX; - } - - boost::iostreams::stream dataStream(textureFile); - - boost::gil::rgba8_image_t image; - - try - { - boost::gil::read_and_convert_image( - dataStream, image, boost::gil::png_tag()); - } - catch (const std::exception& ex) - { - logger_->error("Error reading texture: {}", ex.what()); - return GL_INVALID_INDEX; - } - - boost::gil::rgba8_view_t view = boost::gil::view(image); - - std::vector pixelData(view.width() * - view.height()); - - boost::gil::copy_pixels( - view, - boost::gil::interleaved_view(view.width(), - view.height(), - pixelData.data(), - view.width() * - sizeof(boost::gil::rgba8_pixel_t))); - - OpenGLFunctions& gl = gl_; - - gl.glGenTextures(1, &texture); - gl.glBindTexture(GL_TEXTURE_2D, texture); - - // TODO: Change to GL_REPEAT once a texture atlas is used - gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - gl.glTexParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - gl.glTexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA, - view.width(), - view.height(), - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - pixelData.data()); - gl.glGenerateMipmap(GL_TEXTURE_2D); - - return texture; -} - } // namespace gl } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/gl/gl_context.hpp b/scwx-qt/source/scwx/qt/gl/gl_context.hpp index 69802534..623b5855 100644 --- a/scwx-qt/source/scwx/qt/gl/gl_context.hpp +++ b/scwx-qt/source/scwx/qt/gl/gl_context.hpp @@ -29,7 +29,6 @@ public: const std::string& fragmentPath); GLuint GetTextureAtlas(); - GLuint GetTexture(const std::string& texturePath); private: class Impl;