mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-11-01 14:00: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,12 +15,10 @@ 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;
|
||||||
|
|
@ -26,11 +28,20 @@ public:
|
||||||
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,15 +63,17 @@ 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;
|
||||||
|
|
@ -77,7 +83,17 @@ 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,12 +14,10 @@ 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;
|
||||||
|
|
@ -29,7 +27,7 @@ public:
|
||||||
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,7 +36,7 @@ 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;
|
||||||
|
|
@ -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,8 +16,6 @@ namespace qt
|
||||||
namespace gl
|
namespace gl
|
||||||
{
|
{
|
||||||
|
|
||||||
class ShaderProgramImpl;
|
|
||||||
|
|
||||||
class ShaderProgram
|
class ShaderProgram
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -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,20 +19,23 @@ 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;
|
||||||
|
|
@ -41,18 +45,20 @@ 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,10 +24,10 @@ 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;
|
||||||
|
|
|
||||||
|
|
@ -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,8 +148,7 @@ 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
|
||||||
|
|
@ -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