mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 14:20:04 +00:00 
			
		
		
		
	Merge branch 'feature/geo-line' into develop
This commit is contained in:
		
						commit
						fa78861a76
					
				
					 38 changed files with 1471 additions and 227 deletions
				
			
		
							
								
								
									
										3
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							|  | @ -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 | ||||
|  |  | |||
							
								
								
									
										4
									
								
								external/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								external/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							|  | @ -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) | ||||
|  |  | |||
							
								
								
									
										1
									
								
								external/stb
									
										
									
									
										vendored
									
									
										Submodule
									
								
							
							
						
						
									
										1
									
								
								external/stb
									
										
									
									
										vendored
									
									
										Submodule
									
								
							|  | @ -0,0 +1 @@ | |||
| Subproject commit 8b5f1f37b5b75829fc72d38e7b5d4bcbf8a26d55 | ||||
							
								
								
									
										4
									
								
								external/stb.cmake
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								external/stb.cmake
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -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) | ||||
							
								
								
									
										41
									
								
								scwx-qt/gl/geo_line.vert
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								scwx-qt/gl/geo_line.vert
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| #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 mat4 uMapMatrix; | ||||
| uniform vec2 uMapScreenCoord; | ||||
| 
 | ||||
| smooth 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) - uMapScreenCoord; | ||||
| 
 | ||||
|    // Transform the position to screen coordinates | ||||
|    gl_Position = uMapMatrix * vec4(p, 0.0f, 1.0f) - | ||||
|                  uMVPMatrix * vec4(aXYOffset, 0.0f, 0.0f); | ||||
| } | ||||
							
								
								
									
										16
									
								
								scwx-qt/gl/texture2d.frag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								scwx-qt/gl/texture2d.frag
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| #version 330 core | ||||
| 
 | ||||
| // Lower the default precision to medium | ||||
| precision mediump float; | ||||
| 
 | ||||
| uniform sampler2D uTexture; | ||||
| 
 | ||||
| smooth in vec2 texCoord; | ||||
| flat   in vec4 modulate; | ||||
| 
 | ||||
| layout (location = 0) out vec4 fragColor; | ||||
| 
 | ||||
| void main() | ||||
| { | ||||
|    fragColor = texture(uTexture, texCoord) * modulate; | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								scwx-qt/res/textures/lines/default-1x7.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								scwx-qt/res/textures/lines/default-1x7.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 486 B | 
							
								
								
									
										
											BIN
										
									
								
								scwx-qt/res/textures/lines/test-pattern.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								scwx-qt/res/textures/lines/test-pattern.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 479 B | 
|  | @ -40,14 +40,19 @@ 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 | ||||
|            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 | ||||
|                 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 | ||||
|  | @ -71,6 +76,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 | ||||
|  | @ -101,10 +107,13 @@ 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 | ||||
|              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 | ||||
|  | @ -122,12 +131,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) | ||||
| 
 | ||||
|  | @ -139,6 +150,7 @@ set(PROJECT_SOURCES ${HDR_MAIN} | |||
|                     ${SRC_MAIN} | ||||
|                     ${HDR_CONFIG} | ||||
|                     ${SRC_CONFIG} | ||||
|                     ${SRC_EXTERNAL} | ||||
|                     ${HDR_GL} | ||||
|                     ${SRC_GL} | ||||
|                     ${HDR_GL_DRAW} | ||||
|  | @ -173,6 +185,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}) | ||||
|  | @ -223,7 +236,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) | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,16 +2,20 @@ | |||
|     <qresource prefix="/"> | ||||
|         <file>gl/color.frag</file> | ||||
|         <file>gl/color.vert</file> | ||||
|         <file>gl/geo_line.vert</file> | ||||
|         <file>gl/radar.frag</file> | ||||
|         <file>gl/radar.vert</file> | ||||
|         <file>gl/text.frag</file> | ||||
|         <file>gl/text.vert</file> | ||||
|         <file>gl/texture1d.frag</file> | ||||
|         <file>gl/texture1d.vert</file> | ||||
|         <file>gl/texture2d.frag</file> | ||||
|         <file>res/config/radar_sites.json</file> | ||||
|         <file>res/fonts/din1451alt.ttf</file> | ||||
|         <file>res/fonts/din1451alt_g.ttf</file> | ||||
|         <file>res/icons/font-awesome-6/square-minus-regular.svg</file> | ||||
|         <file>res/icons/font-awesome-6/square-plus-regular.svg</file> | ||||
|         <file>res/textures/lines/default-1x7.png</file> | ||||
|         <file>res/textures/lines/test-pattern.png</file> | ||||
|     </qresource> | ||||
| </RCC> | ||||
|  |  | |||
							
								
								
									
										2
									
								
								scwx-qt/source/scwx/qt/external/stb_rect_pack.cpp
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								scwx-qt/source/scwx/qt/external/stb_rect_pack.cpp
									
										
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | |||
| #define STB_RECT_PACK_IMPLEMENTATION | ||||
| #include <stb_rect_pack.h> | ||||
|  | @ -2,6 +2,13 @@ | |||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| #pragma warning(push, 0) | ||||
| #include <glm/glm.hpp> | ||||
| #include <glm/gtc/matrix_transform.hpp> | ||||
| #include <glm/gtc/type_ptr.hpp> | ||||
| #include <mbgl/util/constants.hpp> | ||||
| #pragma warning(pop) | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
|  | @ -13,20 +20,76 @@ 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<DrawItemImpl>()) {} | ||||
| DrawItem::DrawItem(OpenGLFunctions& gl) : p(std::make_unique<Impl>(gl)) {} | ||||
| DrawItem::~DrawItem() = 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<float>(params.width), | ||||
|                                      0.0f, | ||||
|                                      static_cast<float>(params.height)); | ||||
| 
 | ||||
