diff options
Diffstat (limited to 'src/waveform/renderers/allshader/waveformrenderersimple.cpp')
-rw-r--r-- | src/waveform/renderers/allshader/waveformrenderersimple.cpp | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/src/waveform/renderers/allshader/waveformrenderersimple.cpp b/src/waveform/renderers/allshader/waveformrenderersimple.cpp new file mode 100644 index 0000000000..83502732ab --- /dev/null +++ b/src/waveform/renderers/allshader/waveformrenderersimple.cpp @@ -0,0 +1,182 @@ +#include "waveform/renderers/allshader/waveformrenderersimple.h" + +#include "track/track.h" +#include "util/math.h" +#include "waveform/renderers/allshader/matrixforwidgetgeometry.h" +#include "waveform/waveform.h" +#include "waveform/waveformwidgetfactory.h" +#include "waveform/widgets/allshader/waveformwidget.h" +#include "widget/wskincolor.h" +#include "widget/wwidget.h" + +using namespace allshader; + +WaveformRendererSimple::WaveformRendererSimple( + WaveformWidgetRenderer* waveformWidget) + : WaveformRendererSignalBase(waveformWidget) { +} + +WaveformRendererSimple::~WaveformRendererSimple() { +} + +void WaveformRendererSimple::onSetup(const QDomNode& node) { + Q_UNUSED(node); +} + +void WaveformRendererSimple::initializeGL() { + WaveformRendererSignalBase::initializeGL(); + m_shader.init(); +} + +void WaveformRendererSimple::paintGL() { + TrackPointer pTrack = m_waveformRenderer->getTrackInfo(); + if (!pTrack) { + return; + } + + ConstWaveformPointer waveform = pTrack->getWaveform(); + if (waveform.isNull()) { + return; + } + + const int dataSize = waveform->getDataSize(); + if (dataSize <= 1) { + return; + } + + const WaveformData* data = waveform->data(); + if (data == nullptr) { + return; + } + + const float devicePixelRatio = m_waveformRenderer->getDevicePixelRatio(); + const int length = static_cast<int>(m_waveformRenderer->getLength() * devicePixelRatio); + + // Not multiplying with devicePixelRatio will also work. In that case, on + // High-DPI-Display the lines will be devicePixelRatio pixels wide (which is + // also what is used for the beat grid and the markers), or in other words + // each block of samples is represented by devicePixelRatio pixels (width). + + const double firstVisualIndex = m_waveformRenderer->getFirstDisplayedPosition() * dataSize; + const double lastVisualIndex = m_waveformRenderer->getLastDisplayedPosition() * dataSize; + + // Represents the # of waveform data points per horizontal pixel. + const double visualIncrementPerPixel = + (lastVisualIndex - firstVisualIndex) / static_cast<double>(length); + + // Per-band gain from the EQ knobs. + float allGain{1.0}; + float bandGain[3] = {1.0, 1.0, 1.0}; + getGains(&allGain, &bandGain[0], &bandGain[1], &bandGain[2]); + + const float breadth = static_cast<float>(m_waveformRenderer->getBreadth()) * devicePixelRatio; + const float halfBreadth = breadth / 2.0f; + + const float heightFactor = allGain * halfBreadth / 255.f; + + // Effective visual index of x + double xVisualSampleIndex = firstVisualIndex; + + const int numVerticesPerLine = 6; // 2 triangles + + int reserved[2]; + + reserved[0] = numVerticesPerLine * length; + m_vertices[0].clear(); + m_vertices[0].reserve(reserved[0]); + + // the horizontal line + reserved[1] = numVerticesPerLine; + m_vertices[1].clear(); + m_vertices[1].reserve(reserved[1]); + + m_vertices[1].addRectangle( + 0.f, + halfBreadth - 0.5f * devicePixelRatio, + static_cast<float>(length), + halfBreadth + 0.5f * devicePixelRatio); + + for (int pos = 0; pos < length; ++pos) { + // Our current pixel (x) corresponds to a number of visual samples + // (visualSamplerPerPixel) in our waveform object. We take the max of + // all the data points on either side of xVisualSampleIndex within a + // window of 'maxSamplingRange' visual samples to measure the maximum + // data point contained by this pixel. + double maxSamplingRange = visualIncrementPerPixel / 2.0; + + // Since xVisualSampleIndex is in visual-samples (e.g. R,L,R,L) we want + // to check +/- maxSamplingRange frames, not samples. To do this, divide + // xVisualSampleIndex by 2. Since frames indices are integers, we round + // to the nearest integer by adding 0.5 before casting to int. + int visualFrameStart = int(xVisualSampleIndex / 2.0 - maxSamplingRange + 0.5); + int visualFrameStop = int(xVisualSampleIndex / 2.0 + maxSamplingRange + 0.5); + const int lastVisualFrame = dataSize / 2 - 1; + + // We now know that some subset of [visualFrameStart, visualFrameStop] + // lies within the valid range of visual frames. Clamp + // visualFrameStart/Stop to within [0, lastVisualFrame]. + visualFrameStart = math_clamp(visualFrameStart, 0, lastVisualFrame); + visualFrameStop = math_clamp(visualFrameStop, 0, lastVisualFrame); + + int visualIndexStart = visualFrameStart * 2; + int visualIndexStop = visualFrameStop * 2; + + visualIndexStart = std::max(visualIndexStart, 0); + visualIndexStop = std::min(visualIndexStop, dataSize); + + // 2 channels + float max[2]{}; + + for (int i = visualIndexStart; i < visualIndexStop; i += 2) { + for (int chn = 0; chn < 2; chn++) { + const WaveformData& waveformData = data[i + chn]; + const float filteredAll = static_cast<float>(waveformData.filtered.all); + + max[chn] = math_max(max[chn], filteredAll); + } + } + + const float fpos = static_cast<float>(pos); + + // lines are thin rectangles + m_vertices[0].addRectangle( + fpos - 0.5f, + halfBreadth - heightFactor * max[0], + fpos + 0.5f, + halfBreadth + heightFactor * max[1]); + + xVisualSampleIndex += visualIncrementPerPixel; + } + + const QMatrix4x4 matrix = matrixForWidgetGeometry(m_waveformRenderer, true); + + const int matrixLocation = m_shader.uniformLocation("matrix"); + const int colorLocation = m_shader.uniformLocation("color"); + const int positionLocation = m_shader.attributeLocation("position"); + + m_shader.bind(); + m_shader.enableAttributeArray(positionLocation); + + m_shader.setUniformValue(matrixLocation, matrix); + + QColor colors[2]; + colors[0].setRgbF(static_cast<float>(m_signalColor_r), + static_cast<float>(m_signalColor_g), + static_cast<float>(m_signalColor_b)); + colors[1].setRgbF(static_cast<float>(m_axesColor_r), + static_cast<float>(m_axesColor_g), + static_cast<float>(m_axesColor_b), + static_cast<float>(m_axesColor_a)); + + for (int i = 0; i < 2; i++) { + DEBUG_ASSERT(reserved[i] == m_vertices[i].size()); + m_shader.setUniformValue(colorLocation, colors[i]); + m_shader.setAttributeArray( + positionLocation, GL_FLOAT, m_vertices[i].constData(), 2); + + glDrawArrays(GL_TRIANGLES, 0, m_vertices[i].size()); + } + + m_shader.disableAttributeArray(positionLocation); + m_shader.release(); +} |