Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spectrum fill/gradient #1299

Merged
merged 3 commits into from
Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions sdrbase/dsp/spectrumsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ void SpectrumSettings::resetToDefaults()
m_useCalibration = false;
m_calibrationInterpMode = CalibInterpLinear;
m_3DSpectrogramStyle = Outline;
m_3DSpectrogramColorMap = "Angel";
m_colorMap = "Angel";
m_spectrumStyle = Line;
}

QByteArray SpectrumSettings::serialize() const
Expand Down Expand Up @@ -104,8 +105,9 @@ QByteArray SpectrumSettings::serialize() const
s.writeS32(30, (int) m_calibrationInterpMode);
s.writeBool(31, m_display3DSpectrogram);
s.writeS32(32, (int) m_3DSpectrogramStyle);
s.writeString(33, m_3DSpectrogramColorMap);
s.writeS32(100, m_histogramMarkers.size());
s.writeString(33, m_colorMap);
s.writeS32(34, (int) m_spectrumStyle);
s.writeS32(100, m_histogramMarkers.size());

for (int i = 0; i < m_histogramMarkers.size(); i++) {
s.writeBlob(101+i, m_histogramMarkers[i].serialize());
Expand Down Expand Up @@ -204,7 +206,8 @@ bool SpectrumSettings::deserialize(const QByteArray& data)
m_calibrationInterpMode = (CalibrationInterpolationMode) tmp;
d.readBool(31, &m_display3DSpectrogram, false);
d.readS32(32, (int*)&m_3DSpectrogramStyle, (int)Outline);
d.readString(33, &m_3DSpectrogramColorMap, "Angel");
d.readString(33, &m_colorMap, "Angel");
d.readS32(34, (int*)&m_spectrumStyle, (int)Line);

int histogramMarkersSize;
d.readS32(100, &histogramMarkersSize, 0);
Expand Down
10 changes: 9 additions & 1 deletion sdrbase/dsp/spectrumsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ class SDRBASE_API SpectrumSettings : public Serializable
Shaded
};

enum SpectrumStyle
{
Line,
Fill,
Gradient
};

int m_fftSize;
int m_fftOverlap;
FFTWindow::Function m_fftWindow;
Expand Down Expand Up @@ -97,7 +104,8 @@ class SDRBASE_API SpectrumSettings : public Serializable
bool m_useCalibration;
CalibrationInterpolationMode m_calibrationInterpMode; //!< How is power interpolated between calibration points
SpectrogramStyle m_3DSpectrogramStyle;
QString m_3DSpectrogramColorMap;
QString m_colorMap;
SpectrumStyle m_spectrumStyle;
static const int m_log2FFTSizeMin = 6; // 64
static const int m_log2FFTSizeMax = 15; // 32k

Expand Down
1 change: 1 addition & 0 deletions sdrbase/util/colormap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ const float ColorMap::m_angel[m_size] =
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
1.0, 1.0, 1.0,
};

