mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 07:50: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
|
|
@ -13,6 +13,7 @@ set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||||
include(${PROJECT_SOURCE_DIR}/external/cmake-conan/conan.cmake)
|
include(${PROJECT_SOURCE_DIR}/external/cmake-conan/conan.cmake)
|
||||||
|
|
||||||
conan_cmake_configure(REQUIRES boost/1.76.0
|
conan_cmake_configure(REQUIRES boost/1.76.0
|
||||||
|
glm/0.9.9.8
|
||||||
gtest/cci.20210126
|
gtest/cci.20210126
|
||||||
openssl/1.1.1k
|
openssl/1.1.1k
|
||||||
vulkan-loader/1.2.172
|
vulkan-loader/1.2.172
|
||||||
|
|
|
||||||
13
scwx-qt/gl/radar.frag
Normal file
13
scwx-qt/gl/radar.frag
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
// Lower the default precision to medium
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
uniform sampler2D uTexture;
|
||||||
|
|
||||||
|
in vec2 texCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
17
scwx-qt/gl/radar.vert
Normal file
17
scwx-qt/gl/radar.vert
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
layout (location = 0) in vec2 aPosition;
|
||||||
|
layout (location = 1) in vec2 aTexCoord;
|
||||||
|
|
||||||
|
uniform mat4 uMVPMatrix;
|
||||||
|
|
||||||
|
out vec2 texCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Pass the texture coordinate to the fragment shader
|
||||||
|
texCoord = aTexCoord;
|
||||||
|
|
||||||
|
// Transform the position to screen coordinates
|
||||||
|
gl_Position = uMVPMatrix * vec4(aPosition, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,7 @@ set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
find_package(Boost)
|
find_package(Boost)
|
||||||
|
find_package(glm)
|
||||||
|
|
||||||
# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
|
# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
|
||||||
# Check https://doc.qt.io/qt/deployment-android.html for more information.
|
# Check https://doc.qt.io/qt/deployment-android.html for more information.
|
||||||
|
|
@ -50,9 +51,18 @@ set(SRC_MAIN source/scwx/qt/main/main.cpp
|
||||||
source/scwx/qt/main/main_window.cpp)
|
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_MAP source/scwx/qt/map/map_widget.hpp
|
set(HDR_MAP source/scwx/qt/map/map_widget.hpp
|
||||||
|
source/scwx/qt/map/radar_layer.hpp
|
||||||
source/scwx/qt/map/triangle_layer.hpp)
|
source/scwx/qt/map/triangle_layer.hpp)
|
||||||
set(SRC_MAP source/scwx/qt/map/map_widget.cpp
|
set(SRC_MAP source/scwx/qt/map/map_widget.cpp
|
||||||
|
source/scwx/qt/map/radar_layer.cpp
|
||||||
source/scwx/qt/map/triangle_layer.cpp)
|
source/scwx/qt/map/triangle_layer.cpp)
|
||||||
|
set(HDR_UTIL source/scwx/qt/util/shader_program.hpp)
|
||||||
|
set(SRC_UTIL source/scwx/qt/util/shader_program.cpp)
|
||||||
|
|
||||||
|
set(RESOURCE_FILES scwx-qt.qrc)
|
||||||
|
|
||||||
|
set(SHADER_FILES gl/radar.frag
|
||||||
|
gl/radar.vert)
|
||||||
|
|
||||||
set(TS_FILES ts/scwx_en_US.ts)
|
set(TS_FILES ts/scwx_en_US.ts)
|
||||||
|
|
||||||
|
|
@ -61,6 +71,10 @@ set(PROJECT_SOURCES ${HDR_MAIN}
|
||||||
${UI_MAIN}
|
${UI_MAIN}
|
||||||
${HDR_MAP}
|
${HDR_MAP}
|
||||||
${SRC_MAP}
|
${SRC_MAP}
|
||||||
|
${HDR_UTIL}
|
||||||
|
${SRC_UTIL}
|
||||||
|
${SHADER_FILES}
|
||||||
|
${RESOURCE_FILES}
|
||||||
${TS_FILES})
|
${TS_FILES})
|
||||||
|
|
||||||
source_group("Header Files\\main" FILES ${HDR_MAIN})
|
source_group("Header Files\\main" FILES ${HDR_MAIN})
|
||||||
|
|
@ -68,6 +82,10 @@ source_group("Source Files\\main" FILES ${SRC_MAIN})
|
||||||
source_group("UI Files\\main" FILES ${UI_MAIN})
|
source_group("UI Files\\main" FILES ${UI_MAIN})
|
||||||
source_group("Header Files\\map" FILES ${HDR_MAP})
|
source_group("Header Files\\map" FILES ${HDR_MAP})
|
||||||
source_group("Source Files\\map" FILES ${SRC_MAP})
|
source_group("Source Files\\map" FILES ${SRC_MAP})
|
||||||
|
source_group("Header Files\\util" FILES ${HDR_UTIL})
|
||||||
|
source_group("Source Files\\util" FILES ${SRC_UTIL})
|
||||||
|
source_group("OpenGL Shaders" FILES ${SHADER_FILES})
|
||||||
|
source_group("Resources" FILES ${RESOURCE_FILES})
|
||||||
source_group("I18N Files" FILES ${TS_FILES})
|
source_group("I18N Files" FILES ${TS_FILES})
|
||||||
|
|
||||||
qt_add_executable(scwx-qt
|
qt_add_executable(scwx-qt
|
||||||
|
|
@ -82,4 +100,5 @@ target_link_libraries(scwx-qt PRIVATE Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
Qt${QT_VERSION_MAJOR}::OpenGLWidgets
|
Qt${QT_VERSION_MAJOR}::OpenGLWidgets
|
||||||
Boost::log
|
Boost::log
|
||||||
qmapboxgl
|
qmapboxgl
|
||||||
opengl32)
|
opengl32
|
||||||
|
glm::glm)
|
||||||
|
|
|
||||||
6
scwx-qt/scwx-qt.qrc
Normal file
6
scwx-qt/scwx-qt.qrc
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>gl/radar.frag</file>
|
||||||
|
<file>gl/radar.vert</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "map_widget.hpp"
|
#include "map_widget.hpp"
|
||||||
|
|
||||||
#include <scwx/qt/map/triangle_layer.hpp>
|
#include <scwx/qt/map/radar_layer.hpp>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
|
@ -65,7 +65,7 @@ void MapWidget::changeStyle()
|
||||||
void MapWidget::AddLayers()
|
void MapWidget::AddLayers()
|
||||||
{
|
{
|
||||||
// QMapboxGL::addCustomLayer will take ownership of the QScopedPointer
|
// QMapboxGL::addCustomLayer will take ownership of the QScopedPointer
|
||||||
QScopedPointer<QMapbox::CustomLayerHostInterface> pHost(new TriangleLayer());
|
QScopedPointer<QMapbox::CustomLayerHostInterface> pHost(new RadarLayer());
|
||||||
|
|
||||||
QString before = "ferry";
|
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)
|
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