|    p->gl_.glUniformMatrix4fv( | ||||
|       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<float>(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
 | ||||
|  |  | |||
|  | @ -1,7 +1,11 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/gl/gl.hpp> | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| #include <QMapbox> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
|  | @ -11,12 +15,10 @@ namespace gl | |||
| namespace draw | ||||
| { | ||||
| 
 | ||||
| class DrawItemImpl; | ||||
| 
 | ||||
| class DrawItem | ||||
| { | ||||
| public: | ||||
|    explicit DrawItem(); | ||||
|    explicit DrawItem(OpenGLFunctions& gl); | ||||
|    ~DrawItem(); | ||||
| 
 | ||||
|    DrawItem(const DrawItem&)            = delete; | ||||
|  | @ -26,11 +28,20 @@ public: | |||
|    DrawItem& operator=(DrawItem&&) noexcept; | ||||
| 
 | ||||
|    virtual void Initialize()                                               = 0; | ||||
|    virtual void Render()       = 0; | ||||
|    virtual void Render(const QMapbox::CustomLayerRenderParameters& params) = 0; | ||||
|    virtual void Deinitialize()                                             = 0; | ||||
| 
 | ||||
| protected: | ||||
|    void UseDefaultProjection(const QMapbox::CustomLayerRenderParameters& params, | ||||
|                              GLint uMVPMatrixLocation); | ||||
|    void UseMapProjection(const QMapbox::CustomLayerRenderParameters& params, | ||||
|                          GLint uMVPMatrixLocation, | ||||
|                          GLint uMapScreenCoordLocation); | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<DrawItemImpl> p; | ||||
|    class Impl; | ||||
| 
 | ||||
|    std::unique_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace draw
 | ||||
|  |  | |||
							
								
								
									
										292
									
								
								scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										292
									
								
								scwx-qt/source/scwx/qt/gl/draw/geo_line.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,292 @@ | |||
| #include <scwx/qt/gl/draw/geo_line.hpp> | ||||
| #include <scwx/qt/util/texture_atlas.hpp> | ||||
| #include <scwx/common/geographic.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #include <optional> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace gl | ||||
| { | ||||
| 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; | ||||
| 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(std::shared_ptr<GlContext> context) : | ||||
|        context_ {context}, | ||||
|        dirty_ {false}, | ||||
|        visible_ {true}, | ||||
|        points_ {}, | ||||
|        width_ {7.0f}, | ||||
|        modulateColor_ {std::nullopt}, | ||||
|        shaderProgram_ {nullptr}, | ||||
|        uMVPMatrixLocation_(GL_INVALID_INDEX), | ||||
|        uMapMatrixLocation_(GL_INVALID_INDEX), | ||||
|        uMapScreenCoordLocation_(GL_INVALID_INDEX), | ||||
|        texture_ {}, | ||||
|        vao_ {GL_INVALID_INDEX}, | ||||
|        vbo_ {GL_INVALID_INDEX} | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    ~Impl() {} | ||||
| 
 | ||||
|    std::shared_ptr<GlContext> context_; | ||||
| 
 | ||||
|    bool dirty_; | ||||
| 
 | ||||
|    bool                              visible_; | ||||
|    std::array<common::Coordinate, 2> points_; | ||||
|    float                             width_; | ||||
| 
 | ||||
|    std::optional<boost::gil::rgba8_pixel_t> modulateColor_; | ||||
| 
 | ||||
|    std::shared_ptr<ShaderProgram> shaderProgram_; | ||||
|    GLint                          uMVPMatrixLocation_; | ||||
|    GLint                          uMapMatrixLocation_; | ||||
|    GLint                          uMapScreenCoordLocation_; | ||||
| 
 | ||||
|    util::TextureAttributes texture_; | ||||
| 
 | ||||
|    GLuint vao_; | ||||
|    GLuint vbo_; | ||||
| 
 | ||||
|    void Update(); | ||||
| }; | ||||
| 
 | ||||
| GeoLine::GeoLine(std::shared_ptr<GlContext> context) : | ||||
|     DrawItem(context->gl()), p(std::make_unique<Impl>(context)) | ||||
| { | ||||
| } | ||||
| GeoLine::~GeoLine() = default; | ||||
| 
 | ||||
| GeoLine::GeoLine(GeoLine&&) noexcept            = default; | ||||
| GeoLine& GeoLine::operator=(GeoLine&&) noexcept = default; | ||||
| 
 | ||||
| void GeoLine::Initialize() | ||||
| { | ||||
|    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"); | ||||
|    } | ||||
| 
 | ||||
|    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) | ||||
|    { | ||||
|       logger_->warn("Could not find uMapScreenCoord"); | ||||
|    } | ||||
| 
 | ||||
|    p->texture_ = | ||||
|       util::TextureAtlas::Instance().GetTextureAttributes("lines/default-1x7"); | ||||
| 
 | ||||
|    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<void*>(0)); | ||||
|    gl.glEnableVertexAttribArray(0); | ||||
| 
 | ||||
|    // aXYOffset
 | ||||
|    gl.glVertexAttribPointer(1, | ||||
|                             2, | ||||
|                             GL_FLOAT, | ||||
|                             GL_FALSE, | ||||
|                             kPointsPerVertex * sizeof(float), | ||||
|                             reinterpret_cast<void*>(2 * sizeof(float))); | ||||
|    gl.glEnableVertexAttribArray(1); | ||||
| 
 | ||||
|    // aTexCoord
 | ||||
|    gl.glVertexAttribPointer(2, | ||||
|                             2, | ||||
|                             GL_FLOAT, | ||||
|                             GL_FALSE, | ||||
|                             kPointsPerVertex * sizeof(float), | ||||
|                             reinterpret_cast<void*>(4 * sizeof(float))); | ||||
|    gl.glEnableVertexAttribArray(2); | ||||
| 
 | ||||
|    // aModulate
 | ||||
|    gl.glVertexAttribPointer(3, | ||||
|                             4, | ||||
|                             GL_FLOAT, | ||||
|                             GL_FALSE, | ||||
|                             kPointsPerVertex * sizeof(float), | ||||
|                             reinterpret_cast<void*>(6 * sizeof(float))); | ||||
|    gl.glEnableVertexAttribArray(3); | ||||
| 
 | ||||
|    p->dirty_ = true; | ||||
| } | ||||
| 
 | ||||
| void GeoLine::Render(const QMapbox::CustomLayerRenderParameters& params) | ||||
| { | ||||
|    if (p->visible_) | ||||
|    { | ||||
|       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_); | ||||
|       UseMapProjection( | ||||
|          params, p->uMapMatrixLocation_, p->uMapScreenCoordLocation_); | ||||
| 
 | ||||
|       // Draw line
 | ||||
|       gl.glDrawArrays(GL_TRIANGLES, 0, 6); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void GeoLine::Deinitialize() | ||||
| { | ||||
|    gl::OpenGLFunctions& gl = p->context_->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 = 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; | ||||
|       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, 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, | ||||
|                       sizeof(float) * kBufferLength, | ||||
|                       buffer, | ||||
|                       GL_DYNAMIC_DRAW); | ||||
| 
 | ||||
|       dirty_ = false; | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| } // namespace draw
 | ||||
| } // namespace gl
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										77
									
								
								scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								scwx-qt/source/scwx/qt/gl/draw/geo_line.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/gl/gl_context.hpp> | ||||
