Skip to content
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
1 change: 1 addition & 0 deletions res/mixxx.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
<file>shaders/filteredsignal.frag</file>
<file>shaders/passthrough.vert</file>
<file>shaders/rgbsignal.frag</file>
<file>shaders/stackedsignal.frag</file>
<file>skins/default.qss</file>
</qresource>
</RCC>
168 changes: 168 additions & 0 deletions res/shaders/stackedsignal.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#version 120

uniform vec2 framebufferSize;
uniform vec4 axesColor;
uniform vec4 lowColor;
uniform vec4 midColor;
uniform vec4 highColor;
uniform vec4 lowFilteredColor;
uniform vec4 midFilteredColor;
uniform vec4 highFilteredColor;

uniform int waveformLength;
uniform int textureSize;
uniform int textureStride;

uniform float allGain;
uniform float lowGain;
uniform float midGain;
uniform float highGain;
uniform float firstVisualIndex;
uniform float lastVisualIndex;

uniform sampler2D waveformDataTexture;

vec4 getWaveformData(float index) {
vec2 uv_data;
uv_data.y = floor(index / float(textureStride));
uv_data.x = floor(index - uv_data.y * float(textureStride));
// Divide again to convert to normalized UV coordinates.
return texture2D(waveformDataTexture, uv_data / float(textureStride));
}

bool nearBorder(float target, float test, float epsilon) {
float dist = target - test;
return (abs(dist) <= epsilon && dist > 0);
}

void main(void) {
vec2 uv = gl_TexCoord[0].st;
vec4 pixel = gl_FragCoord;

float new_currentIndex =
floor(firstVisualIndex +
uv.x * (lastVisualIndex - firstVisualIndex)) *
2;

// Texture coordinates put (0,0) at the bottom left, so show the right
// channel if we are in the bottom half.
if (uv.y < 0.5) {
new_currentIndex += 1;
}

vec4 outputColor = vec4(0.0, 0.0, 0.0, 0.0);
bool showing = false;
bool showingUnscaled = false;
vec4 showingColor = vec4(0.0, 0.0, 0.0, 0.0);
vec4 mixColor = vec4(0.0, 0.0, 0.0, 0.0);
bool mixin = true;
float alpha = 0.75;

// We don't exit early if the waveform data is not valid because we may want
// to show other things (e.g. the axes lines) even when we are on a pixel
// that does not have valid waveform data.
if (new_currentIndex >= 0 && new_currentIndex <= waveformLength - 1) {
// Since the magnitude of the (low, mid, high) vector is used as the
// waveform height, re-scale the maximum height to 1.
const float scaleFactor = 1.0 / sqrt(3.0);

vec4 new_currentDataUnscaled = getWaveformData(new_currentIndex) * allGain;
new_currentDataUnscaled.x *= scaleFactor;
new_currentDataUnscaled.y *= scaleFactor;
new_currentDataUnscaled.z *= scaleFactor;

vec4 new_currentData = new_currentDataUnscaled;
new_currentData.x *= lowGain;
new_currentData.y *= midGain;
new_currentData.z *= highGain;

vec4 new_currentDataTop = vec4(0.0, 0.0, 0.0, 0.0);
new_currentDataTop.x = max(new_currentData.x, new_currentDataUnscaled.x);
new_currentDataTop.y = max(new_currentData.y, new_currentDataUnscaled.y);
new_currentDataTop.z = max(new_currentData.z, new_currentDataUnscaled.z);

// Represents the [-1, 1] distance of this pixel. Subtracting this from
// the signal data in new_currentData, we can tell if a signal band should
// show in this pixel if the component is > 0.
float ourDistance = abs((uv.y - 0.5) * 2.0);

float signalDistance = sqrt(new_currentData.x * new_currentData.x +
new_currentData.y * new_currentData.y +
new_currentData.z * new_currentData.z) *
scaleFactor;

bool drawBorder = false;
showing = true;
if (drawBorder && nearBorder(new_currentDataUnscaled.x, ourDistance, 0.04)) {
showingColor = lowColor;
mixin = false;
alpha = 0.90;
} else if (ourDistance <= new_currentData.x) {
showingColor = lowColor;
} else if (ourDistance <= new_currentDataUnscaled.x) {
showingColor = lowFilteredColor;
alpha = 0.6;
} else if (drawBorder &&
nearBorder(
new_currentDataUnscaled.x + new_currentDataUnscaled.y,
ourDistance,
0.04)) {
showingColor = midColor;
mixin = false;
alpha = 0.90;
} else if (ourDistance <= new_currentDataTop.x + new_currentData.y) {
showingColor = midColor;
} else if (ourDistance <= new_currentDataTop.x + new_currentDataTop.y) {
showingColor = midFilteredColor;
alpha = 0.6;
} else if (drawBorder &&
nearBorder(new_currentDataTop.x + new_currentDataTop.y +
new_currentDataUnscaled.z,
ourDistance,
0.04)) {
showingColor = highColor;
mixin = false;
alpha = 0.90;
} else if (ourDistance <= new_currentDataTop.x + new_currentDataTop.y +
new_currentData.z) {
showingColor = highColor;
} else if (ourDistance <= new_currentDataTop.x + new_currentDataTop.y +
new_currentDataUnscaled.z) {
showingColor = highFilteredColor;
alpha = 0.6;
} else {
showing = false;
}

// Linearly combine the low, mid, and high colors according to the low,
// mid, and high components of the unfiltered signal.
mixColor = lowColor * new_currentDataUnscaled.x +
midColor * new_currentDataUnscaled.y +
highColor * new_currentDataUnscaled.z;

// Re-scale the color by the maximum component.
float showingMax = max(mixColor.x, max(mixColor.y, mixColor.z));
mixColor = mixColor / showingMax;
mixColor.w = 1.0;
}
// Draw the axes color as the lowest item on the screen.
// TODO(owilliams): The "4" in this line makes sure the axis gets
// rendered even when the waveform is fairly short. Really this
// value should be based on the size of the widget.
if (abs(framebufferSize.y / 2 - pixel.y) <= 4) {
outputColor.xyz = mix(outputColor.xyz, axesColor.xyz, axesColor.w);
outputColor.w = 1.0;
}

if (showing) {
outputColor.xyz = mix(outputColor.xyz, showingColor.xyz, alpha);
// we mix in the sum color to smoothen the look and give it the
// general color tone.
if (mixin == true) {
outputColor.xyz = mix(outputColor.xyz, mixColor.xyz, 0.53f);
}
outputColor.w = 1.0;
}

gl_FragColor = outputColor;
}
92 changes: 56 additions & 36 deletions src/waveform/renderers/glslwaveformrenderersignal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@
#include "waveform/waveformwidgetfactory.h"