const float ColorMap::m_jet[m_size] =
Expand Down
2 changes: 2 additions & 0 deletions sdrgui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ set(sdrgui_SOURCES
gui/glscope.cpp
gui/glscopegui.cpp
gui/glshadercolors.cpp
gui/glshadercolormap.cpp
gui/glshadersimple.cpp
gui/glshaderspectrogram.cpp
gui/glshadertextured.cpp
Expand Down Expand Up @@ -145,6 +146,7 @@ set(sdrgui_HEADERS
gui/glscope.h
gui/glscopegui.h
gui/glshadercolors.h
gui/glshadercolormap.h
gui/glshadersimple.h
gui/glshaderspectrogram.h
gui/glshadertvarray.h
Expand Down
283 changes: 283 additions & 0 deletions sdrgui/gui/glshadercolormap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// Copyright (C) 2022 Jon Beniston, M7RCE //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////

#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>
#include <QOpenGLContext>
#include <QImage>
#include <QMatrix4x4>
#include <QVector4D>
#include <QDebug>

#include "gui/glshadercolormap.h"
#include "util/colormap.h"

GLShaderColorMap::GLShaderColorMap() :
m_program(nullptr),
m_vao(nullptr),
m_verticesBuf(nullptr),
m_colorMapTexture(nullptr),
m_colorMapTextureId(0),
m_vertexLoc(0),
m_matrixLoc(0),
m_colorMapLoc(0),
m_scaleLoc(0),
m_alphaLoc(0),
m_useImmutableStorage(true)
{ }

GLShaderColorMap::~GLShaderColorMap()
{
cleanup();
}

void GLShaderColorMap::initializeGL(int majorVersion, int minorVersion)
{
initializeOpenGLFunctions();
m_useImmutableStorage = useImmutableStorage();
qDebug() << "GLShaderColorMap::initializeGL: m_useImmutableStorage: " << m_useImmutableStorage;

m_program = new QOpenGLShaderProgram;
if ((majorVersion > 3) || ((majorVersion == 3) && (minorVersion >= 3)))
{
if (!m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, m_vertexShaderSourceColorMap)) {
qDebug() << "GLShaderColorMap::initializeGL: error in vertex shader: " << m_program->log();
}
if (!m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, m_fragmentShaderSourceColorMap)) {
qDebug() << "GLShaderColorMap::initializeGL: error in fragment shader: " << m_program->log();
}

m_vao = new QOpenGLVertexArrayObject();
m_vao->create();
m_vao->bind();
}
else
{
if (!m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, m_vertexShaderSourceColorMap2)) {
qDebug() << "GLShaderColorMap::initializeGL: error in vertex shader: " << m_program->log();
}
if (!m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, m_fragmentShaderSourceColorMap2)) {
qDebug() << "GLShaderColorMap::initializeGL: error in fragment shader: " << m_program->log();
}
}

m_program->bindAttributeLocation("vertex", 0);

if (!m_program->link()) {
qDebug() << "GLShaderColorMap::initializeGL: error linking shader: " << m_program->log();
}

m_program->bind();
m_vertexLoc = m_program->attributeLocation("vertex");
m_matrixLoc = m_program->uniformLocation("uMatrix");
m_colorMapLoc = m_program->uniformLocation("colorMap");
m_scaleLoc = m_program->uniformLocation("scale");
m_alphaLoc = m_program->uniformLocation("alpha");
if (m_vao)
{
m_verticesBuf = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
m_verticesBuf->setUsagePattern(QOpenGLBuffer::DynamicDraw);
m_verticesBuf->create();
m_vao->release();
}
m_program->release();
}

void GLShaderColorMap::initColorMapTexture(const QString &colorMapName)
{
if (m_useImmutableStorage) {
initColorMapTextureImmutable(colorMapName);
} else {
initColorMapTextureMutable(colorMapName);
}
}

void GLShaderColorMap::initColorMapTextureImmutable(const QString &colorMapName)
{
if (!m_colorMapTexture)
{
m_colorMapTexture = new QOpenGLTexture(QOpenGLTexture::Target1D);
m_colorMapTexture->setFormat(QOpenGLTexture::RGB32F);
m_colorMapTexture->setSize(256);
m_colorMapTexture->allocateStorage();
m_colorMapTexture->setMinificationFilter(QOpenGLTexture::Linear);
m_colorMapTexture->setMagnificationFilter(QOpenGLTexture::Linear);
m_colorMapTexture->setWrapMode(QOpenGLTexture::ClampToEdge);
}

GLfloat *colorMap = (GLfloat *)ColorMap::getColorMap(colorMapName);
if (colorMap) {
m_colorMapTexture->setData(QOpenGLTexture::RGB, QOpenGLTexture::Float32, colorMap);
} else {
qDebug() << "GLShaderColorMap::initColorMapTextureImmutable: colorMap " << colorMapName << " not supported";
}
}

void GLShaderColorMap::initColorMapTextureMutable(const QString &colorMapName)
{
if (m_colorMapTextureId)
{
glDeleteTextures(1, &m_colorMapTextureId);
m_colorMapTextureId = 0;
}

glGenTextures(1, &m_colorMapTextureId);
glBindTexture(GL_TEXTURE_1D, m_colorMapTextureId);
GLfloat *colorMap = (GLfloat *)ColorMap::getColorMap(colorMapName);
if (colorMap) {
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 256, 0, GL_RGB, GL_FLOAT, colorMap);
} else {
qDebug() << "GLShaderColorMap::initColorMapTextureMutable: colorMap " << colorMapName << " not supported";
}

glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, QOpenGLTexture::Repeat);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, QOpenGLTexture::Repeat);
}

void GLShaderColorMap::drawSurfaceStrip(const QMatrix4x4& transformMatrix, GLfloat *vertices, int nbVertices, float scale, float alpha)
{
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
m_program->bind();
m_program->setUniformValue(m_matrixLoc, transformMatrix);
m_colorMapTexture->bind();
m_program->setUniformValue(m_colorMapLoc, 0); // Texture unit 0 for color map
m_program->setUniformValue(m_scaleLoc, scale);
m_program->setUniformValue(m_alphaLoc, alpha);
if (m_vao)
{
m_vao->bind();

m_verticesBuf->bind();
m_verticesBuf->allocate(vertices, nbVertices * 2 * sizeof(GL_FLOAT));
m_program->enableAttributeArray(m_vertexLoc);
m_program->setAttributeBuffer(m_vertexLoc, GL_FLOAT, 0, 2);
}
else
{
f->glEnableVertexAttribArray(m_vertexLoc);
f->glVertexAttribPointer(m_vertexLoc, 2, GL_FLOAT, GL_FALSE, 0, vertices);
}

f->glEnable(GL_BLEND);
f->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
f->glDrawArrays(GL_TRIANGLE_STRIP, 0, nbVertices);

if (m_vao)
{
m_vao->release();
}
else
{
f->glDisableVertexAttribArray(m_vertexLoc);
}
m_program->release();
}

void GLShaderColorMap::cleanup()
{
delete m_program;
m_program = nullptr;
delete m_vao;
m_vao = nullptr;
delete m_verticesBuf;
m_verticesBuf = nullptr;
delete m_colorMapTexture;
m_colorMapTexture = nullptr;

if (!QOpenGLContext::currentContext()) {
return;
}

if (m_colorMapTextureId)
{
glDeleteTextures(1, &m_colorMapTextureId);
m_colorMapTextureId = 0;
}
}

bool GLShaderColorMap::useImmutableStorage()
{
QOpenGLContext* ctx = QOpenGLContext::currentContext();
QSurfaceFormat sf = ctx->format();

if (sf.version() >= qMakePair(4, 2)
|| ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_storage"))
|| ctx->hasExtension(QByteArrayLiteral("GL_EXT_texture_storage")))
{
void (QOPENGLF_APIENTRYP glTexStorage2D)(
GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height);
glTexStorage2D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(
GLenum, GLsizei, GLenum, GLsizei, GLsizei)>(ctx->getProcAddress("glTexStorage2D"));
int data = 0;
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data);
GLenum err = glGetError();
glDeleteTextures(1, &textureId);
return err == GL_NO_ERROR;
}

return false;
}

const QString GLShaderColorMap::m_vertexShaderSourceColorMap2 = QString(
"uniform highp mat4 uMatrix;\n"
"attribute highp vec4 vertex;\n"
"varying float y;\n"
"void main() {\n"
" gl_Position = uMatrix * vertex;\n"
" y = vertex.y;\n"
"}\n"
);

const QString GLShaderColorMap::m_vertexShaderSourceColorMap = QString(
"#version 330\n"
"uniform highp mat4 uMatrix;\n"
"in highp vec4 vertex;\n"
"out float y;\n"
"void main() {\n"
" gl_Position = uMatrix * vertex;\n"
" y = vertex.y;\n"
"}\n"
);

const QString GLShaderColorMap::m_fragmentShaderSourceColorMap2 = QString(
"uniform float alpha;\n"
"uniform float scale;\n"
"uniform highp sampler1D colorMap;\n"
"varying float y;\n"
"void main() {\n"
" gl_FragColor = vec4(texture1D(colorMap, 1.0-(y/scale)).rgb, alpha);\n"
"}\n"
);

const QString GLShaderColorMap::m_fragmentShaderSourceColorMap = QString(
"#version 330\n"
"uniform float alpha;\n"
"uniform float scale;\n"
"uniform sampler1D colorMap;\n"
"in float y;\n"
"out vec4 fragColor;\n"
"void main() {\n"
" fragColor = vec4(texture(colorMap, 1.0-(y/scale)).rgb, alpha);\n"
"}\n"
);
Loading