mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 09:10:04 +00:00 
			
		
		
		
	Draw a radial. This needs some cleanup, and some MVP matrix tweaking.
This commit is contained in:
		
							parent
							
								
									ace3aeb460
								
							
						
					
					
						commit
						516983ab09
					
				
					 10 changed files with 506 additions and 4 deletions
				
			
		|  | @ -1,6 +1,6 @@ | |||
| #include "map_widget.hpp" | ||||
| 
 | ||||
| #include <scwx/qt/map/triangle_layer.hpp> | ||||
| #include <scwx/qt/map/radar_layer.hpp> | ||||
| 
 | ||||
| #include <QApplication> | ||||
| #include <QColor> | ||||
|  | @ -65,7 +65,7 @@ void MapWidget::changeStyle() | |||
| void MapWidget::AddLayers() | ||||
| { | ||||
|    // QMapboxGL::addCustomLayer will take ownership of the QScopedPointer
 | ||||
|    QScopedPointer<QMapbox::CustomLayerHostInterface> pHost(new TriangleLayer()); | ||||
|    QScopedPointer<QMapbox::CustomLayerHostInterface> pHost(new RadarLayer()); | ||||
| 
 | ||||
|    QString before = "ferry"; | ||||
| 
 | ||||
|  | @ -80,7 +80,7 @@ void MapWidget::AddLayers() | |||
|       } | ||||
|    } | ||||
| 
 | ||||
|    map_->addCustomLayer("triangle", pHost, before); | ||||
|    map_->addCustomLayer("radar", pHost, before); | ||||
| } | ||||
| 
 | ||||
| void MapWidget::keyPressEvent(QKeyEvent* ev) | ||||
|  |  | |||
							
								
								
									
										215
									
								
								scwx-qt/source/scwx/qt/map/radar_layer.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								scwx-qt/source/scwx/qt/map/radar_layer.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,215 @@ | |||
| #define _USE_MATH_DEFINES | ||||
| 
 | ||||
| #include <scwx/qt/map/radar_layer.hpp> | ||||
| #include <scwx/qt/util/shader_program.hpp> | ||||
| 
 | ||||
| #include <QOpenGLFunctions_3_3_Core> | ||||
| 
 | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| #include <glm/glm.hpp> | ||||
| #include <glm/gtc/matrix_transform.hpp> | ||||
| #include <glm/gtc/type_ptr.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "[scwx::qt::map::radar_layer] "; | ||||
| 
 | ||||
| class RadarLayerImpl | ||||
| { | ||||
| public: | ||||
|    explicit RadarLayerImpl() : | ||||
|        gl_(), | ||||
|        shaderProgram_(), | ||||
|        uMVPMatrixLocation_(GL_INVALID_INDEX), | ||||
|        vbo_ {GL_INVALID_INDEX}, | ||||
|        vao_ {GL_INVALID_INDEX}, | ||||
|        numVertices_ {0} | ||||
|    { | ||||
|       gl_.initializeOpenGLFunctions(); | ||||
|    } | ||||
|    ~RadarLayerImpl() = default; | ||||
| 
 | ||||
|    QOpenGLFunctions_3_3_Core gl_; | ||||
| 
 | ||||
|    ShaderProgram shaderProgram_; | ||||
|    GLint         uMVPMatrixLocation_; | ||||
|    GLuint        vbo_; | ||||
|    GLuint        vao_; | ||||
| 
 | ||||
|    GLsizeiptr numVertices_; | ||||
| }; | ||||
| 
 | ||||
| RadarLayer::RadarLayer() : p(std::make_unique<RadarLayerImpl>()) {} | ||||
| RadarLayer::~RadarLayer() = default; | ||||
| 
 | ||||
| RadarLayer::RadarLayer(RadarLayer&&) noexcept = default; | ||||
| RadarLayer& RadarLayer::operator=(RadarLayer&&) noexcept = default; | ||||
| 
 | ||||