GLSLWaveformRendererSignal::GLSLWaveformRendererSignal(WaveformWidgetRenderer* waveformWidgetRenderer,
bool rgbShader)
ColorType colorType,
const QString& fragShader)
: WaveformRendererSignalBase(waveformWidgetRenderer),
m_unitQuadListId(-1),
m_textureId(0),
m_textureRenderedWaveformCompletion(0),
m_bDumpPng(false),
m_shadersValid(false),
m_rgbShader(rgbShader) {
m_colorType(colorType),
m_pFragShader(fragShader) {
initializeOpenGLFunctions();
}

Expand Down Expand Up @@ -51,11 +53,9 @@ bool GLSLWaveformRendererSignal::loadShaders() {
<< m_frameShaderProgram->log();
return false;
}
QString fragmentShader = m_rgbShader ?
":/shaders/rgbsignal.frag" :
":/shaders/filteredsignal.frag";

if (!m_frameShaderProgram->addShaderFromSourceFile(
QGLShader::Fragment, fragmentShader)) {
QGLShader::Fragment, m_pFragShader)) {
qDebug() << "GLWaveformRendererSignalShader::loadShaders - "
<< m_frameShaderProgram->log();
return false;
Expand Down Expand Up @@ -339,36 +339,56 @@ void GLSLWaveformRendererSignal::draw(QPainter* painter, QPaintEvent* /*event*/)
static_cast<GLfloat>(m_axesColor_b),
static_cast<GLfloat>(m_axesColor_a)));

QVector4D lowColor = m_rgbShader
? QVector4D(static_cast<GLfloat>(m_rgbLowColor_r),
static_cast<GLfloat>(m_rgbLowColor_g),
static_cast<GLfloat>(m_rgbLowColor_b),
1.0f)
: QVector4D(static_cast<GLfloat>(m_lowColor_r),
static_cast<GLfloat>(m_lowColor_g),
static_cast<GLfloat>(m_lowColor_b),
1.0f);
QVector4D midColor = m_rgbShader
? QVector4D(static_cast<GLfloat>(m_rgbMidColor_r),
static_cast<GLfloat>(m_rgbMidColor_g),
static_cast<GLfloat>(m_rgbMidColor_b),
1.0f)
: QVector4D(static_cast<GLfloat>(m_midColor_r),
static_cast<GLfloat>(m_midColor_g),
static_cast<GLfloat>(m_midColor_b),
1.0f);
QVector4D highColor = m_rgbShader
? QVector4D(static_cast<GLfloat>(m_rgbHighColor_r),
static_cast<GLfloat>(m_rgbHighColor_g),
static_cast<GLfloat>(m_rgbHighColor_b),
1.0f)
: QVector4D(static_cast<GLfloat>(m_highColor_r),
static_cast<GLfloat>(m_highColor_g),
static_cast<GLfloat>(m_highColor_b),
1.0f);
m_frameShaderProgram->setUniformValue("lowColor", lowColor);
m_frameShaderProgram->setUniformValue("midColor", midColor);
m_frameShaderProgram->setUniformValue("highColor", highColor);
if (m_colorType == ColorType::RGBFiltered) {
m_frameShaderProgram->setUniformValue("lowFilteredColor",
QVector4D(static_cast<GLfloat>(m_rgbLowFilteredColor_r),
static_cast<GLfloat>(m_rgbLowFilteredColor_g),
static_cast<GLfloat>(m_rgbLowFilteredColor_b),
1.0));
m_frameShaderProgram->setUniformValue("midFilteredColor",
QVector4D(static_cast<GLfloat>(m_rgbMidFilteredColor_r),
static_cast<GLfloat>(m_rgbMidFilteredColor_g),
static_cast<GLfloat>(m_rgbMidFilteredColor_b),
1.0));
m_frameShaderProgram->setUniformValue("highFilteredColor",
QVector4D(static_cast<GLfloat>(m_rgbHighFilteredColor_r),
static_cast<GLfloat>(m_rgbHighFilteredColor_g),
static_cast<GLfloat>(m_rgbHighFilteredColor_b),
1.0));
}
if (m_colorType == ColorType::RGB || m_colorType == ColorType::RGBFiltered) {
m_frameShaderProgram->setUniformValue("lowColor",
QVector4D(static_cast<GLfloat>(m_rgbLowColor_r),
static_cast<GLfloat>(m_rgbLowColor_g),
static_cast<GLfloat>(m_rgbLowColor_b),
1.0));
m_frameShaderProgram->setUniformValue("midColor",
QVector4D(static_cast<GLfloat>(m_rgbMidColor_r),
static_cast<GLfloat>(m_rgbMidColor_g),
static_cast<GLfloat>(m_rgbMidColor_b),
1.0));
m_frameShaderProgram->setUniformValue("highColor",
QVector4D(static_cast<GLfloat>(m_rgbHighColor_r),
static_cast<GLfloat>(m_rgbHighColor_g),
static_cast<GLfloat>(m_rgbHighColor_b),
1.0));
} else {
m_frameShaderProgram->setUniformValue("lowColor",
QVector4D(static_cast<GLfloat>(m_lowColor_r),
static_cast<GLfloat>(m_lowColor_g),
static_cast<GLfloat>(m_lowColor_b),
1.0));
m_frameShaderProgram->setUniformValue("midColor",
QVector4D(static_cast<GLfloat>(m_midColor_r),
static_cast<GLfloat>(m_midColor_g),
static_cast<GLfloat>(m_midColor_b),
1.0));
m_frameShaderProgram->setUniformValue("highColor",
QVector4D(static_cast<GLfloat>(m_highColor_r),
static_cast<GLfloat>(m_highColor_g),
static_cast<GLfloat>(m_highColor_b),
1.0));
}

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_textureId);
Expand Down
41 changes: 33 additions & 8 deletions src/waveform/renderers/glslwaveformrenderersignal.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,15 @@ class GLSLWaveformRendererSignal: public QObject,
protected QOpenGLFunctions_2_1 {
Q_OBJECT
public:
enum class ColorType {
Filtered,
RGB,
RGBFiltered,
};

GLSLWaveformRendererSignal(WaveformWidgetRenderer* waveformWidgetRenderer,
bool rgbShader);
ColorType colorType,
const QString& fragShader);
~GLSLWaveformRendererSignal() override;