| #include <scwx/qt/gl/draw/draw_item.hpp> | ||||
| 
 | ||||
| #include <boost/gil.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace gl | ||||
| { | ||||
| namespace draw | ||||
| { | ||||
| 
 | ||||
| class GeoLine : public DrawItem | ||||
| { | ||||
| public: | ||||
|    explicit GeoLine(std::shared_ptr<GlContext> context); | ||||
|    ~GeoLine(); | ||||
| 
 | ||||
|    GeoLine(const GeoLine&)            = delete; | ||||
|    GeoLine& operator=(const GeoLine&) = delete; | ||||
| 
 | ||||
|    GeoLine(GeoLine&&) noexcept; | ||||
|    GeoLine& operator=(GeoLine&&) noexcept; | ||||
| 
 | ||||
|    void Initialize() override; | ||||
|    void Render(const QMapbox::CustomLayerRenderParameters& params) 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<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace draw
 | ||||
| } // namespace gl
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -1,4 +1,5 @@ | |||
| #include <scwx/qt/gl/draw/rectangle.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #include <optional> | ||||
| 
 | ||||
|  | @ -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<GlContext> 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<GlContext> context_; | ||||
| 
 | ||||
|    bool dirty_; | ||||
| 
 | ||||
|  | @ -59,15 +63,17 @@ public: | |||
| 
 | ||||
|    std::optional<boost::gil::rgba8_pixel_t> fillColor_; | ||||
| 
 | ||||
|    std::shared_ptr<ShaderProgram> shaderProgram_; | ||||
|    GLint                          uMVPMatrixLocation_; | ||||
| 
 | ||||
|    GLuint vao_; | ||||
|    GLuint vbo_; | ||||
| 
 | ||||
|    void Update(); | ||||
| }; | ||||
| 
 | ||||
| // TODO: OpenGL context with shaders
 | ||||
| Rectangle::Rectangle(OpenGLFunctions& gl) : | ||||
|     DrawItem(), p(std::make_unique<RectangleImpl>(gl)) | ||||
| Rectangle::Rectangle(std::shared_ptr<GlContext> context) : | ||||
|     DrawItem(context->gl()), p(std::make_unique<Impl>(context)) | ||||
| { | ||||
| } | ||||
| Rectangle::~Rectangle() = default; | ||||
|  | @ -77,7 +83,17 @@ 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_; | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/gl/gl.hpp> | ||||
| #include <scwx/qt/gl/gl_context.hpp> | ||||
| #include <scwx/qt/gl/draw/draw_item.hpp> | ||||
| 
 | ||||
| #include <boost/gil.hpp> | ||||
|  | @ -14,12 +14,10 @@ namespace gl | |||
| namespace draw | ||||
| { | ||||
| 
 | ||||
| class RectangleImpl; | ||||
| 
 | ||||
| class Rectangle : public DrawItem | ||||
| { | ||||
| public: | ||||
|    explicit Rectangle(OpenGLFunctions& gl); | ||||
|    explicit Rectangle(std::shared_ptr<GlContext> context); | ||||
|    ~Rectangle(); | ||||
| 
 | ||||
|    Rectangle(const Rectangle&)            = delete; | ||||
|  | @ -29,7 +27,7 @@ public: | |||
|    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<RectangleImpl> p; | ||||
|    class Impl; | ||||
| 
 | ||||
|    std::unique_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace draw
 | ||||
|  |  | |||
							
								
								
									
										90
									
								
								scwx-qt/source/scwx/qt/gl/gl_context.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								scwx-qt/source/scwx/qt/gl/gl_context.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,90 @@ | |||
| #include <scwx/qt/gl/gl_context.hpp> | ||||
| #include <scwx/qt/util/texture_atlas.hpp> | ||||
| #include <scwx/util/hash.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace gl | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "scwx::qt::gl::gl_context"; | ||||
| 
 | ||||
| class GlContext::Impl | ||||
| { | ||||
| public: | ||||
|    explicit Impl() : | ||||
|        gl_ {}, | ||||
|        shaderProgramMap_ {}, | ||||
|        shaderProgramMutex_ {}, | ||||
|        textureAtlas_ {GL_INVALID_INDEX}, | ||||
|        textureMutex_ {} | ||||
|    { | ||||
|    } | ||||
|    ~Impl() {} | ||||
| 
 | ||||
|    gl::OpenGLFunctions gl_; | ||||
| 
 | ||||
|    std::unordered_map<std::pair<std::string, std::string>, | ||||
|                       std::shared_ptr<gl::ShaderProgram>, | ||||
|                       scwx::util::hash<std::pair<std::string, std::string>>> | ||||
|               shaderProgramMap_; | ||||
|    std::mutex shaderProgramMutex_; | ||||
| 
 | ||||
|    GLuint     textureAtlas_; | ||||
|    std::mutex textureMutex_; | ||||
| }; | ||||
| 
 | ||||
| GlContext::GlContext() : p(std::make_unique<Impl>()) {} | ||||
| GlContext::~GlContext() = default; | ||||
| 
 | ||||
| GlContext::GlContext(GlContext&&) noexcept            = default; | ||||
| GlContext& GlContext::operator=(GlContext&&) noexcept = default; | ||||
| 
 | ||||
| gl::OpenGLFunctions& GlContext::gl() | ||||
| { | ||||
|    return p->gl_; | ||||
| } | ||||
| 
 | ||||
| std::shared_ptr<gl::ShaderProgram> | ||||
| GlContext::GetShaderProgram(const std::string& vertexPath, | ||||
|                             const std::string& fragmentPath) | ||||
| { | ||||
|    const std::pair<std::string, std::string> key {vertexPath, fragmentPath}; | ||||
|    std::shared_ptr<gl::ShaderProgram>        shaderProgram; | ||||
| 
 | ||||
|    std::unique_lock lock(p->shaderProgramMutex_); | ||||
| 
 | ||||
|    auto it = p->shaderProgramMap_.find(key); | ||||
| 
 | ||||
|    if (it == p->shaderProgramMap_.end()) | ||||
|    { | ||||
|       shaderProgram = std::make_shared<gl::ShaderProgram>(p->gl_); | ||||
|       shaderProgram->Load(vertexPath, fragmentPath); | ||||
|       p->shaderProgramMap_[key] = shaderProgram; | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       shaderProgram = it->second; | ||||
|    } | ||||
| 
 | ||||
|    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_; | ||||
| } | ||||
| 
 | ||||
| } // namespace gl
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										41
									
								
								scwx-qt/source/scwx/qt/gl/gl_context.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								scwx-qt/source/scwx/qt/gl/gl_context.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/gl/gl.hpp> | ||||
| #include <scwx/qt/gl/shader_program.hpp> | ||||
| 
 | ||||
| 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<gl::ShaderProgram> | ||||
|    GetShaderProgram(const std::string& vertexPath, | ||||
|                     const std::string& fragmentPath); | ||||
| 
 | ||||
|    GLuint GetTextureAtlas(); | ||||
| 
 | ||||
| private: | ||||
|    class Impl; | ||||
| 
 | ||||
|    std::unique_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace gl
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -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,7 +36,7 @@ public: | |||
| }; | ||||
| 
 | ||||
| ShaderProgram::ShaderProgram(OpenGLFunctions& gl) : | ||||
|     p(std::make_unique<ShaderProgramImpl>(gl)) | ||||
|     p(std::make_unique<Impl>(gl)) | ||||
| { | ||||
| } | ||||
| ShaderProgram::~ShaderProgram() = default; | ||||
|  | @ -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); | ||||
|  |  | |||
|  | @ -16,8 +16,6 @@ namespace qt | |||
| namespace gl | ||||
| { | ||||
| 
 | ||||
| class ShaderProgramImpl; | ||||
| 
 | ||||
| class ShaderProgram | ||||
| { | ||||
| public: | ||||
|  | @ -37,7 +35,9 @@ public: | |||
|    void Use() const; | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<ShaderProgramImpl> p; | ||||
|    class Impl; | ||||
| 
 | ||||
|    std::unique_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace gl
 | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| #include <scwx/qt/gl/text_shader.hpp> | ||||
| #include <scwx/qt/gl/shader_program.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #pragma warning(push, 0) | ||||
|  | @ -18,20 +19,23 @@ 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<GlContext> context) : | ||||
|        context_ {context}, | ||||
|        shaderProgram_ {nullptr}, | ||||
|        projectionLocation_(GL_INVALID_INDEX) | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    ~TextShaderImpl() {} | ||||
| 
 | ||||
|    OpenGLFunctions& gl_; | ||||
|    std::shared_ptr<GlContext>     context_; | ||||
|    std::shared_ptr<ShaderProgram> shaderProgram_; | ||||
| 
 | ||||
|    GLint projectionLocation_; | ||||
| }; | ||||
| 
 | ||||
