-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add qopengl renderers, qopengl rgbwaveformwidget and qopengl wvumeter…
…gl and qopengl wspinny
- Loading branch information
Showing
43 changed files
with
3,866 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/// functions to do fixed point calculations, used by qopengl::WaveformRendererRGB | ||
|
||
// float to fixed point with 8 fractional bits, clipped at 4.0 | ||
inline uint32_t toFrac8(float x) { | ||
return std::min<uint32_t>(static_cast<uint32_t>(std::max(x, 0.f) * 256.f), 4 * 256); | ||
} | ||
|
||
// scaled sqrt lookable table to convert maxAll and maxAllNext as calculated | ||
// in updatePaintNode back to y coordinates | ||
class Frac16SqrtTableSingleton { | ||
public: | ||
static constexpr size_t frac16sqrtTableSize{(3 * 4 * 255 * 256) / 16 + 1}; | ||
|
||
static Frac16SqrtTableSingleton& getInstance() { | ||
static Frac16SqrtTableSingleton instance; | ||
return instance; | ||
} | ||
|
||
inline float get(uint32_t x) const { | ||
// The maximum value of fact16x can be (as uint32_t) 3 * 4 * 255 * 256, | ||
// which would be exessive for the table size. We divide by 16 in order | ||
// to get a more reasonable size. | ||
return m_table[x >> 4]; | ||
} | ||
|
||
private: | ||
float* m_table; | ||
Frac16SqrtTableSingleton() | ||
: m_table(new float[frac16sqrtTableSize]) { | ||
// In the original implementation, the result of sqrt(maxAll) is divided | ||
// by sqrt(3 * 255 * 255); | ||
// We get rid of that division and bake it into this table. | ||
// Additionally, we divide the index for the lookup by 16 (see get(...)), | ||
// so we need to invert that here. | ||
const float f = (3.f * 255.f * 255.f / 16.f); | ||
for (uint32_t i = 0; i < frac16sqrtTableSize; i++) { | ||
m_table[i] = std::sqrt(static_cast<float>(i) / f); | ||
} | ||
} | ||
~Frac16SqrtTableSingleton() { | ||
delete[] m_table; | ||
} | ||
Frac16SqrtTableSingleton(const Frac16SqrtTableSingleton&) = delete; | ||
Frac16SqrtTableSingleton& operator=(const Frac16SqrtTableSingleton&) = delete; | ||
}; | ||
|
||
inline float frac16_sqrt(uint32_t x) { | ||
return Frac16SqrtTableSingleton::getInstance().get(x); | ||
} | ||
|
||
inline uint32_t frac8Pow2ToFrac16(uint32_t x) { | ||
// x is the result of multiplying two fixedpoint values with 8 fraction bits, | ||
// thus x has 16 fraction bits, which is also what we want to return for this | ||
// function. We would naively return (x * x) >> 16, but x * x would overflow | ||
// the 32 bits for values > 1, so we shift before multiplying. | ||
x >>= 8; | ||
return (x * x); | ||
} | ||
|
||
inline uint32_t math_max_u32(uint32_t a, uint32_t b, uint32_t c) { | ||
return std::max(a, std::max(b, c)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#pragma once | ||
|
||
#include <QOpenGLFunctions> | ||
|
||
/// Interface for QOpenGL-based waveform renderers | ||
|
||
namespace qopengl { | ||
class IWaveformRenderer; | ||
} | ||
|
||
class qopengl::IWaveformRenderer : public QOpenGLFunctions { | ||
public: | ||
virtual void initializeGL() { | ||
} | ||
virtual void resizeGL(int w, int h) { | ||
} | ||
virtual void renderGL() = 0; | ||
}; |
73 changes: 73 additions & 0 deletions
73
src/waveform/renderers/qopengl/waveformrenderbackground.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
#include "waveform/renderers/qopengl/waveformrenderbackground.h" | ||
|
||
#include "waveform/renderers/waveformwidgetrenderer.h" | ||
#include "widget/wimagestore.h" | ||
#include "widget/wskincolor.h" | ||
#include "widget/wwidget.h" | ||
|
||
using namespace qopengl; | ||
|
||
WaveformRenderBackground::WaveformRenderBackground( | ||
WaveformWidgetRenderer* waveformWidgetRenderer) | ||
: WaveformRenderer(waveformWidgetRenderer), | ||
m_backgroundColor(0, 0, 0) { | ||
} | ||
|
||
WaveformRenderBackground::~WaveformRenderBackground() { | ||
} | ||
|
||
void WaveformRenderBackground::setup(const QDomNode& node, | ||
const SkinContext& context) { | ||
m_backgroundColor = m_waveformRenderer->getWaveformSignalColors()->getBgColor(); | ||
QString backgroundPixmapPath = context.selectString(node, "BgPixmap"); | ||
if (!backgroundPixmapPath.isEmpty()) { | ||
m_backgroundPixmapPath = context.makeSkinPath(backgroundPixmapPath); | ||
} | ||
setDirty(true); | ||
} | ||
|
||
void WaveformRenderBackground::renderGL() { | ||
if (isDirty()) { | ||
// TODO @m0dB | ||
// generateImage(); | ||
} | ||
|
||
// If there is no background image, just fill the painter with the | ||
// background color. | ||
if (m_backgroundImage.isNull()) { | ||
glClearColor(m_backgroundColor.redF(), | ||
m_backgroundColor.greenF(), | ||
m_backgroundColor.blueF(), | ||
1.f); | ||
glClear(GL_COLOR_BUFFER_BIT); | ||
return; | ||
} | ||
|
||
//painter->drawImage(QPoint(0, 0), m_backgroundImage); | ||
} | ||
|
||
void WaveformRenderBackground::generateImage() { | ||
m_backgroundImage = QImage(); | ||
if (!m_backgroundPixmapPath.isEmpty()) { | ||
QImage backgroundImage = *WImageStore::getImage( | ||
m_backgroundPixmapPath, | ||
scaleFactor()); | ||
|
||
if (!backgroundImage.isNull()) { | ||
if (backgroundImage.width() == m_waveformRenderer->getWidth() && | ||
backgroundImage.height() == m_waveformRenderer->getHeight()) { | ||
m_backgroundImage = backgroundImage.convertToFormat(QImage::Format_RGB32); | ||
} else { | ||
m_backgroundImage = QImage(m_waveformRenderer->getWidth(), | ||
m_waveformRenderer->getHeight(), | ||
QImage::Format_RGB32); | ||
QPainter painter(&m_backgroundImage); | ||
painter.setRenderHint(QPainter::SmoothPixmapTransform); | ||
painter.drawImage(m_backgroundImage.rect(), | ||
backgroundImage, | ||
backgroundImage.rect()); | ||
} | ||
} | ||
} | ||
setDirty(false); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
#pragma once | ||
|
||
#include <QColor> | ||
#include <QImage> | ||
|
||
#include "util/class.h" | ||
#include "waveform/renderers/qopengl/waveformrenderer.h" | ||
|
||
class QDomNode; | ||
class SkinContext; | ||
|
||
namespace qopengl { | ||
class WaveformRenderBackground; | ||
} | ||
class qopengl::WaveformRenderBackground : public qopengl::WaveformRenderer { | ||
public: | ||
explicit WaveformRenderBackground(WaveformWidgetRenderer* waveformWidgetRenderer); | ||
~WaveformRenderBackground() override; | ||
|
||
void setup(const QDomNode& node, const SkinContext& context) override; | ||
void renderGL() override; | ||
|
||
private: | ||
void generateImage(); | ||
|
||
QString m_backgroundPixmapPath; | ||
QColor m_backgroundColor; | ||
QImage m_backgroundImage; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(WaveformRenderBackground); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
#include "waveform/renderers/qopengl/waveformrenderbeat.h" | ||
|
||
#include <QDomNode> | ||
|
||
#include "control/controlobject.h" | ||
#include "skin/legacy/skincontext.h" | ||
#include "track/track.h" | ||
#include "waveform/widgets/qopengl/waveformwidget.h" | ||
#include "widget/wskincolor.h" | ||
#include "widget/wwidget.h" | ||
|
||
using namespace qopengl; | ||
|
||
WaveformRenderBeat::WaveformRenderBeat(WaveformWidgetRenderer* waveformWidget) | ||
: WaveformRenderer(waveformWidget) { | ||
m_beatLineVertices.resize(1024); | ||
} | ||
|
||
WaveformRenderBeat::~WaveformRenderBeat() { | ||
} | ||
|
||
void WaveformRenderBeat::initializeGL() { | ||
QString vertexShaderCode = | ||
"\ | ||
uniform mat4 matrix;\n\ | ||
attribute vec4 position;\n\ | ||
void main()\n\ | ||
{\n\ | ||
gl_Position = matrix * position;\n\ | ||
}\n"; | ||
|
||
QString fragmentShaderCode = | ||
"\ | ||
uniform vec4 color;\n\ | ||
void main()\n\ | ||
{\n\ | ||
gl_FragColor = color;\n\ | ||
}\n"; | ||
|
||
if (!m_shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderCode)) { | ||
return; | ||
} | ||
|
||
if (!m_shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderCode)) { | ||
return; | ||
} | ||
|
||
if (!m_shaderProgram.link()) { | ||
return; | ||
} | ||
|
||
if (!m_shaderProgram.bind()) { | ||
return; | ||
} | ||
} | ||
|
||
void WaveformRenderBeat::setup(const QDomNode& node, const SkinContext& context) { | ||
m_beatColor.setNamedColor(context.selectString(node, "BeatColor")); | ||
m_beatColor = WSkinColor::getCorrectColor(m_beatColor).toRgb(); | ||
} | ||
|
||
void WaveformRenderBeat::renderGL() { | ||
TrackPointer trackInfo = m_waveformRenderer->getTrackInfo(); | ||
|
||
if (!trackInfo) { | ||
return; | ||
} | ||
|
||
mixxx::BeatsPointer trackBeats = trackInfo->getBeats(); | ||
if (!trackBeats) { | ||
return; | ||
} | ||
|
||
int alpha = m_waveformRenderer->getBeatGridAlpha(); | ||
if (alpha == 0) { | ||
return; | ||
} | ||
|
||
glEnable(GL_BLEND); | ||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
|
||
m_beatColor.setAlphaF(alpha / 100.0); | ||
|
||
const int trackSamples = m_waveformRenderer->getTrackSamples(); | ||
if (trackSamples <= 0) { | ||
return; | ||
} | ||
|
||
const double firstDisplayedPosition = | ||
m_waveformRenderer->getFirstDisplayedPosition(); | ||
const double lastDisplayedPosition = | ||
m_waveformRenderer->getLastDisplayedPosition(); | ||
|
||
const auto startPosition = mixxx::audio::FramePos::fromEngineSamplePos( | ||
firstDisplayedPosition * trackSamples); | ||
const auto endPosition = mixxx::audio::FramePos::fromEngineSamplePos( | ||
lastDisplayedPosition * trackSamples); | ||
auto it = trackBeats->iteratorFrom(startPosition); | ||
|
||
// TODO @m0dB use rendererWidth for vertical orientation | ||
// and apply a 90 degrees rotation to the matrix | ||
//const float rendererWidth = m_waveformRenderer->getWidth(); | ||
const float rendererHeight = m_waveformRenderer->getHeight(); | ||
|
||
int vertexCount = 0; | ||
|
||
for (; it != trackBeats->cend() && *it <= endPosition; ++it) { | ||
double beatPosition = it->toEngineSamplePos(); | ||
double xBeatPoint = | ||
m_waveformRenderer->transformSamplePositionInRendererWorld(beatPosition); | ||
|
||
xBeatPoint = qRound(xBeatPoint); | ||
|
||
// If we don't have enough space, double the size. | ||
if (vertexCount >= m_beatLineVertices.size()) { | ||
m_beatLineVertices.resize(m_beatLineVertices.size() * 2); | ||
} | ||
|
||
m_beatLineVertices[vertexCount++] = xBeatPoint; | ||
m_beatLineVertices[vertexCount++] = 0.f; | ||
m_beatLineVertices[vertexCount++] = xBeatPoint + 1; | ||
m_beatLineVertices[vertexCount++] = 0.f; | ||
m_beatLineVertices[vertexCount++] = xBeatPoint; | ||
m_beatLineVertices[vertexCount++] = rendererHeight; | ||
m_beatLineVertices[vertexCount++] = xBeatPoint; | ||
m_beatLineVertices[vertexCount++] = rendererHeight; | ||
m_beatLineVertices[vertexCount++] = xBeatPoint + 1; | ||
m_beatLineVertices[vertexCount++] = rendererHeight; | ||
m_beatLineVertices[vertexCount++] = xBeatPoint + 1; | ||
m_beatLineVertices[vertexCount++] = 0.f; | ||
} | ||
m_shaderProgram.bind(); | ||
|
||
int vertexLocation = m_shaderProgram.attributeLocation("position"); | ||
int matrixLocation = m_shaderProgram.uniformLocation("matrix"); | ||
int colorLocation = m_shaderProgram.uniformLocation("color"); | ||
|
||
QMatrix4x4 matrix; | ||
matrix.ortho(QRectF(0, 0, m_waveformRenderer->getWidth(), m_waveformRenderer->getHeight())); | ||
|
||
m_shaderProgram.enableAttributeArray(vertexLocation); | ||
m_shaderProgram.setAttributeArray( | ||
vertexLocation, GL_FLOAT, m_beatLineVertices.constData(), 2); | ||
|
||
m_shaderProgram.setUniformValue(matrixLocation, matrix); | ||
m_shaderProgram.setUniformValue(colorLocation, m_beatColor); | ||
|
||
glDrawArrays(GL_TRIANGLES, 0, vertexCount / 2); | ||
} |
Oops, something went wrong.