bool onInit() override;
Expand Down Expand Up @@ -51,26 +58,44 @@ class GLSLWaveformRendererSignal: public QObject,

// shaders
bool m_shadersValid;
bool m_rgbShader;
ColorType m_colorType;
const QString m_pFragShader;
std::unique_ptr<QGLShaderProgram> m_frameShaderProgram;
};

class GLSLWaveformRendererFilteredSignal: public GLSLWaveformRendererSignal {
public:
GLSLWaveformRendererFilteredSignal(
WaveformWidgetRenderer* waveformWidgetRenderer) :
GLSLWaveformRendererSignal(waveformWidgetRenderer, false) {
}
GLSLWaveformRendererFilteredSignal(
WaveformWidgetRenderer* waveformWidgetRenderer)
: GLSLWaveformRendererSignal(waveformWidgetRenderer,
ColorType::Filtered,
QLatin1String(":/shaders/filteredsignal.frag")) {
}
~GLSLWaveformRendererFilteredSignal() override {
}
};

class GLSLWaveformRendererRGBSignal : public GLSLWaveformRendererSignal {
public:
GLSLWaveformRendererRGBSignal(
WaveformWidgetRenderer* waveformWidgetRenderer)
: GLSLWaveformRendererSignal(waveformWidgetRenderer, true) {}
WaveformWidgetRenderer* waveformWidgetRenderer)
: GLSLWaveformRendererSignal(waveformWidgetRenderer,
ColorType::RGB,
QLatin1String(":/shaders/rgbsignal.frag")) {
}
~GLSLWaveformRendererRGBSignal() override {}
};

class GLSLWaveformRendererStackedSignal : public GLSLWaveformRendererSignal {
public:
GLSLWaveformRendererStackedSignal(
WaveformWidgetRenderer* waveformWidgetRenderer)
: GLSLWaveformRendererSignal(waveformWidgetRenderer,
ColorType::RGBFiltered,
QLatin1String(":/shaders/stackedsignal.frag")) {
}
~GLSLWaveformRendererStackedSignal() override {
}
};

#endif // QT_NO_OPENGL && !QT_OPENGL_ES_2
15 changes: 15 additions & 0 deletions src/waveform/renderers/waveformrenderersignalbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,21 @@ void WaveformRendererSignalBase::setup(const QDomNode& node,
const QColor& rgbHigh = m_pColors->getRgbHighColor();
rgbHigh.getRgbF(&m_rgbHighColor_r, &m_rgbHighColor_g, &m_rgbHighColor_b);

const QColor& rgbFilteredLow = m_pColors->getRgbLowFilteredColor();
rgbFilteredLow.getRgbF(&m_rgbLowFilteredColor_r,
&m_rgbLowFilteredColor_g,
&m_rgbLowFilteredColor_b);

const QColor& rgbFilteredMid = m_pColors->getRgbMidFilteredColor();
rgbFilteredMid.getRgbF(&m_rgbMidFilteredColor_r,
&m_rgbMidFilteredColor_g,
&m_rgbMidFilteredColor_b);

const QColor& rgbFilteredHigh = m_pColors->getRgbHighFilteredColor();
rgbFilteredHigh.getRgbF(&m_rgbHighFilteredColor_r,
&m_rgbHighFilteredColor_g,
&m_rgbHighFilteredColor_b);

const QColor& axes = m_pColors->getAxesColor();
axes.getRgbF(&m_axesColor_r, &m_axesColor_g, &m_axesColor_b,
&m_axesColor_a);
Expand Down
3 changes: 3 additions & 0 deletions src/waveform/renderers/waveformrenderersignalbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class WaveformRendererSignalBase : public WaveformRendererAbstract {
qreal m_rgbLowColor_r, m_rgbLowColor_g, m_rgbLowColor_b;
qreal m_rgbMidColor_r, m_rgbMidColor_g, m_rgbMidColor_b;
qreal m_rgbHighColor_r, m_rgbHighColor_g, m_rgbHighColor_b;
qreal m_rgbLowFilteredColor_r, m_rgbLowFilteredColor_g, m_rgbLowFilteredColor_b;
qreal m_rgbMidFilteredColor_r, m_rgbMidFilteredColor_g, m_rgbMidFilteredColor_b;
qreal m_rgbHighFilteredColor_r, m_rgbHighFilteredColor_g, m_rgbHighFilteredColor_b;
};

#endif // WAVEFORMRENDERERSIGNALBASE_H
Loading