mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 03:30:06 +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"] | [submodule "external/freetype-gl"] | ||||||
| 	path = external/freetype-gl | 	path = external/freetype-gl | ||||||
| 	url = https://github.com/rougier/freetype-gl.git | 	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 |              PROPERTY CMAKE_CONFIGURE_DEPENDS | ||||||
|              freetype-gl.cmake |              freetype-gl.cmake | ||||||
|              hsluv-c.cmake |              hsluv-c.cmake | ||||||
|              mapbox-gl-native.cmake) |              mapbox-gl-native.cmake | ||||||
|  |              stb.cmake) | ||||||
| 
 | 
 | ||||||
| include(freetype-gl.cmake) | include(freetype-gl.cmake) | ||||||
| include(hsluv-c.cmake) | include(hsluv-c.cmake) | ||||||
| include(mapbox-gl-native.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(UI_MAIN  source/scwx/qt/main/main_window.ui) | ||||||
| set(HDR_CONFIG source/scwx/qt/config/radar_site.hpp) | set(HDR_CONFIG source/scwx/qt/config/radar_site.hpp) | ||||||
| set(SRC_CONFIG source/scwx/qt/config/radar_site.cpp) | 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 | 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/shader_program.hpp | ||||||
|            source/scwx/qt/gl/text_shader.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) |            source/scwx/qt/gl/text_shader.cpp) | ||||||
| set(HDR_GL_DRAW source/scwx/qt/gl/draw/draw_item.hpp | 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) |                 source/scwx/qt/gl/draw/rectangle.hpp) | ||||||
| set(SRC_GL_DRAW source/scwx/qt/gl/draw/draw_item.cpp | 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) |                 source/scwx/qt/gl/draw/rectangle.cpp) | ||||||
| set(HDR_MANAGER source/scwx/qt/manager/radar_product_manager.hpp | set(HDR_MANAGER source/scwx/qt/manager/radar_product_manager.hpp | ||||||
|                 source/scwx/qt/manager/radar_product_manager_notifier.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/draw_layer.cpp | ||||||
|             source/scwx/qt/map/generic_layer.cpp |             source/scwx/qt/map/generic_layer.cpp | ||||||
|             source/scwx/qt/map/layer_wrapper.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/map_widget.cpp | ||||||
|             source/scwx/qt/map/overlay_layer.cpp |             source/scwx/qt/map/overlay_layer.cpp | ||||||
|             source/scwx/qt/map/radar_product_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) |            source/scwx/qt/ui/level3_products_widget.cpp) | ||||||
| set(HDR_UTIL source/scwx/qt/util/font.hpp | set(HDR_UTIL source/scwx/qt/util/font.hpp | ||||||
|              source/scwx/qt/util/font_buffer.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 | set(SRC_UTIL source/scwx/qt/util/font.cpp | ||||||
|              source/scwx/qt/util/font_buffer.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 | set(HDR_VIEW source/scwx/qt/view/level2_product_view.hpp | ||||||
|              source/scwx/qt/view/level3_product_view.hpp |              source/scwx/qt/view/level3_product_view.hpp | ||||||
|              source/scwx/qt/view/level3_radial_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 | set(SHADER_FILES gl/color.frag | ||||||
|                  gl/color.vert |                  gl/color.vert | ||||||
|  |                  gl/geo_line.vert | ||||||
|                  gl/radar.frag |                  gl/radar.frag | ||||||
|                  gl/radar.vert |                  gl/radar.vert | ||||||
|                  gl/text.frag |                  gl/text.frag | ||||||
|                  gl/text.vert |                  gl/text.vert | ||||||
|                  gl/texture1d.frag |                  gl/texture1d.frag | ||||||
|                  gl/texture1d.vert) |                  gl/texture1d.vert | ||||||
|  |                  gl/texture2d.frag) | ||||||
| 
 | 
 | ||||||
| set(CMAKE_FILES scwx-qt.cmake) | set(CMAKE_FILES scwx-qt.cmake) | ||||||
| 
 | 
 | ||||||
|  | @ -139,6 +150,7 @@ set(PROJECT_SOURCES ${HDR_MAIN} | ||||||
|                     ${SRC_MAIN} |                     ${SRC_MAIN} | ||||||
|                     ${HDR_CONFIG} |                     ${HDR_CONFIG} | ||||||
|                     ${SRC_CONFIG} |                     ${SRC_CONFIG} | ||||||
|  |                     ${SRC_EXTERNAL} | ||||||
|                     ${HDR_GL} |                     ${HDR_GL} | ||||||
|                     ${SRC_GL} |                     ${SRC_GL} | ||||||
|                     ${HDR_GL_DRAW} |                     ${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("Source Files\\main"     FILES ${SRC_MAIN}) | ||||||
| source_group("Header Files\\config"   FILES ${HDR_CONFIG}) | source_group("Header Files\\config"   FILES ${HDR_CONFIG}) | ||||||
| source_group("Source Files\\config"   FILES ${SRC_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("Header Files\\gl"       FILES ${HDR_GL}) | ||||||
| source_group("Source Files\\gl"       FILES ${SRC_GL}) | source_group("Source Files\\gl"       FILES ${SRC_GL}) | ||||||
| source_group("Header Files\\gl\\draw" FILES ${HDR_GL_DRAW}) | 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 | target_include_directories(scwx-qt PUBLIC ${scwx-qt_SOURCE_DIR}/source | ||||||
|                                           ${FTGL_INCLUDE_DIR} |                                           ${FTGL_INCLUDE_DIR} | ||||||
|                                           ${MBGL_INCLUDE_DIR}) |                                           ${MBGL_INCLUDE_DIR} | ||||||
|  |                                           ${STB_INCLUDE_DIR}) | ||||||
| 
 | 
 | ||||||
| target_include_directories(supercell-wx PUBLIC ${scwx-qt_SOURCE_DIR}/source) | target_include_directories(supercell-wx PUBLIC ${scwx-qt_SOURCE_DIR}/source) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,16 +2,20 @@ | ||||||
|     <qresource prefix="/"> |     <qresource prefix="/"> | ||||||
|         <file>gl/color.frag</file> |         <file>gl/color.frag</file> | ||||||
|         <file>gl/color.vert</file> |         <file>gl/color.vert</file> | ||||||
|  |         <file>gl/geo_line.vert</file> | ||||||
|         <file>gl/radar.frag</file> |         <file>gl/radar.frag</file> | ||||||
|         <file>gl/radar.vert</file> |         <file>gl/radar.vert</file> | ||||||
|         <file>gl/text.frag</file> |         <file>gl/text.frag</file> | ||||||
|         <file>gl/text.vert</file> |         <file>gl/text.vert</file> | ||||||
|         <file>gl/texture1d.frag</file> |         <file>gl/texture1d.frag</file> | ||||||
|         <file>gl/texture1d.vert</file> |         <file>gl/texture1d.vert</file> | ||||||
|  |         <file>gl/texture2d.frag</file> | ||||||
|         <file>res/config/radar_sites.json</file> |         <file>res/config/radar_sites.json</file> | ||||||
|         <file>res/fonts/din1451alt.ttf</file> |         <file>res/fonts/din1451alt.ttf</file> | ||||||
|         <file>res/fonts/din1451alt_g.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-minus-regular.svg</file> | ||||||
|         <file>res/icons/font-awesome-6/square-plus-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> |     </qresource> | ||||||
| </RCC> | </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> | #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 scwx | ||||||
| { | { | ||||||
| namespace qt | namespace qt | ||||||
|  | @ -13,20 +20,76 @@ namespace draw | ||||||
| 
 | 
 | ||||||
| static const std::string logPrefix_ = "scwx::qt::gl::draw::draw_item"; | static const std::string logPrefix_ = "scwx::qt::gl::draw::draw_item"; | ||||||
| 
 | 
 | ||||||
| class DrawItemImpl | class DrawItem::Impl | ||||||
| { | { | ||||||
| public: | 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() = default; | ||||||
| 
 | 
 | ||||||
| DrawItem::DrawItem(DrawItem&&) noexcept = default; | DrawItem::DrawItem(DrawItem&&) noexcept            = default; | ||||||
| DrawItem& DrawItem::operator=(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 draw
 | ||||||
| } // namespace gl
 | } // namespace gl
 | ||||||
| } // namespace qt
 | } // namespace qt
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,11 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <scwx/qt/gl/gl.hpp> | ||||||
|  | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
| 
 | 
 | ||||||
|  | #include <QMapbox> | ||||||
|  | 
 | ||||||
| namespace scwx | namespace scwx | ||||||
| { | { | ||||||
| namespace qt | namespace qt | ||||||
|  | @ -11,26 +15,33 @@ namespace gl | ||||||
| namespace draw | namespace draw | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| class DrawItemImpl; |  | ||||||
| 
 |  | ||||||
| class DrawItem | class DrawItem | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit DrawItem(); |    explicit DrawItem(OpenGLFunctions& gl); | ||||||
|    ~DrawItem(); |    ~DrawItem(); | ||||||
| 
 | 
 | ||||||
|    DrawItem(const DrawItem&) = delete; |    DrawItem(const DrawItem&)            = delete; | ||||||
|    DrawItem& operator=(const DrawItem&) = delete; |    DrawItem& operator=(const DrawItem&) = delete; | ||||||
| 
 | 
 | ||||||
|    DrawItem(DrawItem&&) noexcept; |    DrawItem(DrawItem&&) noexcept; | ||||||
|    DrawItem& operator=(DrawItem&&) noexcept; |    DrawItem& operator=(DrawItem&&) noexcept; | ||||||
| 
 | 
 | ||||||
|    virtual void Initialize()   = 0; |    virtual void Initialize()                                               = 0; | ||||||
|    virtual void Render()       = 0; |    virtual void Render(const QMapbox::CustomLayerRenderParameters& params) = 0; | ||||||
|    virtual void Deinitialize() = 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: | private: | ||||||
|    std::unique_ptr<DrawItemImpl> p; |    class Impl; | ||||||
|  | 
 | ||||||
|  |    std::unique_ptr<Impl> p; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace draw
 | } // 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/qt/gl/draw/rectangle.hpp> | ||||||
|  | #include <scwx/util/logger.hpp> | ||||||
| 
 | 
 | ||||||
| #include <optional> | #include <optional> | ||||||
| 
 | 
 | ||||||
|  | @ -12,6 +13,7 @@ namespace draw | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| static const std::string logPrefix_ = "scwx::qt::gl::draw::rectangle"; | 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_RECTANGLES         = 5; | ||||||
| static constexpr size_t NUM_TRIANGLES          = NUM_RECTANGLES * 2; | 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 = | static constexpr size_t BUFFER_LENGTH = | ||||||
|    NUM_TRIANGLES * VERTICES_PER_TRIANGLE * POINTS_PER_VERTEX; |    NUM_TRIANGLES * VERTICES_PER_TRIANGLE * POINTS_PER_VERTEX; | ||||||
| 
 | 
 | ||||||
| class RectangleImpl | class Rectangle::Impl | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit RectangleImpl(OpenGLFunctions& gl) : |    explicit Impl(std::shared_ptr<GlContext> context) : | ||||||
|        gl_ {gl}, |        context_ {context}, | ||||||
|        dirty_ {false}, |        dirty_ {false}, | ||||||
|        visible_ {true}, |        visible_ {true}, | ||||||
|        x_ {0.0f}, |        x_ {0.0f}, | ||||||
|  | @ -36,14 +38,16 @@ public: | ||||||
|        borderColor_ {0, 0, 0, 0}, |        borderColor_ {0, 0, 0, 0}, | ||||||
|        borderWidth_ {0.0f}, |        borderWidth_ {0.0f}, | ||||||
|        fillColor_ {std::nullopt}, |        fillColor_ {std::nullopt}, | ||||||
|  |        shaderProgram_ {nullptr}, | ||||||
|  |        uMVPMatrixLocation_(GL_INVALID_INDEX), | ||||||
|        vao_ {GL_INVALID_INDEX}, |        vao_ {GL_INVALID_INDEX}, | ||||||
|        vbo_ {GL_INVALID_INDEX} |        vbo_ {GL_INVALID_INDEX} | ||||||
|    { |    { | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    ~RectangleImpl() {} |    ~Impl() {} | ||||||
| 
 | 
 | ||||||
|    OpenGLFunctions& gl_; |    std::shared_ptr<GlContext> context_; | ||||||
| 
 | 
 | ||||||
|    bool dirty_; |    bool dirty_; | ||||||
| 
 | 
 | ||||||
|  | @ -59,25 +63,37 @@ public: | ||||||
| 
 | 
 | ||||||
|    std::optional<boost::gil::rgba8_pixel_t> fillColor_; |    std::optional<boost::gil::rgba8_pixel_t> fillColor_; | ||||||
| 
 | 
 | ||||||
|  |    std::shared_ptr<ShaderProgram> shaderProgram_; | ||||||
|  |    GLint                          uMVPMatrixLocation_; | ||||||
|  | 
 | ||||||
|    GLuint vao_; |    GLuint vao_; | ||||||
|    GLuint vbo_; |    GLuint vbo_; | ||||||
| 
 | 
 | ||||||
|    void Update(); |    void Update(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // TODO: OpenGL context with shaders
 | Rectangle::Rectangle(std::shared_ptr<GlContext> context) : | ||||||
| Rectangle::Rectangle(OpenGLFunctions& gl) : |     DrawItem(context->gl()), p(std::make_unique<Impl>(context)) | ||||||
|     DrawItem(), p(std::make_unique<RectangleImpl>(gl)) |  | ||||||
| { | { | ||||||
| } | } | ||||||
| Rectangle::~Rectangle() = default; | Rectangle::~Rectangle() = default; | ||||||
| 
 | 
 | ||||||
| Rectangle::Rectangle(Rectangle&&) noexcept = default; | Rectangle::Rectangle(Rectangle&&) noexcept            = default; | ||||||
| Rectangle& Rectangle::operator=(Rectangle&&) noexcept = default; | Rectangle& Rectangle::operator=(Rectangle&&) noexcept = default; | ||||||
| 
 | 
 | ||||||
| void Rectangle::Initialize() | 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.glGenVertexArrays(1, &p->vao_); | ||||||
|    gl.glGenBuffers(1, &p->vbo_); |    gl.glGenBuffers(1, &p->vbo_); | ||||||
|  | @ -106,16 +122,18 @@ void Rectangle::Initialize() | ||||||
|    p->dirty_ = true; |    p->dirty_ = true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Rectangle::Render() | void Rectangle::Render(const QMapbox::CustomLayerRenderParameters& params) | ||||||
| { | { | ||||||
|    if (p->visible_) |    if (p->visible_) | ||||||
|    { |    { | ||||||
|       gl::OpenGLFunctions& gl = p->gl_; |       gl::OpenGLFunctions& gl = p->context_->gl(); | ||||||
| 
 | 
 | ||||||
|       gl.glBindVertexArray(p->vao_); |       gl.glBindVertexArray(p->vao_); | ||||||
|       gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_); |       gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_); | ||||||
| 
 | 
 | ||||||
|       p->Update(); |       p->Update(); | ||||||
|  |       p->shaderProgram_->Use(); | ||||||
|  |       UseDefaultProjection(params, p->uMVPMatrixLocation_); | ||||||
| 
 | 
 | ||||||
|       if (p->fillColor_.has_value()) |       if (p->fillColor_.has_value()) | ||||||
|       { |       { | ||||||
|  | @ -133,7 +151,7 @@ void Rectangle::Render() | ||||||
| 
 | 
 | ||||||
| void Rectangle::Deinitialize() | void Rectangle::Deinitialize() | ||||||
| { | { | ||||||
|    gl::OpenGLFunctions& gl = p->gl_; |    gl::OpenGLFunctions& gl = p->context_->gl(); | ||||||
| 
 | 
 | ||||||
|    gl.glDeleteVertexArrays(1, &p->vao_); |    gl.glDeleteVertexArrays(1, &p->vao_); | ||||||
|    gl.glDeleteBuffers(1, &p->vbo_); |    gl.glDeleteBuffers(1, &p->vbo_); | ||||||
|  | @ -184,11 +202,11 @@ void Rectangle::SetVisible(bool visible) | ||||||
|    p->visible_ = visible; |    p->visible_ = visible; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RectangleImpl::Update() | void Rectangle::Impl::Update() | ||||||
| { | { | ||||||
|    if (dirty_) |    if (dirty_) | ||||||
|    { |    { | ||||||
|       gl::OpenGLFunctions& gl = gl_; |       gl::OpenGLFunctions& gl = context_->gl(); | ||||||
| 
 | 
 | ||||||
|       const float lox = x_; |       const float lox = x_; | ||||||
|       const float rox = x_ + width_; |       const float rox = x_ + width_; | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <scwx/qt/gl/gl.hpp> | #include <scwx/qt/gl/gl_context.hpp> | ||||||
| #include <scwx/qt/gl/draw/draw_item.hpp> | #include <scwx/qt/gl/draw/draw_item.hpp> | ||||||
| 
 | 
 | ||||||
| #include <boost/gil.hpp> | #include <boost/gil.hpp> | ||||||
|  | @ -14,22 +14,20 @@ namespace gl | ||||||
| namespace draw | namespace draw | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| class RectangleImpl; |  | ||||||
| 
 |  | ||||||
| class Rectangle : public DrawItem | class Rectangle : public DrawItem | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit Rectangle(OpenGLFunctions& gl); |    explicit Rectangle(std::shared_ptr<GlContext> context); | ||||||
|    ~Rectangle(); |    ~Rectangle(); | ||||||
| 
 | 
 | ||||||
|    Rectangle(const Rectangle&) = delete; |    Rectangle(const Rectangle&)            = delete; | ||||||
|    Rectangle& operator=(const Rectangle&) = delete; |    Rectangle& operator=(const Rectangle&) = delete; | ||||||
| 
 | 
 | ||||||
|    Rectangle(Rectangle&&) noexcept; |    Rectangle(Rectangle&&) noexcept; | ||||||
|    Rectangle& operator=(Rectangle&&) noexcept; |    Rectangle& operator=(Rectangle&&) noexcept; | ||||||
| 
 | 
 | ||||||
|    void Initialize() override; |    void Initialize() override; | ||||||
|    void Render() override; |    void Render(const QMapbox::CustomLayerRenderParameters& params) override; | ||||||
|    void Deinitialize() override; |    void Deinitialize() override; | ||||||
| 
 | 
 | ||||||
|    void SetBorder(float width, boost::gil::rgba8_pixel_t color); |    void SetBorder(float width, boost::gil::rgba8_pixel_t color); | ||||||
|  | @ -39,7 +37,9 @@ public: | ||||||
|    void SetVisible(bool visible); |    void SetVisible(bool visible); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|    std::unique_ptr<RectangleImpl> p; |    class Impl; | ||||||
|  | 
 | ||||||
|  |    std::unique_ptr<Impl> p; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace draw
 | } // 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 std::string logPrefix_ = "scwx::qt::gl::shader_program"; | ||||||
| static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | 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: | public: | ||||||
|    explicit ShaderProgramImpl(OpenGLFunctions& gl) : |    explicit Impl(OpenGLFunctions& gl) : gl_(gl), id_ {GL_INVALID_INDEX} | ||||||
|        gl_(gl), id_ {GL_INVALID_INDEX} |  | ||||||
|    { |    { | ||||||
|       // Create shader program
 |       // Create shader program
 | ||||||
|       id_ = gl_.glCreateProgram(); |       id_ = gl_.glCreateProgram(); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    ~ShaderProgramImpl() |    ~Impl() | ||||||
|    { |    { | ||||||
|       // Delete shader program
 |       // Delete shader program
 | ||||||
|       gl_.glDeleteProgram(id_); |       gl_.glDeleteProgram(id_); | ||||||
|  | @ -37,12 +36,12 @@ public: | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| ShaderProgram::ShaderProgram(OpenGLFunctions& gl) : | ShaderProgram::ShaderProgram(OpenGLFunctions& gl) : | ||||||
|     p(std::make_unique<ShaderProgramImpl>(gl)) |     p(std::make_unique<Impl>(gl)) | ||||||
| { | { | ||||||
| } | } | ||||||
| ShaderProgram::~ShaderProgram() = default; | ShaderProgram::~ShaderProgram() = default; | ||||||
| 
 | 
 | ||||||
| ShaderProgram::ShaderProgram(ShaderProgram&&) noexcept = default; | ShaderProgram::ShaderProgram(ShaderProgram&&) noexcept            = default; | ||||||
| ShaderProgram& ShaderProgram::operator=(ShaderProgram&&) noexcept = default; | ShaderProgram& ShaderProgram::operator=(ShaderProgram&&) noexcept = default; | ||||||
| 
 | 
 | ||||||
| GLuint ShaderProgram::id() const | GLuint ShaderProgram::id() const | ||||||
|  | @ -59,7 +58,7 @@ bool ShaderProgram::Load(const std::string& vertexPath, | ||||||
| 
 | 
 | ||||||
|    GLint   glSuccess; |    GLint   glSuccess; | ||||||
|    bool    success = true; |    bool    success = true; | ||||||
|    char    infoLog[INFO_LOG_BUF_SIZE]; |    char    infoLog[kInfoLogBufSize]; | ||||||
|    GLsizei logLength; |    GLsizei logLength; | ||||||
| 
 | 
 | ||||||
|    QFile vertexFile(vertexPath.c_str()); |    QFile vertexFile(vertexPath.c_str()); | ||||||
|  | @ -102,7 +101,7 @@ bool ShaderProgram::Load(const std::string& vertexPath, | ||||||
| 
 | 
 | ||||||
|    // Check for errors
 |    // Check for errors
 | ||||||
|    gl.glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &glSuccess); |    gl.glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &glSuccess); | ||||||
|    gl.glGetShaderInfoLog(vertexShader, INFO_LOG_BUF_SIZE, &logLength, infoLog); |    gl.glGetShaderInfoLog(vertexShader, kInfoLogBufSize, &logLength, infoLog); | ||||||
|    if (!glSuccess) |    if (!glSuccess) | ||||||
|    { |    { | ||||||
|       logger_->error("Vertex shader compilation failed: {}", infoLog); |       logger_->error("Vertex shader compilation failed: {}", infoLog); | ||||||
|  | @ -122,8 +121,7 @@ bool ShaderProgram::Load(const std::string& vertexPath, | ||||||
| 
 | 
 | ||||||
|    // Check for errors
 |    // Check for errors
 | ||||||
|    gl.glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &glSuccess); |    gl.glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &glSuccess); | ||||||
|    gl.glGetShaderInfoLog( |    gl.glGetShaderInfoLog(fragmentShader, kInfoLogBufSize, &logLength, infoLog); | ||||||
|       fragmentShader, INFO_LOG_BUF_SIZE, &logLength, infoLog); |  | ||||||
|    if (!glSuccess) |    if (!glSuccess) | ||||||
|    { |    { | ||||||
|       logger_->error("Fragment shader compilation failed: {}", infoLog); |       logger_->error("Fragment shader compilation failed: {}", infoLog); | ||||||
|  | @ -142,7 +140,7 @@ bool ShaderProgram::Load(const std::string& vertexPath, | ||||||
| 
 | 
 | ||||||
|       // Check for errors
 |       // Check for errors
 | ||||||
|       gl.glGetProgramiv(p->id_, GL_LINK_STATUS, &glSuccess); |       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) |       if (!glSuccess) | ||||||
|       { |       { | ||||||
|          logger_->error("Shader program link failed: {}", infoLog); |          logger_->error("Shader program link failed: {}", infoLog); | ||||||
|  |  | ||||||
|  | @ -16,15 +16,13 @@ namespace qt | ||||||
| namespace gl | namespace gl | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| class ShaderProgramImpl; |  | ||||||
| 
 |  | ||||||
| class ShaderProgram | class ShaderProgram | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit ShaderProgram(OpenGLFunctions& gl); |    explicit ShaderProgram(OpenGLFunctions& gl); | ||||||
|    virtual ~ShaderProgram(); |    virtual ~ShaderProgram(); | ||||||
| 
 | 
 | ||||||
|    ShaderProgram(const ShaderProgram&) = delete; |    ShaderProgram(const ShaderProgram&)            = delete; | ||||||
|    ShaderProgram& operator=(const ShaderProgram&) = delete; |    ShaderProgram& operator=(const ShaderProgram&) = delete; | ||||||
| 
 | 
 | ||||||
|    ShaderProgram(ShaderProgram&&) noexcept; |    ShaderProgram(ShaderProgram&&) noexcept; | ||||||
|  | @ -37,7 +35,9 @@ public: | ||||||
|    void Use() const; |    void Use() const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|    std::unique_ptr<ShaderProgramImpl> p; |    class Impl; | ||||||
|  | 
 | ||||||
|  |    std::unique_ptr<Impl> p; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace gl
 | } // namespace gl
 | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| #include <scwx/qt/gl/text_shader.hpp> | #include <scwx/qt/gl/text_shader.hpp> | ||||||
|  | #include <scwx/qt/gl/shader_program.hpp> | ||||||
| #include <scwx/util/logger.hpp> | #include <scwx/util/logger.hpp> | ||||||
| 
 | 
 | ||||||
| #pragma warning(push, 0) | #pragma warning(push, 0) | ||||||
|  | @ -18,41 +19,46 @@ static const auto        logger_    = scwx::util::Logger::Create(logPrefix_); | ||||||
| class TextShaderImpl | class TextShaderImpl | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit TextShaderImpl(OpenGLFunctions& gl) : |    explicit TextShaderImpl(std::shared_ptr<GlContext> context) : | ||||||
|        gl_ {gl}, projectionLocation_(GL_INVALID_INDEX) |        context_ {context}, | ||||||
|  |        shaderProgram_ {nullptr}, | ||||||
|  |        projectionLocation_(GL_INVALID_INDEX) | ||||||
|    { |    { | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    ~TextShaderImpl() {} |    ~TextShaderImpl() {} | ||||||
| 
 | 
 | ||||||
|    OpenGLFunctions& gl_; |    std::shared_ptr<GlContext>     context_; | ||||||
|  |    std::shared_ptr<ShaderProgram> shaderProgram_; | ||||||
| 
 | 
 | ||||||
|    GLint projectionLocation_; |    GLint projectionLocation_; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| TextShader::TextShader(OpenGLFunctions& gl) : | TextShader::TextShader(std::shared_ptr<GlContext> context) : | ||||||
|     ShaderProgram(gl), p(std::make_unique<TextShaderImpl>(gl)) |     p(std::make_unique<TextShaderImpl>(context)) | ||||||
| { | { | ||||||
| } | } | ||||||
| TextShader::~TextShader() = default; | TextShader::~TextShader() = default; | ||||||
| 
 | 
 | ||||||
| TextShader::TextShader(TextShader&&) noexcept = default; | TextShader::TextShader(TextShader&&) noexcept            = default; | ||||||
| TextShader& TextShader::operator=(TextShader&&) noexcept = default; | TextShader& TextShader::operator=(TextShader&&) noexcept = default; | ||||||
| 
 | 
 | ||||||
| bool TextShader::Initialize() | bool TextShader::Initialize() | ||||||
| { | { | ||||||
|    OpenGLFunctions& gl = p->gl_; |    OpenGLFunctions& gl = p->context_->gl(); | ||||||
| 
 | 
 | ||||||
|    // Load and configure shader
 |    // 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) |    if (p->projectionLocation_ == -1) | ||||||
|    { |    { | ||||||
|       logger_->warn("Could not find projection"); |       logger_->warn("Could not find projection"); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    return success; |    return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void TextShader::RenderText(const std::string&               text, | void TextShader::RenderText(const std::string&               text, | ||||||
|  | @ -65,9 +71,9 @@ void TextShader::RenderText(const std::string&               text, | ||||||
|                             GLuint                           textureId, |                             GLuint                           textureId, | ||||||
|                             TextAlign                        align) |                             TextAlign                        align) | ||||||
| { | { | ||||||
|    OpenGLFunctions& gl = p->gl_; |    OpenGLFunctions& gl = p->context_->gl(); | ||||||
| 
 | 
 | ||||||
|    Use(); |    p->shaderProgram_->Use(); | ||||||
| 
 | 
 | ||||||
|    gl.glEnable(GL_BLEND); |    gl.glEnable(GL_BLEND); | ||||||
|    gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |    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) | void TextShader::SetProjection(const glm::mat4& projection) | ||||||
| { | { | ||||||
|    p->gl_.glUniformMatrix4fv( |    p->context_->gl().glUniformMatrix4fv( | ||||||
|       p->projectionLocation_, 1, GL_FALSE, glm::value_ptr(projection)); |       p->projectionLocation_, 1, GL_FALSE, glm::value_ptr(projection)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <scwx/qt/gl/shader_program.hpp> | #include <scwx/qt/gl/gl_context.hpp> | ||||||
| #include <scwx/qt/util/font.hpp> | #include <scwx/qt/util/font.hpp> | ||||||
| 
 | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
|  | @ -24,13 +24,13 @@ enum class TextAlign | ||||||
| 
 | 
 | ||||||
| class TextShaderImpl; | class TextShaderImpl; | ||||||
| 
 | 
 | ||||||
| class TextShader : public ShaderProgram | class TextShader | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit TextShader(OpenGLFunctions& gl); |    explicit TextShader(std::shared_ptr<GlContext> context); | ||||||
|    ~TextShader(); |    ~TextShader(); | ||||||
| 
 | 
 | ||||||
|    TextShader(const TextShader&) = delete; |    TextShader(const TextShader&)            = delete; | ||||||
|    TextShader& operator=(const TextShader&) = delete; |    TextShader& operator=(const TextShader&) = delete; | ||||||
| 
 | 
 | ||||||
|    TextShader(TextShader&&) noexcept; |    TextShader(TextShader&&) noexcept; | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| #include <scwx/qt/manager/resource_manager.hpp> | #include <scwx/qt/manager/resource_manager.hpp> | ||||||
| #include <scwx/qt/util/font.hpp> | #include <scwx/qt/util/font.hpp> | ||||||
|  | #include <scwx/qt/util/texture_atlas.hpp> | ||||||
| 
 | 
 | ||||||
| namespace scwx | namespace scwx | ||||||
| { | { | ||||||
|  | @ -20,6 +21,13 @@ static void LoadFonts() | ||||||
| { | { | ||||||
|    util::Font::Create(":/res/fonts/din1451alt.ttf"); |    util::Font::Create(":/res/fonts/din1451alt.ttf"); | ||||||
|    util::Font::Create(":/res/fonts/din1451alt_g.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
 | } // namespace ResourceManager
 | ||||||
|  |  | ||||||
|  | @ -21,7 +21,7 @@ class ColorTableLayerImpl | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit ColorTableLayerImpl(std::shared_ptr<MapContext> context) : |    explicit ColorTableLayerImpl(std::shared_ptr<MapContext> context) : | ||||||
|        shaderProgram_(context->gl_), |        shaderProgram_(nullptr), | ||||||
|        uMVPMatrixLocation_(GL_INVALID_INDEX), |        uMVPMatrixLocation_(GL_INVALID_INDEX), | ||||||
|        vbo_ {GL_INVALID_INDEX}, |        vbo_ {GL_INVALID_INDEX}, | ||||||
|        vao_ {GL_INVALID_INDEX}, |        vao_ {GL_INVALID_INDEX}, | ||||||
|  | @ -31,7 +31,8 @@ public: | ||||||
|    } |    } | ||||||
|    ~ColorTableLayerImpl() = default; |    ~ColorTableLayerImpl() = default; | ||||||
| 
 | 
 | ||||||
|    gl::ShaderProgram     shaderProgram_; |    std::shared_ptr<gl::ShaderProgram> shaderProgram_; | ||||||
|  | 
 | ||||||
|    GLint                 uMVPMatrixLocation_; |    GLint                 uMVPMatrixLocation_; | ||||||
|    std::array<GLuint, 2> vbo_; |    std::array<GLuint, 2> vbo_; | ||||||
|    GLuint                vao_; |    GLuint                vao_; | ||||||
|  | @ -52,13 +53,14 @@ void ColorTableLayer::Initialize() | ||||||
| { | { | ||||||
|    logger_->debug("Initialize()"); |    logger_->debug("Initialize()"); | ||||||
| 
 | 
 | ||||||
|    gl::OpenGLFunctions& gl = context()->gl_; |    gl::OpenGLFunctions& gl = context()->gl(); | ||||||
| 
 | 
 | ||||||
|    // Load and configure overlay shader
 |    // 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_ = |    p->uMVPMatrixLocation_ = | ||||||
|       gl.glGetUniformLocation(p->shaderProgram_.id(), "uMVPMatrix"); |       gl.glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix"); | ||||||
|    if (p->uMVPMatrixLocation_ == -1) |    if (p->uMVPMatrixLocation_ == -1) | ||||||
|    { |    { | ||||||
|       logger_->warn("Could not find uMVPMatrix"); |       logger_->warn("Could not find uMVPMatrix"); | ||||||
|  | @ -66,7 +68,7 @@ void ColorTableLayer::Initialize() | ||||||
| 
 | 
 | ||||||
|    gl.glGenTextures(1, &p->texture_); |    gl.glGenTextures(1, &p->texture_); | ||||||
| 
 | 
 | ||||||
|    p->shaderProgram_.Use(); |    p->shaderProgram_->Use(); | ||||||
| 
 | 
 | ||||||
|    // Generate a vertex array object
 |    // Generate a vertex array object
 | ||||||
|    gl.glGenVertexArrays(1, &p->vao_); |    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.glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, static_cast<void*>(0)); | ||||||
|    gl.glEnableVertexAttribArray(1); |    gl.glEnableVertexAttribArray(1); | ||||||
| 
 | 
 | ||||||
|    connect(context()->radarProductView_.get(), |    connect(context()->radar_product_view().get(), | ||||||
|            &view::RadarProductView::ColorTableUpdated, |            &view::RadarProductView::ColorTableUpdated, | ||||||
|            this, |            this, | ||||||
|            [=]() { p->colorTableNeedsUpdate_ = true; }); |            [=]() { p->colorTableNeedsUpdate_ = true; }); | ||||||
|  | @ -107,10 +109,11 @@ void ColorTableLayer::Initialize() | ||||||
| 
 | 
 | ||||||
| void ColorTableLayer::Render(const QMapbox::CustomLayerRenderParameters& params) | 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 || |    if (context()->radar_product_view() == nullptr || | ||||||
|        !context()->radarProductView_->IsInitialized()) |        !context()->radar_product_view()->IsInitialized()) | ||||||
|    { |    { | ||||||
|       // Defer rendering until view is initialized
 |       // Defer rendering until view is initialized
 | ||||||
|       return; |       return; | ||||||
|  | @ -121,14 +124,14 @@ void ColorTableLayer::Render(const QMapbox::CustomLayerRenderParameters& params) | ||||||
|                                      0.0f, |                                      0.0f, | ||||||
|                                      static_cast<float>(params.height)); |                                      static_cast<float>(params.height)); | ||||||
| 
 | 
 | ||||||
|    p->shaderProgram_.Use(); |    p->shaderProgram_->Use(); | ||||||
| 
 | 
 | ||||||
|    gl.glUniformMatrix4fv( |    gl.glUniformMatrix4fv( | ||||||
|       p->uMVPMatrixLocation_, 1, GL_FALSE, glm::value_ptr(projection)); |       p->uMVPMatrixLocation_, 1, GL_FALSE, glm::value_ptr(projection)); | ||||||
| 
 | 
 | ||||||
|    if (p->colorTableNeedsUpdate_) |    if (p->colorTableNeedsUpdate_) | ||||||
|    { |    { | ||||||
|       p->colorTable_ = context()->radarProductView_->color_table(); |       p->colorTable_ = radarProductView->color_table(); | ||||||
| 
 | 
 | ||||||
|       gl.glActiveTexture(GL_TEXTURE0); |       gl.glActiveTexture(GL_TEXTURE0); | ||||||
|       gl.glBindTexture(GL_TEXTURE_1D, p->texture_); |       gl.glBindTexture(GL_TEXTURE_1D, p->texture_); | ||||||
|  | @ -145,9 +148,8 @@ void ColorTableLayer::Render(const QMapbox::CustomLayerRenderParameters& params) | ||||||
|       gl.glGenerateMipmap(GL_TEXTURE_1D); |       gl.glGenerateMipmap(GL_TEXTURE_1D); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    if (p->colorTable_.size() > 0 && |    if (p->colorTable_.size() > 0 && radarProductView->sweep_time() != | ||||||
|        context()->radarProductView_->sweep_time() != |                                        std::chrono::system_clock::time_point()) | ||||||
|           std::chrono::system_clock::time_point()) |  | ||||||
|    { |    { | ||||||
|       // Color table panel vertices
 |       // Color table panel vertices
 | ||||||
|       const float vertexLX       = 0.0f; |       const float vertexLX       = 0.0f; | ||||||
|  | @ -176,7 +178,7 @@ void ColorTableLayer::Deinitialize() | ||||||
| { | { | ||||||
|    logger_->debug("Deinitialize()"); |    logger_->debug("Deinitialize()"); | ||||||
| 
 | 
 | ||||||
|    gl::OpenGLFunctions& gl = context()->gl_; |    gl::OpenGLFunctions& gl = context()->gl(); | ||||||
| 
 | 
 | ||||||
|    gl.glDeleteVertexArrays(1, &p->vao_); |    gl.glDeleteVertexArrays(1, &p->vao_); | ||||||
|    gl.glDeleteBuffers(2, p->vbo_.data()); |    gl.glDeleteBuffers(2, p->vbo_.data()); | ||||||
|  |  | ||||||
|  | @ -2,12 +2,6 @@ | ||||||
| #include <scwx/qt/gl/shader_program.hpp> | #include <scwx/qt/gl/shader_program.hpp> | ||||||
| #include <scwx/util/logger.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 scwx | ||||||
| { | { | ||||||
| namespace qt | namespace qt | ||||||
|  | @ -22,16 +16,14 @@ class DrawLayerImpl | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit DrawLayerImpl(std::shared_ptr<MapContext> context) : |    explicit DrawLayerImpl(std::shared_ptr<MapContext> context) : | ||||||
|        shaderProgram_ {context->gl_}, uMVPMatrixLocation_(GL_INVALID_INDEX) |        context_ {context}, drawList_ {}, textureAtlas_ {GL_INVALID_INDEX} | ||||||
|    { |    { | ||||||
|    } |    } | ||||||
| 
 |  | ||||||
|    ~DrawLayerImpl() {} |    ~DrawLayerImpl() {} | ||||||
| 
 | 
 | ||||||
|    gl::ShaderProgram shaderProgram_; |    std::shared_ptr<MapContext>                      context_; | ||||||
|    GLint             uMVPMatrixLocation_; |  | ||||||
| 
 |  | ||||||
|    std::vector<std::shared_ptr<gl::draw::DrawItem>> drawList_; |    std::vector<std::shared_ptr<gl::draw::DrawItem>> drawList_; | ||||||
|  |    GLuint                                           textureAtlas_; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| DrawLayer::DrawLayer(std::shared_ptr<MapContext> context) : | DrawLayer::DrawLayer(std::shared_ptr<MapContext> context) : | ||||||
|  | @ -42,20 +34,9 @@ DrawLayer::~DrawLayer() = default; | ||||||
| 
 | 
 | ||||||
| void DrawLayer::Initialize() | void DrawLayer::Initialize() | ||||||
| { | { | ||||||
|    gl::OpenGLFunctions& gl = context()->gl_; |    p->textureAtlas_ = p->context_->GetTextureAtlas(); | ||||||
| 
 | 
 | ||||||
|    p->shaderProgram_.Load(":/gl/color.vert", ":/gl/color.frag"); |    for (auto& item : p->drawList_) | ||||||
| 
 |  | ||||||
|    p->uMVPMatrixLocation_ = |  | ||||||
|       gl.glGetUniformLocation(p->shaderProgram_.id(), "uMVPMatrix"); |  | ||||||
|    if (p->uMVPMatrixLocation_ == -1) |  | ||||||
|    { |  | ||||||
|       logger_->warn("Could not find uMVPMatrix"); |  | ||||||
|    } |  | ||||||
| 
 |  | ||||||
|    p->shaderProgram_.Use(); |  | ||||||
| 
 |  | ||||||
|    for (auto item : p->drawList_) |  | ||||||
|    { |    { | ||||||
|       item->Initialize(); |       item->Initialize(); | ||||||
|    } |    } | ||||||
|  | @ -63,27 +44,22 @@ void DrawLayer::Initialize() | ||||||
| 
 | 
 | ||||||
| void DrawLayer::Render(const QMapbox::CustomLayerRenderParameters& params) | 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, |    for (auto& item : p->drawList_) | ||||||
|                                      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_) |  | ||||||
|    { |    { | ||||||
|       item->Render(); |       item->Render(params); | ||||||
|    } |    } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DrawLayer::Deinitialize() | void DrawLayer::Deinitialize() | ||||||
| { | { | ||||||
|    for (auto item : p->drawList_) |    p->textureAtlas_ = GL_INVALID_INDEX; | ||||||
|  | 
 | ||||||
|  |    for (auto& item : p->drawList_) | ||||||
|    { |    { | ||||||
|       item->Deinitialize(); |       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 | #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/map/map_settings.hpp> | ||||||
| #include <scwx/qt/view/radar_product_view.hpp> | #include <scwx/qt/view/radar_product_view.hpp> | ||||||
| 
 | 
 | ||||||
|  | @ -11,32 +11,35 @@ namespace qt | ||||||
| namespace map | namespace map | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| struct MapContext | class MapContext : public gl::GlContext | ||||||
| { | { | ||||||
|  | public: | ||||||
|    explicit MapContext( |    explicit MapContext( | ||||||
|       std::shared_ptr<view::RadarProductView> radarProductView = nullptr) : |       std::shared_ptr<view::RadarProductView> radarProductView = nullptr); | ||||||
|        gl_ {}, |    ~MapContext(); | ||||||
|        settings_ {}, |  | ||||||
|        radarProductView_ {radarProductView}, |  | ||||||
|        radarProductGroup_ {common::RadarProductGroup::Unknown}, |  | ||||||
|        radarProduct_ {"???"}, |  | ||||||
|        radarProductCode_ {0} |  | ||||||
|    { |  | ||||||
|    } |  | ||||||
|    ~MapContext() = default; |  | ||||||
| 
 | 
 | ||||||
|    MapContext(const MapContext&) = delete; |    MapContext(const MapContext&)            = delete; | ||||||
|    MapContext& operator=(const MapContext&) = delete; |    MapContext& operator=(const MapContext&) = delete; | ||||||
| 
 | 
 | ||||||
|    MapContext(MapContext&&) noexcept = default; |    MapContext(MapContext&&) noexcept; | ||||||
|    MapContext& operator=(MapContext&&) noexcept = default; |    MapContext& operator=(MapContext&&) noexcept; | ||||||
| 
 | 
 | ||||||
|    gl::OpenGLFunctions                     gl_; |    MapSettings&                            settings(); | ||||||
|    MapSettings                             settings_; |    std::shared_ptr<view::RadarProductView> radar_product_view() const; | ||||||
|    std::shared_ptr<view::RadarProductView> radarProductView_; |    common::RadarProductGroup               radar_product_group() const; | ||||||
|    common::RadarProductGroup               radarProductGroup_; |    std::string                             radar_product() const; | ||||||
|    std::string                             radarProduct_; |    int16_t                                 radar_product_code() const; | ||||||
|    int16_t                                 radarProductCode_; | 
 | ||||||
|  |    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
 | } // namespace map
 | ||||||
|  |  | ||||||
|  | @ -153,9 +153,11 @@ common::Level3ProductCategoryMap MapWidget::GetAvailableLevel3Categories() | ||||||
| 
 | 
 | ||||||
| float MapWidget::GetElevation() const | 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 |    else | ||||||
|    { |    { | ||||||
|  | @ -165,9 +167,11 @@ float MapWidget::GetElevation() const | ||||||
| 
 | 
 | ||||||
| std::vector<float> MapWidget::GetElevationCuts() 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 |    else | ||||||
|    { |    { | ||||||
|  | @ -182,10 +186,12 @@ MapWidgetImpl::GetLevel2ProductOrDefault(const std::string& productName) const | ||||||
| 
 | 
 | ||||||
|    if (level2Product == common::Level2Product::Unknown) |    if (level2Product == common::Level2Product::Unknown) | ||||||
|    { |    { | ||||||
|       if (context_->radarProductView_ != nullptr) |       auto radarProductView = context_->radar_product_view(); | ||||||
|  | 
 | ||||||
|  |       if (radarProductView != nullptr) | ||||||
|       { |       { | ||||||
|          level2Product = common::GetLevel2Product( |          level2Product = | ||||||
|             context_->radarProductView_->GetRadarProductName()); |             common::GetLevel2Product(radarProductView->GetRadarProductName()); | ||||||
|       } |       } | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|  | @ -218,9 +224,11 @@ std::vector<std::string> MapWidget::GetLevel3Products() | ||||||
| 
 | 
 | ||||||
| common::RadarProductGroup MapWidget::GetRadarProductGroup() const | 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 |    else | ||||||
|    { |    { | ||||||
|  | @ -230,10 +238,11 @@ common::RadarProductGroup MapWidget::GetRadarProductGroup() const | ||||||
| 
 | 
 | ||||||
| std::string MapWidget::GetRadarProductName() 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 |    else | ||||||
|    { |    { | ||||||
|  | @ -255,9 +264,11 @@ std::shared_ptr<config::RadarSite> MapWidget::GetRadarSite() const | ||||||
| 
 | 
 | ||||||
| uint16_t MapWidget::GetVcp() 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 |    else | ||||||
|    { |    { | ||||||
|  | @ -267,10 +278,12 @@ uint16_t MapWidget::GetVcp() const | ||||||
| 
 | 
 | ||||||
| void MapWidget::SelectElevation(float elevation) | 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); |       radarProductView->SelectElevation(elevation); | ||||||
|       p->context_->radarProductView_->Update(); |       radarProductView->Update(); | ||||||
|    } |    } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -280,8 +293,7 @@ void MapWidget::SelectRadarProduct(common::RadarProductGroup group, | ||||||
| { | { | ||||||
|    bool radarProductViewCreated = false; |    bool radarProductViewCreated = false; | ||||||
| 
 | 
 | ||||||
|    std::shared_ptr<view::RadarProductView>& radarProductView = |    auto radarProductView = p->context_->radar_product_view(); | ||||||
|       p->context_->radarProductView_; |  | ||||||
| 
 | 
 | ||||||
|    std::string productName {product}; |    std::string productName {product}; | ||||||
| 
 | 
 | ||||||
|  | @ -304,12 +316,13 @@ void MapWidget::SelectRadarProduct(common::RadarProductGroup group, | ||||||
|        (radarProductView->GetRadarProductGroup() == |        (radarProductView->GetRadarProductGroup() == | ||||||
|            common::RadarProductGroup::Level2 && |            common::RadarProductGroup::Level2 && | ||||||
|         radarProductView->GetRadarProductName() != productName) || |         radarProductView->GetRadarProductName() != productName) || | ||||||
|        p->context_->radarProductCode_ != productCode) |        p->context_->radar_product_code() != productCode) | ||||||
|    { |    { | ||||||
|       p->RadarProductViewDisconnect(); |       p->RadarProductViewDisconnect(); | ||||||
| 
 | 
 | ||||||
|       radarProductView = view::RadarProductViewFactory::Create( |       radarProductView = view::RadarProductViewFactory::Create( | ||||||
|          group, productName, productCode, p->radarProductManager_); |          group, productName, productCode, p->radarProductManager_); | ||||||
|  |       p->context_->set_radar_product_view(radarProductView); | ||||||
| 
 | 
 | ||||||
|       p->RadarProductViewConnect(); |       p->RadarProductViewConnect(); | ||||||
| 
 | 
 | ||||||
|  | @ -320,9 +333,9 @@ void MapWidget::SelectRadarProduct(common::RadarProductGroup group, | ||||||
|       radarProductView->SelectProduct(productName); |       radarProductView->SelectProduct(productName); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    p->context_->radarProductGroup_ = group; |    p->context_->set_radar_product_group(group); | ||||||
|    p->context_->radarProduct_      = productName; |    p->context_->set_radar_product(productName); | ||||||
|    p->context_->radarProductCode_  = productCode; |    p->context_->set_radar_product_code(productCode); | ||||||
| 
 | 
 | ||||||
|    if (radarProductView != nullptr) |    if (radarProductView != nullptr) | ||||||
|    { |    { | ||||||
|  | @ -372,7 +385,7 @@ void MapWidget::SelectRadarProduct( | ||||||
| 
 | 
 | ||||||
| void MapWidget::SetActive(bool isActive) | void MapWidget::SetActive(bool isActive) | ||||||
| { | { | ||||||
|    p->context_->settings_.isActive_ = isActive; |    p->context_->settings().isActive_ = isActive; | ||||||
|    update(); |    update(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -382,11 +395,13 @@ void MapWidget::SetAutoRefresh(bool enabled) | ||||||
|    { |    { | ||||||
|       p->autoRefreshEnabled_ = 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->radarProductManager_->EnableRefresh( | ||||||
|             p->context_->radarProductView_->GetRadarProductGroup(), |             radarProductView->GetRadarProductGroup(), | ||||||
|             p->context_->radarProductView_->GetRadarProductName(), |             radarProductView->GetRadarProductName(), | ||||||
|             true); |             true); | ||||||
|       } |       } | ||||||
|    } |    } | ||||||
|  | @ -430,7 +445,9 @@ void MapWidget::AddLayers() | ||||||
|    } |    } | ||||||
|    p->layerList_.clear(); |    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->radarProductLayer_ = std::make_shared<RadarProductLayer>(p->context_); | ||||||
|       p->colorTableLayer_   = std::make_shared<ColorTableLayer>(p->context_); |       p->colorTableLayer_   = std::make_shared<ColorTableLayer>(p->context_); | ||||||
|  | @ -453,7 +470,7 @@ void MapWidget::AddLayers() | ||||||
| 
 | 
 | ||||||
|       p->AddLayer("radar", p->radarProductLayer_, before); |       p->AddLayer("radar", p->radarProductLayer_, before); | ||||||
|       RadarRangeLayer::Add(p->map_, |       RadarRangeLayer::Add(p->map_, | ||||||
|                            p->context_->radarProductView_->range(), |                            radarProductView->range(), | ||||||
|                            {radarSite->latitude(), radarSite->longitude()}); |                            {radarSite->latitude(), radarSite->longitude()}); | ||||||
|       p->AddLayer("colorTable", p->colorTableLayer_); |       p->AddLayer("colorTable", p->colorTableLayer_); | ||||||
|    } |    } | ||||||
|  | @ -572,7 +589,7 @@ void MapWidget::initializeGL() | ||||||
|    logger_->debug("initializeGL()"); |    logger_->debug("initializeGL()"); | ||||||
| 
 | 
 | ||||||
|    makeCurrent(); |    makeCurrent(); | ||||||
|    p->context_->gl_.initializeOpenGLFunctions(); |    p->context_->gl().initializeOpenGLFunctions(); | ||||||
| 
 | 
 | ||||||
|    p->map_.reset(new QMapboxGL(nullptr, p->settings_, size(), pixelRatio())); |    p->map_.reset(new QMapboxGL(nullptr, p->settings_, size(), pixelRatio())); | ||||||
|    connect(p->map_.get(), |    connect(p->map_.get(), | ||||||
|  | @ -637,9 +654,10 @@ void MapWidgetImpl::RadarProductManagerConnect() | ||||||
|              const std::string&                    product, |              const std::string&                    product, | ||||||
|              std::chrono::system_clock::time_point latestTime) |              std::chrono::system_clock::time_point latestTime) | ||||||
|          { |          { | ||||||
|             if (autoRefreshEnabled_ && context_->radarProductGroup_ == group && |             if (autoRefreshEnabled_ && | ||||||
|  |                 context_->radar_product_group() == group && | ||||||
|                 (group == common::RadarProductGroup::Level2 || |                 (group == common::RadarProductGroup::Level2 || | ||||||
|                  context_->radarProduct_ == product)) |                  context_->radar_product() == product)) | ||||||
|             { |             { | ||||||
|                // Create file request
 |                // Create file request
 | ||||||
|                std::shared_ptr<request::NexradFileRequest> request = |                std::shared_ptr<request::NexradFileRequest> request = | ||||||
|  | @ -698,16 +716,18 @@ void MapWidgetImpl::InitializeNewRadarProductView( | ||||||
|    util::async( |    util::async( | ||||||
|       [=]() |       [=]() | ||||||
|       { |       { | ||||||
|  |          auto radarProductView = context_->radar_product_view(); | ||||||
|  | 
 | ||||||
|          std::string colorTableFile = |          std::string colorTableFile = | ||||||
|             manager::SettingsManager::palette_settings()->palette(colorPalette); |             manager::SettingsManager::palette_settings()->palette(colorPalette); | ||||||
|          if (!colorTableFile.empty()) |          if (!colorTableFile.empty()) | ||||||
|          { |          { | ||||||
|             std::shared_ptr<common::ColorTable> colorTable = |             std::shared_ptr<common::ColorTable> colorTable = | ||||||
|                common::ColorTable::Load(colorTableFile); |                common::ColorTable::Load(colorTableFile); | ||||||
|             context_->radarProductView_->LoadColorTable(colorTable); |             radarProductView->LoadColorTable(colorTable); | ||||||
|          } |          } | ||||||
| 
 | 
 | ||||||
|          context_->radarProductView_->Initialize(); |          radarProductView->Initialize(); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|    if (map_ != nullptr) |    if (map_ != nullptr) | ||||||
|  | @ -718,26 +738,28 @@ void MapWidgetImpl::InitializeNewRadarProductView( | ||||||
| 
 | 
 | ||||||
| void MapWidgetImpl::RadarProductViewConnect() | void MapWidgetImpl::RadarProductViewConnect() | ||||||
| { | { | ||||||
|    if (context_->radarProductView_ != nullptr) |    auto radarProductView = context_->radar_product_view(); | ||||||
|  | 
 | ||||||
|  |    if (radarProductView != nullptr) | ||||||
|    { |    { | ||||||
|       connect( |       connect( | ||||||
|          context_->radarProductView_.get(), |          radarProductView.get(), | ||||||
|          &view::RadarProductView::ColorTableUpdated, |          &view::RadarProductView::ColorTableUpdated, | ||||||
|          this, |          this, | ||||||
|          [&]() { widget_->update(); }, |          [&]() { widget_->update(); }, | ||||||
|          Qt::QueuedConnection); |          Qt::QueuedConnection); | ||||||
|       connect( |       connect( | ||||||
|          context_->radarProductView_.get(), |          radarProductView.get(), | ||||||
|          &view::RadarProductView::SweepComputed, |          &view::RadarProductView::SweepComputed, | ||||||
|          this, |          this, | ||||||
|          [&]() |          [=]() | ||||||
|          { |          { | ||||||
|             std::shared_ptr<config::RadarSite> radarSite = |             std::shared_ptr<config::RadarSite> radarSite = | ||||||
|                radarProductManager_->radar_site(); |                radarProductManager_->radar_site(); | ||||||
| 
 | 
 | ||||||
|             RadarRangeLayer::Update( |             RadarRangeLayer::Update( | ||||||
|                map_, |                map_, | ||||||
|                context_->radarProductView_->range(), |                radarProductView->range(), | ||||||
|                {radarSite->latitude(), radarSite->longitude()}); |                {radarSite->latitude(), radarSite->longitude()}); | ||||||
|             widget_->update(); |             widget_->update(); | ||||||
|             emit widget_->RadarSweepUpdated(); |             emit widget_->RadarSweepUpdated(); | ||||||
|  | @ -748,13 +770,15 @@ void MapWidgetImpl::RadarProductViewConnect() | ||||||
| 
 | 
 | ||||||
| void MapWidgetImpl::RadarProductViewDisconnect() | 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, |                  &view::RadarProductView::ColorTableUpdated, | ||||||
|                  this, |                  this, | ||||||
|                  nullptr); |                  nullptr); | ||||||
|       disconnect(context_->radarProductView_.get(), |       disconnect(radarProductView.get(), | ||||||
|                  &view::RadarProductView::SweepComputed, |                  &view::RadarProductView::SweepComputed, | ||||||
|                  this, |                  this, | ||||||
|                  nullptr); |                  nullptr); | ||||||
|  |  | ||||||
|  | @ -34,12 +34,12 @@ class OverlayLayerImpl | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit OverlayLayerImpl(std::shared_ptr<MapContext> context) : |    explicit OverlayLayerImpl(std::shared_ptr<MapContext> context) : | ||||||
|        textShader_(context->gl_), |        textShader_(context), | ||||||
|        font_(util::Font::Create(":/res/fonts/din1451alt.ttf")), |        font_(util::Font::Create(":/res/fonts/din1451alt.ttf")), | ||||||
|        texture_ {GL_INVALID_INDEX}, |        texture_ {GL_INVALID_INDEX}, | ||||||
|        activeBoxOuter_ {std::make_shared<gl::draw::Rectangle>(context->gl_)}, |        activeBoxOuter_ {std::make_shared<gl::draw::Rectangle>(context)}, | ||||||
|        activeBoxInner_ {std::make_shared<gl::draw::Rectangle>(context->gl_)}, |        activeBoxInner_ {std::make_shared<gl::draw::Rectangle>(context)}, | ||||||
|        timeBox_ {std::make_shared<gl::draw::Rectangle>(context->gl_)}, |        timeBox_ {std::make_shared<gl::draw::Rectangle>(context)}, | ||||||
|        sweepTimeString_ {}, |        sweepTimeString_ {}, | ||||||
|        sweepTimeNeedsUpdate_ {true} |        sweepTimeNeedsUpdate_ {true} | ||||||
|    { |    { | ||||||
|  | @ -81,7 +81,8 @@ void OverlayLayer::Initialize() | ||||||
| 
 | 
 | ||||||
|    DrawLayer::Initialize(); |    DrawLayer::Initialize(); | ||||||
| 
 | 
 | ||||||
|    gl::OpenGLFunctions& gl = context()->gl_; |    gl::OpenGLFunctions& gl               = context()->gl(); | ||||||
|  |    auto                 radarProductView = context()->radar_product_view(); | ||||||
| 
 | 
 | ||||||
|    p->textShader_.Initialize(); |    p->textShader_.Initialize(); | ||||||
| 
 | 
 | ||||||
|  | @ -90,9 +91,9 @@ void OverlayLayer::Initialize() | ||||||
|       p->texture_ = p->font_->GenerateTexture(gl); |       p->texture_ = p->font_->GenerateTexture(gl); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    if (context()->radarProductView_ != nullptr) |    if (radarProductView != nullptr) | ||||||
|    { |    { | ||||||
|       connect(context()->radarProductView_.get(), |       connect(radarProductView.get(), | ||||||
|               &view::RadarProductView::SweepComputed, |               &view::RadarProductView::SweepComputed, | ||||||
|               this, |               this, | ||||||
|               &OverlayLayer::UpdateSweepTimeNextFrame); |               &OverlayLayer::UpdateSweepTimeNextFrame); | ||||||
|  | @ -103,14 +104,14 @@ void OverlayLayer::Render(const QMapbox::CustomLayerRenderParameters& params) | ||||||
| { | { | ||||||
|    constexpr float fontSize = 16.0f; |    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_ = |       p->sweepTimeString_ = scwx::util::TimeString( | ||||||
|          scwx::util::TimeString(context()->radarProductView_->sweep_time(), |          radarProductView->sweep_time(), std::chrono::current_zone(), false); | ||||||
|                                 std::chrono::current_zone(), |  | ||||||
|                                 false); |  | ||||||
|       p->sweepTimeNeedsUpdate_ = false; |       p->sweepTimeNeedsUpdate_ = false; | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|  | @ -120,9 +121,9 @@ void OverlayLayer::Render(const QMapbox::CustomLayerRenderParameters& params) | ||||||
|                                      static_cast<float>(params.height)); |                                      static_cast<float>(params.height)); | ||||||
| 
 | 
 | ||||||
|    // Active Box
 |    // Active Box
 | ||||||
|    p->activeBoxOuter_->SetVisible(context()->settings_.isActive_); |    p->activeBoxOuter_->SetVisible(settings.isActive_); | ||||||
|    p->activeBoxInner_->SetVisible(context()->settings_.isActive_); |    p->activeBoxInner_->SetVisible(settings.isActive_); | ||||||
|    if (context()->settings_.isActive_) |    if (settings.isActive_) | ||||||
|    { |    { | ||||||
|       p->activeBoxOuter_->SetSize(params.width, params.height); |       p->activeBoxOuter_->SetSize(params.width, params.height); | ||||||
|       p->activeBoxInner_->SetSize(params.width - 2.0f, params.height - 2.0f); |       p->activeBoxInner_->SetSize(params.width - 2.0f, params.height - 2.0f); | ||||||
|  | @ -164,15 +165,16 @@ void OverlayLayer::Deinitialize() | ||||||
| 
 | 
 | ||||||
|    DrawLayer::Deinitialize(); |    DrawLayer::Deinitialize(); | ||||||
| 
 | 
 | ||||||
|    gl::OpenGLFunctions& gl = context()->gl_; |    gl::OpenGLFunctions& gl               = context()->gl(); | ||||||
|  |    auto                 radarProductView = context()->radar_product_view(); | ||||||
| 
 | 
 | ||||||
|    gl.glDeleteTextures(1, &p->texture_); |    gl.glDeleteTextures(1, &p->texture_); | ||||||
| 
 | 
 | ||||||
|    p->texture_ = GL_INVALID_INDEX; |    p->texture_ = GL_INVALID_INDEX; | ||||||
| 
 | 
 | ||||||
|    if (context()->radarProductView_ != nullptr) |    if (radarProductView != nullptr) | ||||||
|    { |    { | ||||||
|       disconnect(context()->radarProductView_.get(), |       disconnect(radarProductView.get(), | ||||||
|                  &view::RadarProductView::SweepComputed, |                  &view::RadarProductView::SweepComputed, | ||||||
|                  this, |                  this, | ||||||
|                  &OverlayLayer::UpdateSweepTimeNextFrame); |                  &OverlayLayer::UpdateSweepTimeNextFrame); | ||||||
|  |  | ||||||
|  | @ -33,7 +33,7 @@ class RadarProductLayerImpl | ||||||
| { | { | ||||||
| public: | public: | ||||||
|    explicit RadarProductLayerImpl(std::shared_ptr<MapContext> context) : |    explicit RadarProductLayerImpl(std::shared_ptr<MapContext> context) : | ||||||
|        shaderProgram_(context->gl_), |        shaderProgram_(nullptr), | ||||||
|        uMVPMatrixLocation_(GL_INVALID_INDEX), |        uMVPMatrixLocation_(GL_INVALID_INDEX), | ||||||
|        uMapScreenCoordLocation_(GL_INVALID_INDEX), |        uMapScreenCoordLocation_(GL_INVALID_INDEX), | ||||||
|        uDataMomentOffsetLocation_(GL_INVALID_INDEX), |        uDataMomentOffsetLocation_(GL_INVALID_INDEX), | ||||||
|  | @ -50,7 +50,8 @@ public: | ||||||
|    } |    } | ||||||
|    ~RadarProductLayerImpl() = default; |    ~RadarProductLayerImpl() = default; | ||||||
| 
 | 
 | ||||||
|    gl::ShaderProgram     shaderProgram_; |    std::shared_ptr<gl::ShaderProgram> shaderProgram_; | ||||||
|  | 
 | ||||||
|    GLint                 uMVPMatrixLocation_; |    GLint                 uMVPMatrixLocation_; | ||||||
|    GLint                 uMapScreenCoordLocation_; |    GLint                 uMapScreenCoordLocation_; | ||||||
|    GLint                 uDataMomentOffsetLocation_; |    GLint                 uDataMomentOffsetLocation_; | ||||||
|  | @ -78,47 +79,48 @@ void RadarProductLayer::Initialize() | ||||||
| { | { | ||||||
|    logger_->debug("Initialize()"); |    logger_->debug("Initialize()"); | ||||||
| 
 | 
 | ||||||
|    gl::OpenGLFunctions& gl = context()->gl_; |    gl::OpenGLFunctions& gl = context()->gl(); | ||||||
| 
 | 
 | ||||||
|    // Load and configure radar shader
 |    // 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_ = |    p->uMVPMatrixLocation_ = | ||||||
|       gl.glGetUniformLocation(p->shaderProgram_.id(), "uMVPMatrix"); |       gl.glGetUniformLocation(p->shaderProgram_->id(), "uMVPMatrix"); | ||||||
|    if (p->uMVPMatrixLocation_ == -1) |    if (p->uMVPMatrixLocation_ == -1) | ||||||
|    { |    { | ||||||
|       logger_->warn("Could not find uMVPMatrix"); |       logger_->warn("Could not find uMVPMatrix"); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    p->uMapScreenCoordLocation_ = |    p->uMapScreenCoordLocation_ = | ||||||
|       gl.glGetUniformLocation(p->shaderProgram_.id(), "uMapScreenCoord"); |       gl.glGetUniformLocation(p->shaderProgram_->id(), "uMapScreenCoord"); | ||||||
|    if (p->uMapScreenCoordLocation_ == -1) |    if (p->uMapScreenCoordLocation_ == -1) | ||||||
|    { |    { | ||||||
|       logger_->warn("Could not find uMapScreenCoord"); |       logger_->warn("Could not find uMapScreenCoord"); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    p->uDataMomentOffsetLocation_ = |    p->uDataMomentOffsetLocation_ = | ||||||
|       gl.glGetUniformLocation(p->shaderProgram_.id(), "uDataMomentOffset"); |       gl.glGetUniformLocation(p->shaderProgram_->id(), "uDataMomentOffset"); | ||||||
|    if (p->uDataMomentOffsetLocation_ == -1) |    if (p->uDataMomentOffsetLocation_ == -1) | ||||||
|    { |    { | ||||||
|       logger_->warn("Could not find uDataMomentOffset"); |       logger_->warn("Could not find uDataMomentOffset"); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    p->uDataMomentScaleLocation_ = |    p->uDataMomentScaleLocation_ = | ||||||
|       gl.glGetUniformLocation(p->shaderProgram_.id(), "uDataMomentScale"); |       gl.glGetUniformLocation(p->shaderProgram_->id(), "uDataMomentScale"); | ||||||
|    if (p->uDataMomentScaleLocation_ == -1) |    if (p->uDataMomentScaleLocation_ == -1) | ||||||
|    { |    { | ||||||
|       logger_->warn("Could not find uDataMomentScale"); |       logger_->warn("Could not find uDataMomentScale"); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    p->uCFPEnabledLocation_ = |    p->uCFPEnabledLocation_ = | ||||||
|       gl.glGetUniformLocation(p->shaderProgram_.id(), "uCFPEnabled"); |       gl.glGetUniformLocation(p->shaderProgram_->id(), "uCFPEnabled"); | ||||||
|    if (p->uCFPEnabledLocation_ == -1) |    if (p->uCFPEnabledLocation_ == -1) | ||||||
|    { |    { | ||||||
|       logger_->warn("Could not find uCFPEnabled"); |       logger_->warn("Could not find uCFPEnabled"); | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
|    p->shaderProgram_.Use(); |    p->shaderProgram_->Use(); | ||||||
| 
 | 
 | ||||||
|    // Generate a vertex array object
 |    // Generate a vertex array object
 | ||||||
|    gl.glGenVertexArrays(1, &p->vao_); |    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_MAG_FILTER, GL_NEAREST); | ||||||
|    gl.glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |    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, |            &view::RadarProductView::ColorTableUpdated, | ||||||
|            this, |            this, | ||||||
|            [=]() { p->colorTableNeedsUpdate_ = true; }); |            [=]() { p->colorTableNeedsUpdate_ = true; }); | ||||||
|    connect(context()->radarProductView_.get(), |    connect(radarProductView.get(), | ||||||
|            &view::RadarProductView::SweepComputed, |            &view::RadarProductView::SweepComputed, | ||||||
|            this, |            this, | ||||||
|            [=]() { p->sweepNeedsUpdate_ = true; }); |            [=]() { p->sweepNeedsUpdate_ = true; }); | ||||||
|  | @ -152,12 +155,12 @@ void RadarProductLayer::UpdateSweep() | ||||||
| { | { | ||||||
|    logger_->debug("UpdateSweep()"); |    logger_->debug("UpdateSweep()"); | ||||||
| 
 | 
 | ||||||
|    gl::OpenGLFunctions& gl = context()->gl_; |    gl::OpenGLFunctions& gl = context()->gl(); | ||||||
| 
 | 
 | ||||||
|    boost::timer::cpu_timer timer; |    boost::timer::cpu_timer timer; | ||||||
| 
 | 
 | ||||||
|    std::shared_ptr<view::RadarProductView> radarProductView = |    std::shared_ptr<view::RadarProductView> radarProductView = | ||||||
|       context()->radarProductView_; |       context()->radar_product_view(); | ||||||
| 
 | 
 | ||||||
|    std::unique_lock sweepLock(radarProductView->sweep_mutex(), |    std::unique_lock sweepLock(radarProductView->sweep_mutex(), | ||||||
|                               std::try_to_lock); |                               std::try_to_lock); | ||||||
|  | @ -253,9 +256,9 @@ void RadarProductLayer::UpdateSweep() | ||||||
| void RadarProductLayer::Render( | void RadarProductLayer::Render( | ||||||
|    const QMapbox::CustomLayerRenderParameters& params) |    const QMapbox::CustomLayerRenderParameters& params) | ||||||
| { | { | ||||||
|    gl::OpenGLFunctions& gl = context()->gl_; |    gl::OpenGLFunctions& gl = context()->gl(); | ||||||
| 
 | 
 | ||||||
|    p->shaderProgram_.Use(); |    p->shaderProgram_->Use(); | ||||||
| 
 | 
 | ||||||
|    if (p->colorTableNeedsUpdate_) |    if (p->colorTableNeedsUpdate_) | ||||||
|    { |    { | ||||||
|  | @ -300,7 +303,7 @@ void RadarProductLayer::Deinitialize() | ||||||
| { | { | ||||||
|    logger_->debug("Deinitialize()"); |    logger_->debug("Deinitialize()"); | ||||||
| 
 | 
 | ||||||
|    gl::OpenGLFunctions& gl = context()->gl_; |    gl::OpenGLFunctions& gl = context()->gl(); | ||||||
| 
 | 
 | ||||||
|    gl.glDeleteVertexArrays(1, &p->vao_); |    gl.glDeleteVertexArrays(1, &p->vao_); | ||||||
|    gl.glDeleteBuffers(3, p->vbo_.data()); |    gl.glDeleteBuffers(3, p->vbo_.data()); | ||||||
|  | @ -321,9 +324,9 @@ void RadarProductLayer::UpdateColorTable() | ||||||
| 
 | 
 | ||||||
|    p->colorTableNeedsUpdate_ = false; |    p->colorTableNeedsUpdate_ = false; | ||||||
| 
 | 
 | ||||||
|    gl::OpenGLFunctions&                    gl = context()->gl_; |    gl::OpenGLFunctions&                    gl = context()->gl(); | ||||||
|    std::shared_ptr<view::RadarProductView> radarProductView = |    std::shared_ptr<view::RadarProductView> radarProductView = | ||||||
|       context()->radarProductView_; |       context()->radar_product_view(); | ||||||
| 
 | 
 | ||||||
|    const std::vector<boost::gil::rgba8_pixel_t>& colorTable = |    const std::vector<boost::gil::rgba8_pixel_t>& colorTable = | ||||||
|       radarProductView->color_table(); |       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 latitude_;  ///< Latitude in degrees
 | ||||||
|    double longitude_; ///< Longitude in degrees
 |    double longitude_; ///< Longitude in degrees
 | ||||||
| 
 | 
 | ||||||
|  |    Coordinate() : Coordinate(0.0, 0.0) {} | ||||||
|  | 
 | ||||||
|    Coordinate(double latitude, double longitude) : |    Coordinate(double latitude, double longitude) : | ||||||
|        latitude_ {latitude}, longitude_ {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) |                  source/scwx/provider/nexrad_data_provider_factory.cpp) | ||||||
| set(HDR_UTIL include/scwx/util/environment.hpp | set(HDR_UTIL include/scwx/util/environment.hpp | ||||||
|              include/scwx/util/float.hpp |              include/scwx/util/float.hpp | ||||||
|  |              include/scwx/util/hash.hpp | ||||||
|              include/scwx/util/iterator.hpp |              include/scwx/util/iterator.hpp | ||||||
|              include/scwx/util/logger.hpp |              include/scwx/util/logger.hpp | ||||||
|              include/scwx/util/map.hpp |              include/scwx/util/map.hpp | ||||||
|  | @ -56,6 +57,7 @@ set(HDR_UTIL include/scwx/util/environment.hpp | ||||||
|              include/scwx/util/vectorbuf.hpp) |              include/scwx/util/vectorbuf.hpp) | ||||||
| set(SRC_UTIL source/scwx/util/environment.cpp | set(SRC_UTIL source/scwx/util/environment.cpp | ||||||
|              source/scwx/util/float.cpp |              source/scwx/util/float.cpp | ||||||
|  |              source/scwx/util/hash.cpp | ||||||
|              source/scwx/util/logger.cpp |              source/scwx/util/logger.cpp | ||||||
|              source/scwx/util/rangebuf.cpp |              source/scwx/util/rangebuf.cpp | ||||||
|              source/scwx/util/streams.cpp |              source/scwx/util/streams.cpp | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat