diff --git a/sdrbase/dsp/spectrumsettings.cpp b/sdrbase/dsp/spectrumsettings.cpp index 9b9116ecf..f7b2ff96f 100644 --- a/sdrbase/dsp/spectrumsettings.cpp +++ b/sdrbase/dsp/spectrumsettings.cpp @@ -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 @@ -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()); @@ -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); diff --git a/sdrbase/dsp/spectrumsettings.h b/sdrbase/dsp/spectrumsettings.h index badb812b2..71d6904e5 100644 --- a/sdrbase/dsp/spectrumsettings.h +++ b/sdrbase/dsp/spectrumsettings.h @@ -61,6 +61,13 @@ public: Shaded }; + enum SpectrumStyle + { + Line, + Fill, + Gradient + }; + int m_fftSize; int m_fftOverlap; FFTWindow::Function m_fftWindow; @@ -97,7 +104,8 @@ public: 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 diff --git a/sdrbase/util/colormap.cpp b/sdrbase/util/colormap.cpp index 9f9c7e7ea..2f4eb61f4 100644 --- a/sdrbase/util/colormap.cpp +++ b/sdrbase/util/colormap.cpp @@ -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] = diff --git a/sdrgui/CMakeLists.txt b/sdrgui/CMakeLists.txt index 7594bb0d3..e0d590907 100644 --- a/sdrgui/CMakeLists.txt +++ b/sdrgui/CMakeLists.txt @@ -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 @@ -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 diff --git a/sdrgui/gui/glshadercolormap.cpp b/sdrgui/gui/glshadercolormap.cpp new file mode 100644 index 000000000..37a02123b --- /dev/null +++ b/sdrgui/gui/glshadercolormap.cpp @@ -0,0 +1,276 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#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_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"); + 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) +{ + 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); + 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->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(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 scale;\n" + "uniform highp sampler1D colorMap;\n" + "varying float y;\n" + "void main() {\n" + " gl_FragColor = texture1D(colorMap, 1.0-(y/scale));\n" + "}\n" + ); + +const QString GLShaderColorMap::m_fragmentShaderSourceColorMap = QString( + "#version 330\n" + "uniform float scale;\n" + "uniform sampler1D colorMap;\n" + "in float y;\n" + "out vec4 fragColor;\n" + "void main() {\n" + " fragColor = texture(colorMap, 1.0-(y/scale));\n" + "}\n" + ); diff --git a/sdrgui/gui/glshadercolormap.h b/sdrgui/gui/glshadercolormap.h new file mode 100644 index 000000000..d1f4b4017 --- /dev/null +++ b/sdrgui/gui/glshadercolormap.h @@ -0,0 +1,68 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_GUI_GLSHADERCOLORMAP_H_ +#define INCLUDE_GUI_GLSHADERCOLORMAP_H_ + +#include +#include +#include +#include +#include + +#include "export.h" + +class QOpenGLShaderProgram; +class QMatrix4x4; +class QVector4D; + +// Shader to fill with a gradient from a color map +// Used for filling the area under the spectrum +class SDRGUI_API GLShaderColorMap : protected QOpenGLFunctions +{ +public: + GLShaderColorMap(); + ~GLShaderColorMap(); + + void initializeGL(int majorVersion, int minorVersion); + void initColorMapTexture(const QString &colorMapName); + void drawSurfaceStrip(const QMatrix4x4& transformMatrix, GLfloat *vertices, int nbVertices, float scale); + void cleanup(); + +private: + void initColorMapTextureMutable(const QString &colorMapName); + void initColorMapTextureImmutable(const QString &colorMapName); + bool useImmutableStorage(); + + QOpenGLShaderProgram *m_program; + QOpenGLVertexArrayObject *m_vao; + QOpenGLBuffer *m_verticesBuf; + QOpenGLTexture *m_colorMapTexture; + unsigned int m_colorMapTextureId; + int m_vertexLoc; + int m_matrixLoc; + int m_colorMapLoc; + int m_scaleLoc; + bool m_useImmutableStorage; + static const QString m_vertexShaderSourceColorMap2; + static const QString m_vertexShaderSourceColorMap; + static const QString m_fragmentShaderSourceColorMap2; + static const QString m_fragmentShaderSourceColorMap; +}; + +#endif /* INCLUDE_GUI_GLSHADERCOLORMAP_H_ */ diff --git a/sdrgui/gui/glshadersimple.cpp b/sdrgui/gui/glshadersimple.cpp index 6905682fd..125ae3081 100644 --- a/sdrgui/gui/glshadersimple.cpp +++ b/sdrgui/gui/glshadersimple.cpp @@ -111,6 +111,11 @@ void GLShaderSimple::drawSurface(const QMatrix4x4& transformMatrix, const QVecto draw(GL_TRIANGLE_FAN, transformMatrix, color, vertices, nbVertices, nbComponents); } +void GLShaderSimple::drawSurfaceStrip(const QMatrix4x4& transformMatrix, const QVector4D& color, GLfloat *vertices, int nbVertices, int nbComponents) +{ + draw(GL_TRIANGLE_STRIP, transformMatrix, color, vertices, nbVertices, nbComponents); +} + void GLShaderSimple::draw(unsigned int mode, const QMatrix4x4& transformMatrix, const QVector4D& color, GLfloat *vertices, int nbVertices, int nbComponents) { QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); diff --git a/sdrgui/gui/glshadersimple.h b/sdrgui/gui/glshadersimple.h index 5e261087d..cac950165 100644 --- a/sdrgui/gui/glshadersimple.h +++ b/sdrgui/gui/glshadersimple.h @@ -42,6 +42,7 @@ public: void drawSegments(const QMatrix4x4& transformMatrix, const QVector4D& color, GLfloat *vertices, int nbVertices, int nbComponents=2); void drawContour(const QMatrix4x4& transformMatrix, const QVector4D& color, GLfloat *vertices, int nbVertices, int nbComponents=2); void drawSurface(const QMatrix4x4& transformMatrix, const QVector4D& color, GLfloat *vertices, int nbVertices, int nbComponents=2); + void drawSurfaceStrip(const QMatrix4x4& transformMatrix, const QVector4D& color, GLfloat *vertices, int nbVertices, int nbComponents=2); void cleanup(); private: diff --git a/sdrgui/gui/glspectrum.cpp b/sdrgui/gui/glspectrum.cpp index 816d57567..216275664 100644 --- a/sdrgui/gui/glspectrum.cpp +++ b/sdrgui/gui/glspectrum.cpp @@ -91,7 +91,7 @@ GLSpectrum::GLSpectrum(QWidget* parent) : m_pan3DSpectrogram(false), m_scaleZ3DSpectrogram(false), m_3DSpectrogramStyle(SpectrumSettings::Outline), - m_3DSpectrogramColorMap("Angel"), + m_colorMapName("Angel"), m_histogramBuffer(nullptr), m_histogram(nullptr), m_displayHistogram(true), @@ -345,16 +345,22 @@ void GLSpectrum::setDisplay3DSpectrogram(bool display) update(); } +void GLSpectrum::setSpectrumStyle(SpectrumSettings::SpectrumStyle style) +{ + m_spectrumStyle = style; + update(); +} + void GLSpectrum::set3DSpectrogramStyle(SpectrumSettings::SpectrogramStyle style) { m_3DSpectrogramStyle = style; update(); } -void GLSpectrum::set3DSpectrogramColorMap(const QString &colorMap) +void GLSpectrum::setColorMapName(const QString &colorMapName) { m_mutex.lock(); - m_3DSpectrogramColorMap = colorMap; + m_colorMapName = colorMapName; m_changesPending = true; m_mutex.unlock(); update(); @@ -824,6 +830,7 @@ void GLSpectrum::initializeGL() m_glShaderFrequencyScale.initializeGL(majorVersion, minorVersion); m_glShaderWaterfall.initializeGL(majorVersion, minorVersion); m_glShaderHistogram.initializeGL(majorVersion, minorVersion); + m_glShaderColorMap.initializeGL(majorVersion, minorVersion); m_glShaderTextOverlay.initializeGL(majorVersion, minorVersion); m_glShaderInfo.initializeGL(majorVersion, minorVersion); m_glShaderSpectrogram.initializeGL(majorVersion, minorVersion); @@ -1264,6 +1271,30 @@ void GLSpectrum::paintGL() // m_referenceLevel - m_powerRange : bottom m_maxHold[i] = ((j - 99) * m_powerRange) / 99.0 + m_referenceLevel; } + // Fill under max hold line + if (m_spectrumStyle != SpectrumSettings::Line) + { + GLfloat *q3 = m_q3ColorMap.m_array; + for (int i = 0; i < m_nbBins; i++) + { + Real v = m_maxHold[i] - m_referenceLevel; + + if (v > 0) { + v = 0; + } else if (v < -m_powerRange) { + v = -m_powerRange; + } + + q3[4*i] = (GLfloat)i; + q3[4*i+1] = -m_powerRange; + q3[4*i+2] = (GLfloat)i; + q3[4*i+3] = v; + } + + QVector4D color(0.5f, 0.0f, 0.0f, (float) m_displayTraceIntensity / 100.0f); + m_glShaderSimple.drawSurfaceStrip(m_glHistogramSpectrumMatrix, color, q3, 2*m_nbBins); + } + // Max hold line { GLfloat *q3 = m_q3FFT.m_array; @@ -1289,10 +1320,40 @@ void GLSpectrum::paintGL() // paint current spectrum line on top of histogram if ((m_displayCurrent) && m_currentSpectrum) { - { - Real bottom = -m_powerRange; - GLfloat *q3 = m_q3FFT.m_array; + Real bottom = -m_powerRange; + GLfloat *q3; + if (m_spectrumStyle != SpectrumSettings::Line) + { + q3 = m_q3ColorMap.m_array; + // Fill under line + for (int i = 0; i < m_nbBins; i++) + { + Real v = m_currentSpectrum[i] - m_referenceLevel; + + if (v > 0) { + v = 0; + } else if (v < bottom) { + v = bottom; + } + + q3[4*i] = (GLfloat)i; + q3[4*i+1] = bottom; + q3[4*i+2] = (GLfloat)i; + q3[4*i+3] = v; + } + + QVector4D color(1.0f, 1.0f, 0.25f, (float) m_displayTraceIntensity / 100.0f); + if (m_spectrumStyle == SpectrumSettings::Gradient) { + m_glShaderColorMap.drawSurfaceStrip(m_glHistogramSpectrumMatrix, q3, 2*m_nbBins, bottom); + } else { + m_glShaderSimple.drawSurfaceStrip(m_glHistogramSpectrumMatrix, color, q3, 2*m_nbBins); + } + } + + { + // Draw line + q3 = m_q3FFT.m_array; for (int i = 0; i < m_nbBins; i++) { Real v = m_currentSpectrum[i] - m_referenceLevel; @@ -1305,9 +1366,15 @@ void GLSpectrum::paintGL() q3[2*i] = (Real) i; q3[2*i+1] = v; + } - QVector4D color(1.0f, 1.0f, 0.25f, (float) m_displayTraceIntensity / 100.0f); + QVector4D color; + if (m_spectrumStyle == SpectrumSettings::Gradient) { + color = QVector4D(m_colorMap[255*3], m_colorMap[255*3+1], m_colorMap[255*3+2], (float) m_displayTraceIntensity / 100.0f); + } else { + color = QVector4D(1.0f, 1.0f, 0.25f, (float) m_displayTraceIntensity / 100.0f); + } m_glShaderSimple.drawPolyline(m_glHistogramSpectrumMatrix, color, q3, m_nbBins); } } @@ -2598,7 +2665,17 @@ void GLSpectrum::applyChanges() } m_3DSpectrogramBufferPos = 0; } - m_glShaderSpectrogram.initColorMapTexture(m_3DSpectrogramColorMap); + m_glShaderSpectrogram.initColorMapTexture(m_colorMapName); + m_glShaderColorMap.initColorMapTexture(m_colorMapName); + m_colorMap = ColorMap::getColorMap(m_colorMapName); + // Why only 240 entries in the palette? + for (int i = 0; i <= 239; i++) + { + ((quint8*)&m_waterfallPalette[i])[0] = (quint8)(m_colorMap[i*3] * 255.0); + ((quint8*)&m_waterfallPalette[i])[1] = (quint8)(m_colorMap[i*3+1] * 255.0); + ((quint8*)&m_waterfallPalette[i])[2] = (quint8)(m_colorMap[i*3+2] * 255.0); + ((quint8*)&m_waterfallPalette[i])[3] = 255; + } if (fftSizeChanged) { @@ -2622,6 +2699,9 @@ void GLSpectrum::applyChanges() memset(m_histogram, 0x00, 100 * m_nbBins); m_q3FFT.allocate(2*m_nbBins); + + m_q3ColorMap.allocate(4*m_nbBins); + std::fill(m_q3ColorMap.m_array, m_q3ColorMap.m_array+4*m_nbBins, 0.0f); } if (fftSizeChanged || windowSizeChanged) diff --git a/sdrgui/gui/glspectrum.h b/sdrgui/gui/glspectrum.h index 2993c73ca..60141499b 100644 --- a/sdrgui/gui/glspectrum.h +++ b/sdrgui/gui/glspectrum.h @@ -33,6 +33,7 @@ #include "gui/scaleengine.h" #include "gui/glshadersimple.h" #include "gui/glshadertextured.h" +#include "gui/glshadercolormap.h" #include "dsp/glspectruminterface.h" #include "gui/glshaderspectrogram.h" #include "dsp/spectrummarkers.h" @@ -41,6 +42,7 @@ #include "export.h" #include "util/incrementalarray.h" #include "util/message.h" +#include "util/colormap.h" class QOpenGLShaderProgram; class MessageQueue; @@ -146,7 +148,8 @@ public: void setDisplayWaterfall(bool display); void setDisplay3DSpectrogram(bool display); void set3DSpectrogramStyle(SpectrumSettings::SpectrogramStyle style); - void set3DSpectrogramColorMap(const QString &colorMap); + void setColorMapName(const QString &colorMapName); + void setSpectrumStyle(SpectrumSettings::SpectrumStyle style); void setSsbSpectrum(bool ssbSpectrum); void setLsbDisplay(bool lsbDisplay); void setInvertedWaterfall(bool inv); @@ -312,7 +315,9 @@ private: QPixmap m_spectrogramTimePixmap; QPixmap m_spectrogramPowerPixmap; SpectrumSettings::SpectrogramStyle m_3DSpectrogramStyle; - QString m_3DSpectrogramColorMap; + QString m_colorMapName; + SpectrumSettings::SpectrumStyle m_spectrumStyle; + const float *m_colorMap; QRgb m_histogramPalette[240]; QImage* m_histogramBuffer; @@ -336,6 +341,7 @@ private: GLShaderTextured m_glShaderFrequencyScale; GLShaderTextured m_glShaderWaterfall; GLShaderTextured m_glShaderHistogram; + GLShaderColorMap m_glShaderColorMap; GLShaderTextured m_glShaderTextOverlay; GLShaderTextured m_glShaderInfo; GLShaderSpectrogram m_glShaderSpectrogram; @@ -351,6 +357,7 @@ private: IncrementalArray m_q3TickFrequency; IncrementalArray m_q3TickPower; IncrementalArray m_q3FFT; + IncrementalArray m_q3ColorMap; MessageQueue *m_messageQueueToGUI; QOpenGLDebugLogger *m_openGLLogger; diff --git a/sdrgui/gui/glspectrumgui.cpp b/sdrgui/gui/glspectrumgui.cpp index 9377acaa6..c6c6c105f 100644 --- a/sdrgui/gui/glspectrumgui.cpp +++ b/sdrgui/gui/glspectrumgui.cpp @@ -71,8 +71,8 @@ GLSpectrumGUI::GLSpectrumGUI(QWidget* parent) : ui->levelRange->setStyleSheet(levelStyle); ui->fftOverlap->setStyleSheet(levelStyle); - ui->spectrogramColorMap->addItems(ColorMap::getColorMapNames()); - ui->spectrogramColorMap->setCurrentText("Angel"); + ui->colorMap->addItems(ColorMap::getColorMapNames()); + ui->colorMap->setCurrentText("Angel"); connect(&m_messageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); @@ -161,8 +161,8 @@ void GLSpectrumGUI::displaySettings() ui->spectrogram->setChecked(m_settings.m_display3DSpectrogram); ui->spectrogramStyle->setCurrentIndex((int) m_settings.m_3DSpectrogramStyle); ui->spectrogramStyle->setVisible(m_settings.m_display3DSpectrogram); - ui->spectrogramColorMap->setCurrentText(m_settings.m_3DSpectrogramColorMap); - ui->spectrogramColorMap->setVisible(m_settings.m_display3DSpectrogram); + ui->colorMap->setCurrentText(m_settings.m_colorMap); + ui->spectrumStyle->setCurrentIndex((int) m_settings.m_spectrumStyle); ui->maxHold->setChecked(m_settings.m_displayMaxHold); ui->current->setChecked(m_settings.m_displayCurrent); ui->histogram->setChecked(m_settings.m_displayHistogram); @@ -246,7 +246,8 @@ void GLSpectrumGUI::applySpectrumSettings() m_glSpectrum->setDisplayWaterfall(m_settings.m_displayWaterfall); m_glSpectrum->setDisplay3DSpectrogram(m_settings.m_display3DSpectrogram); m_glSpectrum->set3DSpectrogramStyle(m_settings.m_3DSpectrogramStyle); - m_glSpectrum->set3DSpectrogramColorMap(m_settings.m_3DSpectrogramColorMap); + m_glSpectrum->setColorMapName(m_settings.m_colorMap); + m_glSpectrum->setSpectrumStyle(m_settings.m_spectrumStyle); m_glSpectrum->setInvertedWaterfall(m_settings.m_invertedWaterfall); m_glSpectrum->setDisplayMaxHold(m_settings.m_displayMaxHold); m_glSpectrum->setDisplayCurrent(m_settings.m_displayCurrent); @@ -463,16 +464,22 @@ void GLSpectrumGUI::on_stroke_valueChanged(int index) applySettings(); } +void GLSpectrumGUI::on_spectrumStyle_currentIndexChanged(int index) +{ + m_settings.m_spectrumStyle = (SpectrumSettings::SpectrumStyle)index; + applySettings(); +} + void GLSpectrumGUI::on_spectrogramStyle_currentIndexChanged(int index) { m_settings.m_3DSpectrogramStyle = (SpectrumSettings::SpectrogramStyle)index; applySettings(); } -void GLSpectrumGUI::on_spectrogramColorMap_currentIndexChanged(int index) +void GLSpectrumGUI::on_colorMap_currentIndexChanged(int index) { (void) index; - m_settings.m_3DSpectrogramColorMap = ui->spectrogramColorMap->currentText(); + m_settings.m_colorMap = ui->colorMap->currentText(); applySettings(); } @@ -498,7 +505,6 @@ void GLSpectrumGUI::on_spectrogram_toggled(bool checked) blockApplySettings(false); } ui->spectrogramStyle->setVisible(m_settings.m_display3DSpectrogram); - ui->spectrogramColorMap->setVisible(m_settings.m_display3DSpectrogram); applySettings(); } diff --git a/sdrgui/gui/glspectrumgui.h b/sdrgui/gui/glspectrumgui.h index 45d497bb0..b978fd401 100644 --- a/sdrgui/gui/glspectrumgui.h +++ b/sdrgui/gui/glspectrumgui.h @@ -96,8 +96,9 @@ private slots: void on_decay_valueChanged(int index); void on_decayDivisor_valueChanged(int index); void on_stroke_valueChanged(int index); + void on_spectrumStyle_currentIndexChanged(int index); void on_spectrogramStyle_currentIndexChanged(int index); - void on_spectrogramColorMap_currentIndexChanged(int index); + void on_colorMap_currentIndexChanged(int index); void on_gridIntensity_valueChanged(int index); void on_traceIntensity_valueChanged(int index); void on_averagingMode_currentIndexChanged(int index); diff --git a/sdrgui/gui/glspectrumgui.ui b/sdrgui/gui/glspectrumgui.ui index 12e355fa8..1fb6d7e7f 100644 --- a/sdrgui/gui/glspectrumgui.ui +++ b/sdrgui/gui/glspectrumgui.ui @@ -723,6 +723,40 @@ + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Spectrum Style + + + + Line + + + + + Fill + + + + + Gradient + + + + @@ -865,7 +899,7 @@ - + 70 @@ -879,7 +913,7 @@ - 3D Spectrogram Color Map + Color Map