| void RadarLayer::initialize() | ||||
| { | ||||
|    BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "initialize()"; | ||||
| 
 | ||||
|    QOpenGLFunctions_3_3_Core& gl = p->gl_; | ||||
| 
 | ||||
|    p->shaderProgram_.Load(":/gl/radar.vert", ":/gl/radar.frag"); | ||||
| 
 | ||||
|    p->uMVPMatrixLocation_ = | ||||
|       gl.glGetUniformLocation(p->shaderProgram_.id(), "uMVPMatrix"); | ||||
|    if (p->uMVPMatrixLocation_ == -1) | ||||
|    { | ||||
|       BOOST_LOG_TRIVIAL(warning) << logPrefix_ << "Could not find uMVPMatrix"; | ||||
|    } | ||||
|    constexpr uint16_t MAX_RADIALS           = 720; | ||||
|    constexpr uint16_t MAX_DATA_MOMENT_GATES = 1840; | ||||
| 
 | ||||
|    static std::array<GLfloat, MAX_RADIALS * MAX_DATA_MOMENT_GATES * 6 * 2> | ||||
|       vertices; | ||||
| 
 | ||||
|    constexpr float angleDelta = 0.5f * static_cast<float>(M_PI) / 180.0f; | ||||
| 
 | ||||
|    float angle1 = 0; | ||||
|    float angle2 = angleDelta; | ||||
| 
 | ||||
|    GLsizeiptr index = 0; | ||||
| 
 | ||||
|    for (uint16_t azimuth = 0; azimuth < 720; ++azimuth) | ||||
|    { | ||||
|       const float dataMomentRange     = 2.125f; | ||||
|       const float dataMomentInterval  = 0.25f; | ||||
|       const float dataMomentIntervalH = dataMomentInterval * 0.5f; | ||||
|       const float snrThreshold        = 2.0f; | ||||
| 
 | ||||
|       const uint16_t numberOfDataMomentGates = 1832; | ||||
| 
 | ||||
|       float range1 = dataMomentRange - dataMomentIntervalH; | ||||
|       float range2 = range1 + dataMomentInterval; | ||||
| 
 | ||||
|       float sinTheta1 = std::sinf(angle1); | ||||
|       float sinTheta2 = std::sinf(angle2); | ||||
|       float cosTheta1 = std::cosf(angle1); | ||||
|       float cosTheta2 = std::cosf(angle2); | ||||
| 
 | ||||
|       for (uint16_t gate = 0; gate < numberOfDataMomentGates; ++gate) | ||||
|       { | ||||
|          float r1SinTheta1 = range1 * sinTheta1; | ||||
|          float r1SinTheta2 = range1 * sinTheta2; | ||||
|          float r2SinTheta1 = range2 * sinTheta1; | ||||
|          float r2SinTheta2 = range2 * sinTheta2; | ||||
| 
 | ||||
|          float r1CosTheta1 = range1 * cosTheta1; | ||||
|          float r1CosTheta2 = range1 * cosTheta2; | ||||
|          float r2CosTheta1 = range2 * cosTheta1; | ||||
|          float r2CosTheta2 = range2 * cosTheta2; | ||||
| 
 | ||||
|          vertices[index++] = r1SinTheta1; | ||||
|          vertices[index++] = r1CosTheta1; | ||||
| 
 | ||||
|          vertices[index++] = r2SinTheta1; | ||||
|          vertices[index++] = r2CosTheta1; | ||||
| 
 | ||||
|          vertices[index++] = r1SinTheta2; | ||||
|          vertices[index++] = r1CosTheta2; | ||||
| 
 | ||||
|          vertices[index++] = r1SinTheta2; | ||||
|          vertices[index++] = r1CosTheta2; | ||||
| 
 | ||||
|          vertices[index++] = r2SinTheta2; | ||||
|          vertices[index++] = r2CosTheta2; | ||||
| 
 | ||||
|          vertices[index++] = r2SinTheta1; | ||||
|          vertices[index++] = r2CosTheta1; | ||||
| 
 | ||||
|          range1 += dataMomentInterval; | ||||
|          range2 += dataMomentInterval; | ||||
|       } | ||||
| 
 | ||||
|       angle1 += angleDelta; | ||||
|       angle2 += angleDelta; | ||||
|       break; | ||||
|    } | ||||
| 
 | ||||
|    // Generate a vertex buffer object
 | ||||
|    gl.glGenBuffers(1, &p->vbo_); | ||||
| 
 | ||||
|    // Generate a vertex array object
 | ||||
|    gl.glGenVertexArrays(1, &p->vao_); | ||||
| 
 | ||||
|    // Bind vertex array object
 | ||||
|    gl.glBindVertexArray(p->vao_); | ||||
| 
 | ||||
|    // Copy vertices array in a buffer for OpenGL to use
 | ||||
|    gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_); | ||||
|    gl.glBufferData(GL_ARRAY_BUFFER, | ||||
|                    index * sizeof(GLfloat), | ||||
|                    vertices.data(), | ||||
|                    GL_STATIC_DRAW); | ||||
| 
 | ||||
|    // Set the vertex attributes pointers
 | ||||
|    gl.glVertexAttribPointer( | ||||
|       0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), static_cast<void*>(0)); | ||||
|    gl.glEnableVertexAttribArray(0); | ||||
| 
 | ||||
|    p->numVertices_ = index; | ||||
| } | ||||
| 
 | ||||
| void RadarLayer::render(const QMapbox::CustomLayerRenderParameters& params) | ||||
| { | ||||
|    QOpenGLFunctions_3_3_Core& gl = p->gl_; | ||||
| 
 | ||||
|    p->shaderProgram_.Use(); | ||||
| 
 | ||||
|    float metersPerPixel = | ||||
|       QMapbox::metersPerPixelAtLatitude(params.latitude, params.zoom); | ||||
| 
 | ||||
|    const float scale  = 1000.0f / metersPerPixel * 2.0f; | ||||
|    const float xScale = scale / params.width; | ||||
|    const float yScale = scale / params.height; | ||||
| 
 | ||||
|    const QMapbox::Coordinate radar(38.6986, -90.6828); | ||||
| 
 | ||||
|    const QMapbox::ProjectedMeters radarMeters = | ||||
|       QMapbox::projectedMetersForCoordinate(radar); | ||||
|    const QMapbox::ProjectedMeters mapMeters = | ||||
|       QMapbox::projectedMetersForCoordinate( | ||||
|          {params.latitude, params.longitude}); | ||||
| 
 | ||||
|    const float yTranslate = (radarMeters.first - mapMeters.first) * 0.001f; | ||||
|    const float xTranslate = (radarMeters.second - mapMeters.second) * 0.001f; | ||||
| 
 | ||||
|    glm::mat4 uMVPMatrix(1.0f); | ||||
|    uMVPMatrix = glm::scale(uMVPMatrix, glm::vec3(xScale, yScale, 1.0f)); | ||||
|    uMVPMatrix = | ||||
|       glm::translate(uMVPMatrix, glm::vec3(xTranslate, yTranslate, 0.0f)); | ||||
|    uMVPMatrix = glm::rotate(uMVPMatrix, | ||||
|                             glm::radians<float>(params.bearing), | ||||
|                             glm::vec3(0.0f, 0.0f, 1.0f)); | ||||
| 
 | ||||
|    gl.glUniformMatrix4fv( | ||||
|       p->uMVPMatrixLocation_, 1, GL_FALSE, glm::value_ptr(uMVPMatrix)); | ||||
| 
 | ||||
|    gl.glBindVertexArray(p->vao_); | ||||
|    gl.glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); | ||||
|    gl.glDrawArrays(GL_TRIANGLES, 0, p->numVertices_); | ||||
|    gl.glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | ||||
| } | ||||
| 
 | ||||
| void RadarLayer::deinitialize() | ||||
| { | ||||
|    QOpenGLFunctions_3_3_Core& gl = p->gl_; | ||||
| 
 | ||||
|    BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "deinitialize()"; | ||||
| 
 | ||||
|    gl.glDeleteVertexArrays(1, &p->vao_); | ||||
|    gl.glDeleteBuffers(1, &p->vbo_); | ||||
| 
 | ||||
|    p->uMVPMatrixLocation_ = GL_INVALID_INDEX; | ||||
|    p->vao_                = GL_INVALID_INDEX; | ||||
|    p->vbo_                = GL_INVALID_INDEX; | ||||
| } | ||||
| 
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										31
									
								
								scwx-qt/source/scwx/qt/map/radar_layer.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								scwx-qt/source/scwx/qt/map/radar_layer.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | |||
| #include <qmapboxgl.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| 
 | ||||
| class RadarLayerImpl; | ||||
| 
 | ||||
| class RadarLayer : public QMapbox::CustomLayerHostInterface | ||||
| { | ||||
| public: | ||||
|    explicit RadarLayer(); | ||||
|    ~RadarLayer(); | ||||
| 
 | ||||
|    RadarLayer(const RadarLayer&) = delete; | ||||
|    RadarLayer& operator=(const RadarLayer&) = delete; | ||||
| 
 | ||||
|    RadarLayer(RadarLayer&&) noexcept; | ||||
|    RadarLayer& operator=(RadarLayer&&) noexcept; | ||||
| 
 | ||||
|    void initialize() override final; | ||||
|    void render(const QMapbox::CustomLayerRenderParameters&) override final; | ||||
|    void deinitialize() override final; | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<RadarLayerImpl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										158
									
								
								scwx-qt/source/scwx/qt/util/shader_program.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								scwx-qt/source/scwx/qt/util/shader_program.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,158 @@ | |||
| #include <scwx/qt/util/shader_program.hpp> | ||||
| 
 | ||||
| #include <QFile> | ||||
| #include <QOpenGLFunctions_3_3_Core> | ||||
| 
 | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "[scwx::qt::util::shader_program] "; | ||||
| 
 | ||||
| class ShaderProgramImpl | ||||
| { | ||||
| public: | ||||
|    explicit ShaderProgramImpl() : gl_(), id_ {GL_INVALID_INDEX} | ||||
|    { | ||||
|       gl_.initializeOpenGLFunctions(); | ||||
| 
 | ||||
|       // Create shader program
 | ||||
|       id_ = gl_.glCreateProgram(); | ||||
|    } | ||||
| 
 | ||||
|    ~ShaderProgramImpl() | ||||
|    { | ||||
|       // Delete shader program
 | ||||
|       gl_.glDeleteProgram(id_); | ||||
|    } | ||||
| 
 | ||||
|    QOpenGLFunctions_3_3_Core gl_; | ||||
| 
 | ||||
|    GLuint id_; | ||||
| }; | ||||
| 
 | ||||
| ShaderProgram::ShaderProgram() : p(std::make_unique<ShaderProgramImpl>()) {} | ||||
| ShaderProgram::~ShaderProgram() = default; | ||||
| 
 | ||||
| ShaderProgram::ShaderProgram(ShaderProgram&&) noexcept = default; | ||||
| ShaderProgram& ShaderProgram::operator=(ShaderProgram&&) noexcept = default; | ||||
| 
 | ||||
| GLuint ShaderProgram::id() const | ||||
| { | ||||
|    return p->id_; | ||||
| } | ||||
| 
 | ||||
| bool ShaderProgram::Load(const std::string& vertexPath, | ||||
|                          const std::string& fragmentPath) | ||||
| { | ||||
|    BOOST_LOG_TRIVIAL(debug) << logPrefix_ << "Load()"; | ||||
| 
 | ||||
|    QOpenGLFunctions_3_3_Core& gl = p->gl_; | ||||
| 
 | ||||
|    GLint glSuccess; | ||||
|    bool  success = true; | ||||
| 
 | ||||
|    QFile vertexFile(vertexPath.c_str()); | ||||
|    QFile fragmentFile(fragmentPath.c_str()); | ||||
| 
 | ||||
|    vertexFile.open(QIODevice::ReadOnly | QIODevice::Text); | ||||
|    fragmentFile.open(QIODevice::ReadOnly | QIODevice::Text); | ||||
| 
 | ||||
|    if (!vertexFile.isOpen()) | ||||
|    { | ||||
|       BOOST_LOG_TRIVIAL(error) | ||||
|          << logPrefix_ << "Could not load vertex shader: " << vertexPath; | ||||
|       return false; | ||||
|    } | ||||
| 
 | ||||
|    if (!fragmentFile.isOpen()) | ||||
|    { | ||||
|       BOOST_LOG_TRIVIAL(error) | ||||
|          << logPrefix_ << "Could not load fragment shader: " << fragmentPath; | ||||
|       return false; | ||||
|    } | ||||
| 
 | ||||
|    QTextStream vertexShaderStream(&vertexFile); | ||||
|    QTextStream fragmentShaderStream(&fragmentFile); | ||||
| 
 | ||||
|    vertexShaderStream.setEncoding(QStringConverter::Utf8); | ||||
|    fragmentShaderStream.setEncoding(QStringConverter::Utf8); | ||||
| 
 | ||||
|    std::string vertexShaderSource = vertexShaderStream.readAll().toStdString(); | ||||
|    std::string fragmentShaderSource = | ||||
|       fragmentShaderStream.readAll().toStdString(); | ||||
| 
 | ||||
|    const char* vertexShaderSourceC   = vertexShaderSource.c_str(); | ||||
|    const char* fragmentShaderSourceC = fragmentShaderSource.c_str(); | ||||
| 
 | ||||
|    // Create a vertex shader
 | ||||
|    GLuint vertexShader = gl.glCreateShader(GL_VERTEX_SHADER); | ||||
| 
 | ||||
|    // Attach the shader source code and compile the shader
 | ||||
|    gl.glShaderSource(vertexShader, 1, &vertexShaderSourceC, NULL); | ||||
|    gl.glCompileShader(vertexShader); | ||||
| 
 | ||||
|    // Check for errors
 | ||||
|    gl.glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &glSuccess); | ||||
|    if (!glSuccess) | ||||
|    { | ||||
|       char infoLog[512]; | ||||
|       gl.glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); | ||||
|       BOOST_LOG_TRIVIAL(error) | ||||
|          << logPrefix_ << "Vertex shader compilation failed"; | ||||
|       success = false; | ||||
|    } | ||||
| 
 | ||||
|    // Create a fragment shader
 | ||||
|    GLuint fragmentShader = gl.glCreateShader(GL_FRAGMENT_SHADER); | ||||
| 
 | ||||
|    // Attach the shader source and compile the shader
 | ||||
|    gl.glShaderSource(fragmentShader, 1, &fragmentShaderSourceC, NULL); | ||||
|    gl.glCompileShader(fragmentShader); | ||||
| 
 | ||||
|    // Check for errors
 | ||||
|    gl.glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &glSuccess); | ||||
|    if (!glSuccess) | ||||
|    { | ||||
|       char infoLog[512]; | ||||
|       gl.glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); | ||||
|       BOOST_LOG_TRIVIAL(error) | ||||
|          << logPrefix_ << "Fragment shader compilation failed: " << infoLog; | ||||
|       success = false; | ||||
|    } | ||||
| 
 | ||||
|    if (success) | ||||
|    { | ||||
|       gl.glAttachShader(p->id_, vertexShader); | ||||
|       gl.glAttachShader(p->id_, fragmentShader); | ||||
|       gl.glLinkProgram(p->id_); | ||||
| 
 | ||||
|       // Check for errors
 | ||||
|       gl.glGetProgramiv(p->id_, GL_LINK_STATUS, &glSuccess); | ||||
|       if (!glSuccess) | ||||
|       { | ||||
|          char infoLog[512]; | ||||
|          gl.glGetProgramInfoLog(p->id_, 512, NULL, infoLog); | ||||
|          BOOST_LOG_TRIVIAL(error) | ||||
|             << logPrefix_ << "Shader program link failed: " << infoLog; | ||||
|          success = false; | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    // Delete shaders
 | ||||
|    gl.glDeleteShader(vertexShader); | ||||
|    gl.glDeleteShader(fragmentShader); | ||||
| 
 | ||||
|    return false; | ||||
| } | ||||
| 
 | ||||
| void ShaderProgram::Use() const | ||||
| { | ||||
|    p->gl_.glUseProgram(p->id_); | ||||
| } | ||||
| 
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
							
								
								
									
										42
									
								
								scwx-qt/source/scwx/qt/util/shader_program.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								scwx-qt/source/scwx/qt/util/shader_program.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #include <Windows.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <string> | ||||
| 
 | ||||
| #include <GL/gl.h> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace qt | ||||
| { | ||||
| 
 | ||||
| class ShaderProgramImpl; | ||||
| 
 | ||||
| class ShaderProgram | ||||
| { | ||||
| public: | ||||
|    explicit ShaderProgram(); | ||||
|    ~ShaderProgram(); | ||||
| 
 | ||||
|    ShaderProgram(const ShaderProgram&) = delete; | ||||
|    ShaderProgram& operator=(const ShaderProgram&) = delete; | ||||
| 
 | ||||
|    ShaderProgram(ShaderProgram&&) noexcept; | ||||
|    ShaderProgram& operator=(ShaderProgram&&) noexcept; | ||||
| 
 | ||||
|    GLuint id() const; | ||||
| 
 | ||||
|    bool Load(const std::string& vertexPath, const std::string& fragmentPath); | ||||
| 
 | ||||
|    void Use() const; | ||||
| 
 | ||||
| private: | ||||
|    std::unique_ptr<ShaderProgramImpl> p; | ||||
| }; | ||||
| 
 | ||||
| } // namespace qt
 | ||||
| } // namespace scwx
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat