diff --git a/sdrgui/CMakeLists.txt b/sdrgui/CMakeLists.txt index bac9d0052..21e7b11dd 100644 --- a/sdrgui/CMakeLists.txt +++ b/sdrgui/CMakeLists.txt @@ -30,6 +30,7 @@ set(sdrgui_SOURCES gui/externalclockdialog.cpp gui/glscope.cpp gui/glscopegui.cpp + gui/glshadercolors.cpp gui/glshadersimple.cpp gui/glshadertextured.cpp gui/glshadertvarray.cpp @@ -100,6 +101,7 @@ set(sdrgui_HEADERS gui/externalclockdialog.h gui/glscope.h gui/glscopegui.h + gui/glshadercolors.h gui/glshadersimple.h gui/glshadertvarray.h gui/glshadertextured.h diff --git a/sdrgui/gui/glscope.cpp b/sdrgui/gui/glscope.cpp index e8a1123ec..271f897e5 100644 --- a/sdrgui/gui/glscope.cpp +++ b/sdrgui/gui/glscope.cpp @@ -192,6 +192,7 @@ void GLScope::initializeGL() //glDisable(GL_DEPTH_TEST); m_glShaderSimple.initializeGL(); + m_glShaderColors.initializeGL(); m_glShaderLeft1Scale.initializeGL(); m_glShaderBottom1Scale.initializeGL(); m_glShaderLeft2Scale.initializeGL(); @@ -663,7 +664,12 @@ void GLScope::paintGL() mat.setToIdentity(); mat.translate(-1.0f + 2.0f * rectX, 1.0f - 2.0f * rectY); mat.scale(2.0f * rectW, -2.0f * rectH); - m_glShaderSimple.drawPolyline(mat, color, (GLfloat *)&trace[2 * start], end - start); + + if (i == 1) { // Y1 in rainbow color + m_glShaderColors.drawPolyline(mat, (GLfloat *)&trace[2 * start], m_q3Colors.m_array, m_displayTraceIntensity / 100.0f, end - start); + } else { + m_glShaderSimple.drawPolyline(mat, color, (GLfloat *)&trace[2 * start], end - start); + } // Paint trigger level if any if ((traceData.m_triggerDisplayLevel > -1.0f) && (traceData.m_triggerDisplayLevel < 1.0f)) @@ -796,10 +802,21 @@ void GLScope::paintGL() mat.translate(-1.0f + 2.0f * rectX, 1.0f - 2.0f * rectY); mat.scale(2.0f * rectW, -2.0f * rectH); - if (m_displayXYPoints) { - m_glShaderSimple.drawPoints(mat, color, q3, end - start); - } else { - m_glShaderSimple.drawPolyline(mat, color, q3, end - start); + if (i == 1) // Y1 in rainbow color + { + if (m_displayXYPoints) { + m_glShaderColors.drawPoints(mat, q3, m_q3Colors.m_array, m_displayTraceIntensity / 100.0f, end - start); + } else { + m_glShaderColors.drawPolyline(mat, q3, m_q3Colors.m_array, m_displayTraceIntensity / 100.0f, end - start); + } + } + else + { + if (m_displayXYPoints) { + m_glShaderSimple.drawPoints(mat, color, q3, end - start); + } else { + m_glShaderSimple.drawPolyline(mat, color, q3, end - start); + } } } // XY polar display } // trace length > 0 @@ -873,6 +890,8 @@ void GLScope::setTraceSize(int traceSize, bool emitSignal) { m_mutex.lock(); m_traceSize = traceSize; + m_q3Colors.allocate(3*traceSize); + setColorPalette(traceSize, m_q3Colors.m_array); m_configChanged = true; m_mutex.unlock(); update(); @@ -1950,4 +1969,17 @@ void GLScope::drawCircle(float cx, float cy, float r, int num_segments, bool dot vertices[4*ii+3] = y + cy; } } +} + +// https://stackoverflow.com/questions/19452530/how-to-render-a-rainbow-spectrum +void GLScope::setColorPalette(int nbVertices, GLfloat *colors) +{ + for (int v = 0; v < nbVertices; v++) + { + float x = 0.8f*(((float) v)/nbVertices); + QColor c = QColor::fromHslF(x, 0.8f, 0.6f); + colors[3*v] = c.redF(); + colors[3*v+1] = c.greenF(); + colors[3*v+2] = c.blueF(); + } } \ No newline at end of file diff --git a/sdrgui/gui/glscope.h b/sdrgui/gui/glscope.h index ac01c4648..8a25a047f 100644 --- a/sdrgui/gui/glscope.h +++ b/sdrgui/gui/glscope.h @@ -30,6 +30,7 @@ #include "dsp/dsptypes.h" #include "dsp/scopevis.h" #include "gui/scaleengine.h" +#include "gui/glshadercolors.h" #include "gui/glshadersimple.h" #include "gui/glshadertextured.h" #include "export.h" @@ -138,6 +139,7 @@ private: QFont m_channelOverlayFont; GLShaderSimple m_glShaderSimple; + GLShaderColors m_glShaderColors; GLShaderTextured m_glShaderLeft1Scale; GLShaderTextured m_glShaderBottom1Scale; GLShaderTextured m_glShaderLeft2Scale; @@ -151,6 +153,7 @@ private: IncrementalArray m_q3TickX2; IncrementalArray m_q3Radii; //!< Polar grid radii IncrementalArray m_q3Circle; //!< Polar grid unit circle + IncrementalArray m_q3Colors; //!< Colors for trace rainbow palette static const int m_topMargin = 5; static const int m_botMargin = 20; @@ -186,6 +189,7 @@ private: void drawRectGrid2(); void drawPolarGrid2(); static void drawCircle(float cx, float cy, float r, int num_segments, bool dotted, GLfloat *vertices); + static void setColorPalette(int nbVertices, GLfloat *colors); protected slots: void cleanup(); diff --git a/sdrgui/gui/glshadercolors.cpp b/sdrgui/gui/glshadercolors.cpp new file mode 100644 index 000000000..d64b2b69a --- /dev/null +++ b/sdrgui/gui/glshadercolors.cpp @@ -0,0 +1,134 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2019 F4EXB // +// written by Edouard Griffiths // +// // +// 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 "glshadercolors.h" + +GLShaderColors::GLShaderColors() : + m_program(nullptr), + m_matrixLoc(0), + m_alphaLoc(0) +{ } + +GLShaderColors::~GLShaderColors() +{ + cleanup(); +} + +void GLShaderColors::initializeGL() +{ + m_program = new QOpenGLShaderProgram; + + if (!m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, m_vertexShaderSourceSimple)) { + qDebug() << "GLShaderColors::initializeGL: error in vertex shader: " << m_program->log(); + } + + if (!m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, m_fragmentShaderSourceColored)) { + qDebug() << "GLShaderColors::initializeGL: error in fragment shader: " << m_program->log(); + } + + m_program->bindAttributeLocation("vertex", 0); + m_program->bindAttributeLocation("v_color", 1); + + if (!m_program->link()) { + qDebug() << "GLShaderColors::initializeGL: error linking shader: " << m_program->log(); + } + + m_program->bind(); + m_matrixLoc = m_program->uniformLocation("uMatrix"); + m_alphaLoc = m_program->uniformLocation("uAlpha"); + m_program->release(); +} + +void GLShaderColors::drawPoints(const QMatrix4x4& transformMatrix, GLfloat *vertices, GLfloat *colors, GLfloat alpha, int nbVertices) +{ + draw(GL_POINTS, transformMatrix, vertices, colors, alpha, nbVertices); +} + +void GLShaderColors::drawPolyline(const QMatrix4x4& transformMatrix, GLfloat *vertices, GLfloat *colors, GLfloat alpha, int nbVertices) +{ + draw(GL_LINE_STRIP, transformMatrix, vertices, colors, alpha, nbVertices); +} + +void GLShaderColors::drawSegments(const QMatrix4x4& transformMatrix, GLfloat *vertices, GLfloat *colors, GLfloat alpha, int nbVertices) +{ + draw(GL_LINES, transformMatrix, vertices, colors, alpha, nbVertices); +} + +void GLShaderColors::drawContour(const QMatrix4x4& transformMatrix, GLfloat *vertices, GLfloat *colors, GLfloat alpha, int nbVertices) +{ + draw(GL_LINE_LOOP, transformMatrix, vertices, colors, alpha, nbVertices); +} + +void GLShaderColors::drawSurface(const QMatrix4x4& transformMatrix, GLfloat *vertices, GLfloat *colors, GLfloat alpha, int nbVertices) +{ + draw(GL_TRIANGLE_FAN, transformMatrix, vertices, colors, alpha, nbVertices); +} + +void GLShaderColors::draw(unsigned int mode, const QMatrix4x4& transformMatrix, GLfloat *vertices, GLfloat *colors, GLfloat alpha, int nbVertices) +{ + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + m_program->bind(); + m_program->setUniformValue(m_matrixLoc, transformMatrix); + m_program->setUniformValue(m_alphaLoc, alpha); + f->glEnable(GL_BLEND); + f->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + f->glLineWidth(1.0f); + f->glEnableVertexAttribArray(0); // vertex + f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices); + f->glEnableVertexAttribArray(1); // colors + f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, colors); + f->glDrawArrays(mode, 0, nbVertices); + f->glDisableVertexAttribArray(0); + f->glDisableVertexAttribArray(1); + m_program->release(); +} + +void GLShaderColors::cleanup() +{ + if (m_program) + { + delete m_program; + m_program = nullptr; + } +} + +const QString GLShaderColors::m_vertexShaderSourceSimple = QString( + "uniform highp mat4 uMatrix;\n" + "attribute highp vec4 vertex;\n" + "attribute vec3 v_color;\n" + "varying vec3 f_color;\n" + "void main() {\n" + " gl_Position = uMatrix * vertex;\n" + " f_color = v_color;\n" + "}\n" + ); + +const QString GLShaderColors::m_fragmentShaderSourceColored = QString( + "uniform mediump float uAlpha;\n" + "varying vec3 f_color;\n" + "void main() {\n" + " gl_FragColor = vec4(f_color.r, f_color.g, f_color.b, uAlpha);\n" + "}\n" + ); diff --git a/sdrgui/gui/glshadercolors.h b/sdrgui/gui/glshadercolors.h new file mode 100644 index 000000000..67d45cee0 --- /dev/null +++ b/sdrgui/gui/glshadercolors.h @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2019 F4EXB // +// written by Edouard Griffiths // +// // +// Inspired by: // +// https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_03 // // +// // +// 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_GLSHADERCOLORS_H_ +#define INCLUDE_GUI_GLSHADERCOLORS_H_ + +#include +#include + +#include "export.h" + +class QOpenGLShaderProgram; +class QMatrix4x4; +class QVector4D; + +class SDRGUI_API GLShaderColors +{ +public: + GLShaderColors(); + ~GLShaderColors(); + + void initializeGL(); + void drawPoints(const QMatrix4x4& transformMatrix, GLfloat *vertices, GLfloat *colors, GLfloat alpha, int nbVertices); + void drawPolyline(const QMatrix4x4& transformMatrix, GLfloat *vertices, GLfloat *colors, GLfloat alpha, int nbVertices); + void drawSegments(const QMatrix4x4& transformMatrix, GLfloat *vertices, GLfloat *colors, GLfloat alpha, int nbVertices); + void drawContour(const QMatrix4x4& transformMatrix, GLfloat *vertices, GLfloat *colors, GLfloat alpha, int nbVertices); + void drawSurface(const QMatrix4x4& transformMatrix, GLfloat *vertices, GLfloat *colors, GLfloat alpha, int nbVertices); + void cleanup(); + +private: + void draw(unsigned int mode, const QMatrix4x4& transformMatrix, GLfloat *vertices, GLfloat *colors, GLfloat alpha, int nbVertices); + + QOpenGLShaderProgram *m_program; + int m_matrixLoc; + int m_alphaLoc; + static const QString m_vertexShaderSourceSimple; + static const QString m_fragmentShaderSourceColored; +}; + +#endif /* INCLUDE_GUI_GLSHADERCOLORS_H_ */