| TextShader::TextShader(OpenGLFunctions& gl) : | ||||
|     ShaderProgram(gl), p(std::make_unique<TextShaderImpl>(gl)) | ||||
| TextShader::TextShader(std::shared_ptr<GlContext> context) : | ||||
|     p(std::make_unique<TextShaderImpl>(context)) | ||||
| { | ||||
| } | ||||
| TextShader::~TextShader() = default; | ||||
|  | @ -41,18 +45,20 @@ 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)); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/gl/shader_program.hpp> | ||||
| #include <scwx/qt/gl/gl_context.hpp> | ||||
| #include <scwx/qt/util/font.hpp> | ||||
| 
 | ||||
| #include <memory> | ||||
|  | @ -24,10 +24,10 @@ enum class TextAlign | |||
| 
 | ||||
| class TextShaderImpl; | ||||
| 
 | ||||
| class TextShader : public ShaderProgram | ||||
| class TextShader | ||||
| { | ||||
| public: | ||||
|    explicit TextShader(OpenGLFunctions& gl); | ||||
|    explicit TextShader(std::shared_ptr<GlContext> context); | ||||
|    ~TextShader(); | ||||
| 
 | ||||
|    TextShader(const TextShader&)            = delete; | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| #include <scwx/qt/manager/resource_manager.hpp> | ||||
| #include <scwx/qt/util/font.hpp> | ||||
| #include <scwx/qt/util/texture_atlas.hpp> | ||||
| 
 | ||||
| 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
 | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ class ColorTableLayerImpl | |||
| { | ||||
| public: | ||||
|    explicit ColorTableLayerImpl(std::shared_ptr<MapContext> 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<gl::ShaderProgram> shaderProgram_; | ||||
| 
 | ||||
|    GLint                 uMVPMatrixLocation_; | ||||
|    std::array<GLuint, 2> 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<void*>(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<float>(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,8 +148,7 @@ void ColorTableLayer::Render(const QMapbox::CustomLayerRenderParameters& params) | |||
|       gl.glGenerateMipmap(GL_TEXTURE_1D); | ||||
|    } | ||||
| 
 | ||||
|    if (p->colorTable_.size() > 0 && | ||||
|        context()->radarProductView_->sweep_time() != | ||||
|    if (p->colorTable_.size() > 0 && radarProductView->sweep_time() != | ||||
|                                        std::chrono::system_clock::time_point()) | ||||
|    { | ||||
|       // Color table panel vertices
 | ||||
|  | @ -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()); | ||||
|  |  | |||
|  | @ -2,12 +2,6 @@ | |||
| #include <scwx/qt/gl/shader_program.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #pragma warning(push, 0) | ||||
| #include <glm/glm.hpp> | ||||
| #include <glm/gtc/matrix_transform.hpp> | ||||
| #include <glm/gtc/type_ptr.hpp> | ||||
| #pragma warning(pop) | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
|  | @ -22,16 +16,14 @@ class DrawLayerImpl | |||
| { | ||||
| public: | ||||
|    explicit DrawLayerImpl(std::shared_ptr<MapContext> context) : | ||||
|        shaderProgram_ {context->gl_}, uMVPMatrixLocation_(GL_INVALID_INDEX) | ||||
|        context_ {context}, drawList_ {}, textureAtlas_ {GL_INVALID_INDEX} | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    ~DrawLayerImpl() {} | ||||
| 
 | ||||
|    gl::ShaderProgram shaderProgram_; | ||||
|    GLint             uMVPMatrixLocation_; | ||||
| 
 | ||||
|    std::shared_ptr<MapContext>                      context_; | ||||
|    std::vector<std::shared_ptr<gl::draw::DrawItem>> drawList_; | ||||
|    GLuint                                           textureAtlas_; | ||||
| }; | ||||
| 
 | ||||
| DrawLayer::DrawLayer(std::shared_ptr<MapContext> context) : | ||||
|  | @ -42,20 +34,9 @@ DrawLayer::~DrawLayer() = default; | |||
| 
 | ||||
| void DrawLayer::Initialize() | ||||
| { | ||||
|    gl::OpenGLFunctions& gl = context()->gl_; | ||||
|    p->textureAtlas_ = p->context_->GetTextureAtlas(); | ||||
| 
 | ||||
|    p->shaderProgram_.Load(":/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_) | ||||
|    for (auto& item : p->drawList_) | ||||
|    { | ||||
|       item->Initialize(); | ||||
|    } | ||||
|  | @ -63,27 +44,22 @@ void DrawLayer::Initialize() | |||
| 
 | ||||
| void DrawLayer::Render(const QMapbox::CustomLayerRenderParameters& params) | ||||
| { | ||||
|    gl::OpenGLFunctions& gl = context()->gl_; | ||||
|    gl::OpenGLFunctions& gl = p->context_->gl(); | ||||
| 
 | ||||
|    p->shaderProgram_.Use(); | ||||
|    gl.glActiveTexture(GL_TEXTURE0); | ||||
|    gl.glBindTexture(GL_TEXTURE_2D, p->textureAtlas_); | ||||
| 
 | ||||
|    glm::mat4 projection = glm::ortho(0.0f, | ||||
|                                      static_cast<float>(params.width), | ||||
|                                      0.0f, | ||||
|                                      static_cast<float>(params.height)); | ||||
| 
 | ||||
|    gl.glUniformMatrix4fv( | ||||
|       p->uMVPMatrixLocation_, 1, GL_FALSE, glm::value_ptr(projection)); | ||||
| 
 | ||||
|    for (auto item : p->drawList_) | ||||
|    for (auto& item : p->drawList_) | ||||
|    { | ||||
|       item->Render(); | ||||
|       item->Render(params); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| void DrawLayer::Deinitialize() | ||||
| { | ||||
|    for (auto item : p->drawList_) | ||||
|    p->textureAtlas_ = GL_INVALID_INDEX; | ||||
| 
 | ||||
|    for (auto& item : p->drawList_) | ||||
|    { | ||||
|       item->Deinitialize(); | ||||
|    } | ||||
|  |  | |||
							
								
								
									
										90
									
								
								scwx-qt/source/scwx/qt/map/map_context.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								scwx-qt/source/scwx/qt/map/map_context.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,90 @@ | |||
| #include <scwx/qt/map/map_context.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| namespace map | ||||
| { | ||||
| 
 | ||||
| class MapContext::Impl | ||||
| { | ||||
| public: | ||||
|    explicit Impl(std::shared_ptr<view::RadarProductView> radarProductView) : | ||||
|        settings_ {}, | ||||
|        radarProductView_ {radarProductView}, | ||||
|        radarProductGroup_ {common::RadarProductGroup::Unknown}, | ||||
|        radarProduct_ {"???"}, | ||||
|        radarProductCode_ {0} | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    ~Impl() {} | ||||
| 
 | ||||
|    MapSettings                             settings_; | ||||
|    std::shared_ptr<view::RadarProductView> radarProductView_; | ||||
|    common::RadarProductGroup               radarProductGroup_; | ||||
|    std::string                             radarProduct_; | ||||
|    int16_t                                 radarProductCode_; | ||||
| }; | ||||
| 
 | ||||
| MapContext::MapContext( | ||||
|    std::shared_ptr<view::RadarProductView> radarProductView) : | ||||
|     p(std::make_unique<Impl>(radarProductView)) | ||||
| { | ||||
| } | ||||
| MapContext::~MapContext() = default; | ||||
| 
 | ||||
| MapContext::MapContext(MapContext&&) noexcept            = default; | ||||
| MapContext& MapContext::operator=(MapContext&&) noexcept = default; | ||||
| 
 | ||||
| MapSettings& MapContext::settings() | ||||
| { | ||||
|    return p->settings_; | ||||
| } | ||||
| 
 | ||||
| std::shared_ptr<view::RadarProductView> 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<view::RadarProductView> 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; | ||||
| } | ||||
| 
 | ||||
| } // namespace map
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -1,6 +1,6 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/gl/gl.hpp> | ||||
| #include <scwx/qt/gl/gl_context.hpp> | ||||
| #include <scwx/qt/map/map_settings.hpp> | ||||
| #include <scwx/qt/view/radar_product_view.hpp> | ||||
| 
 | ||||
|  | @ -11,32 +11,35 @@ namespace qt | |||
| namespace map | ||||
| { | ||||
| 
 | ||||
| struct MapContext | ||||
| class MapContext : public gl::GlContext | ||||
| { | ||||
| public: | ||||
|    explicit MapContext( | ||||
|       std::shared_ptr<view::RadarProductView> radarProductView = nullptr) : | ||||
|        gl_ {}, | ||||
|        settings_ {}, | ||||
|        radarProductView_ {radarProductView}, | ||||
|        radarProductGroup_ {common::RadarProductGroup::Unknown}, | ||||
|        radarProduct_ {"???"}, | ||||
|        radarProductCode_ {0} | ||||
|    { | ||||
|    } | ||||
|    ~MapContext() = default; | ||||
|       std::shared_ptr<view::RadarProductView> radarProductView = nullptr); | ||||
|    ~MapContext(); | ||||
| 
 | ||||
|    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<view::RadarProductView> radarProductView_; | ||||
|    common::RadarProductGroup               radarProductGroup_; | ||||
|    std::string                             radarProduct_; | ||||
|    int16_t                                 radarProductCode_; | ||||
|    MapSettings&                            settings(); | ||||
|    std::shared_ptr<view::RadarProductView> 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<view::RadarProductView> 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); | ||||
| 
 | ||||
| private: | ||||
|    class Impl; | ||||
| 
 | ||||
|    std::unique_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace map
 | ||||
|  |  | |||
|  | @ -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<float> 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<std::string> 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<config::RadarSite> 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<view::RadarProductView>& 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<RadarProductLayer>(p->context_); | ||||
|       p->colorTableLayer_   = std::make_shared<ColorTableLayer>(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::NexradFileRequest> 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<common::ColorTable> 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<config::RadarSite> 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); | ||||
|  |  | |||
|  | @ -34,12 +34,12 @@ class OverlayLayerImpl | |||
| { | ||||
| public: | ||||
|    explicit OverlayLayerImpl(std::shared_ptr<MapContext> context) : | ||||
|        textShader_(context->gl_), | ||||
|        textShader_(context), | ||||
|        font_(util::Font::Create(":/res/fonts/din1451alt.ttf")), | ||||
|        texture_ {GL_INVALID_INDEX}, | ||||
|        activeBoxOuter_ {std::make_shared<gl::draw::Rectangle>(context->gl_)}, | ||||
|        activeBoxInner_ {std::make_shared<gl::draw::Rectangle>(context->gl_)}, | ||||
|        timeBox_ {std::make_shared<gl::draw::Rectangle>(context->gl_)}, | ||||
|        activeBoxOuter_ {std::make_shared<gl::draw::Rectangle>(context)}, | ||||
|        activeBoxInner_ {std::make_shared<gl::draw::Rectangle>(context)}, | ||||
|        timeBox_ {std::make_shared<gl::draw::Rectangle>(context)}, | ||||
|        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<float>(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); | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ class RadarProductLayerImpl | |||
| { | ||||
| public: | ||||
|    explicit RadarProductLayerImpl(std::shared_ptr<MapContext> 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<gl::ShaderProgram> 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<view::RadarProductView> 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<view::RadarProductView> radarProductView = | ||||
|       context()->radarProductView_; | ||||
|       context()->radar_product_view(); | ||||
| 
 | ||||
|    const std::vector<boost::gil::rgba8_pixel_t>& colorTable = | ||||
|       radarProductView->color_table(); | ||||
|  |  | |||
							
								
								
									
										33
									
								
								scwx-qt/source/scwx/qt/util/streams.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								scwx-qt/source/scwx/qt/util/streams.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <boost/iostreams/categories.hpp> | ||||
| #include <QIODevice> | ||||
| 
 | ||||
| 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
 | ||||
							
								
								
									
										292
									
								
								scwx-qt/source/scwx/qt/util/texture_atlas.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										292
									
								
								scwx-qt/source/scwx/qt/util/texture_atlas.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,292 @@ | |||
| #include <scwx/qt/util/texture_atlas.hpp> | ||||
| #include <scwx/qt/util/streams.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| 
 | ||||
| #include <shared_mutex> | ||||
| #include <unordered_map> | ||||
| 
 | ||||
| #pragma warning(push, 0) | ||||
| #pragma warning(disable : 4714) | ||||
| #include <boost/gil/extension/io/png.hpp> | ||||
| #include <boost/iostreams/stream.hpp> | ||||
| #include <stb_rect_pack.h> | ||||
| #include <QFile> | ||||
| #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_); | ||||
| 
 | ||||
| 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<std::string, std::string> texturePathMap_; | ||||
|    std::shared_mutex                            texturePathMutex_; | ||||
| 
 | ||||
|    boost::gil::rgba8_image_t                          atlas_; | ||||
|    std::unordered_map<std::string, TextureAttributes> atlasMap_; | ||||
|    std::shared_mutex                                  atlasMutex_; | ||||
| }; | ||||
| 
 | ||||
| TextureAtlas::TextureAtlas() : p(std::make_unique<Impl>()) {} | ||||
| 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<std::pair<std::string, boost::gil::rgba8_image_t>> images; | ||||
|    std::vector<stbrp_rect>                                        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<stbrp_coord>(image.width()), | ||||
|                              static_cast<stbrp_coord>(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<stbrp_node> stbrpNodes(width); | ||||
| 
 | ||||
|       stbrp_init_target(&stbrpContext, | ||||
|                         static_cast<int>(width), | ||||
|                         static_cast<int>(height), | ||||
|                         stbrpNodes.data(), | ||||
|                         static_cast<int>(stbrpNodes.size())); | ||||
| 
 | ||||
|       // Pack loaded textures
 | ||||
|       stbrp_pack_rects( | ||||
|          &stbrpContext, stbrpRects.data(), static_cast<int>(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_); | ||||
|    boost::gil::fill_pixels(atlasView, | ||||
|                            boost::gil::rgba8_pixel_t {255, 0, 255, 255}); | ||||
| 
 | ||||
|    // 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
 | ||||
|       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
 | ||||
|          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<float>(imageView.width() - 1) / width; | ||||
|          const float tTop = y * yStep + yMin; | ||||
|          const float tBottom = | ||||
|             tTop + static_cast<float>(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 {x, y}, | ||||
|                boost::gil::point_t {imageView.width(), imageView.height()}, | ||||
|                sLeft, | ||||
|                sRight, | ||||
|                tTop, | ||||
|                tBottom)); | ||||
|       } | ||||
|       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<boost::gil::rgba8_pixel_t> 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; | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
|    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<util::IoDeviceSource> dataStream(imageFile); | ||||
| 
 | ||||
|    boost::gil::image<boost::gil::rgba8_pixel_t, false> 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
 | ||||
							
								
								
									
										83
									
								
								scwx-qt/source/scwx/qt/util/texture_atlas.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								scwx-qt/source/scwx/qt/util/texture_atlas.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,83 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <scwx/qt/gl/gl.hpp> | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <string> | ||||
| 
 | ||||
| #include <boost/gil/point.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| 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: | ||||
|    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); | ||||
| 
 | ||||
|    TextureAttributes GetTextureAttributes(const std::string& name); | ||||
| 
 | ||||
| private: | ||||
|    class Impl; | ||||
| 
 | ||||
|    std::unique_ptr<Impl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace util
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
|  | @ -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} | ||||
|    { | ||||
|  |  | |||
							
								
								
									
										21
									
								
								wxdata/include/scwx/util/hash.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								wxdata/include/scwx/util/hash.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <string> | ||||
| #include <utility> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace util | ||||
| { | ||||
| 
 | ||||
| template<class Key> | ||||
| struct hash; | ||||
| 
 | ||||
| template<> | ||||
| struct hash<std::pair<std::string, std::string>> | ||||
| { | ||||
|    size_t operator()(const std::pair<std::string, std::string>& x) const; | ||||
| }; | ||||
| 
 | ||||
| } // namespace util
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										20
									
								
								wxdata/source/scwx/util/hash.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								wxdata/source/scwx/util/hash.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| #include <scwx/util/hash.hpp> | ||||
| 
 | ||||
| #include <boost/container_hash/hash.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace util | ||||
| { | ||||
| 
 | ||||
| size_t hash<std::pair<std::string, std::string>>::operator()( | ||||
|    const std::pair<std::string, std::string>& x) const | ||||
| { | ||||
|    size_t seed = 0; | ||||
|    boost::hash_combine(seed, x.first); | ||||
|    boost::hash_combine(seed, x.second); | ||||
|    return seed; | ||||
| } | ||||
| 
 | ||||
| } // namespace util
 | ||||
| } // namespace scwx
 | ||||
|  | @ -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 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat