# HG changeset patch # User Chris Cannam # Date 1468852635 -3600 # Node ID 477521f95a84475ec815e2d6dc5451821d0b07e5 # Parent edbe229860acdbf769d0d7880a5d6ede34e5656e Start introducing translucent renderer diff -r edbe229860ac -r 477521f95a84 layer/Colour3DPlotRenderer.cpp --- a/layer/Colour3DPlotRenderer.cpp Thu Jul 14 17:14:30 2016 +0100 +++ b/layer/Colour3DPlotRenderer.cpp Mon Jul 18 15:37:15 2016 +0100 @@ -22,6 +22,9 @@ #include "LayerGeometryProvider.h" #include "VerticalBinLayer.h" +#include "PaintAssistant.h" + +#include "view/ViewManager.h" // for main model sample rate. Pity #include @@ -62,6 +65,21 @@ Colour3DPlotRenderer::render(LayerGeometryProvider *v, QPainter &paint, QRect rect, bool timeConstrained) { + RenderType renderType = decideRenderType(v); + + if (renderType != DrawBufferPixelResolution) { + // Rendering should be fast in bin-resolution and direct draw + // cases because we are quite well zoomed-in, and the sums are + // easier this way. Calculating boundaries later will be + // fiddly for partial paints otherwise. + timeConstrained = false; + } + + if (renderType == DirectTranslucent) { + renderDirectTranslucent(v, paint, rect); + return { rect, {} }; //!!! this return arg is not very useful + } + sv_frame_t startFrame = v->getStartFrame(); int x0 = v->getXForViewX(rect.x()); @@ -80,16 +98,6 @@ << " x0 " << x0 << " x1 " << x1 << endl; - - bool bufferIsBinResolution = useBinResolutionForDrawBuffer(v); - - if (bufferIsBinResolution) { - // Rendering should be fast in this situation because we are - // quite well zoomed-in, and the sums are easier this - // way. Calculating boundaries later will be fiddly for - // partial paints otherwise. - timeConstrained = false; - } if (m_cache.isValid()) { // some part of the cache is valid @@ -145,7 +153,6 @@ } if (m_cache.isValid()) { - cerr << "cache somewhat valid" << endl; // When rendering only a part of the cache, we need to make // sure that the part we're rendering is adjacent to (or @@ -168,16 +175,17 @@ rightToLeft = isLeftOfValidArea; } - // Note, we always paint the full height. Smaller heights can be - // used when painting direct from cache (outside this function), - // but we want to ensure the cache is coherent without having to - // worry about vertical matching of required and valid areas as - // well as horizontal. That's why this function didn't take any - // y/height parameters. + // Note, we always paint the full height to cache. We want to + // ensure the cache is coherent without having to worry about + // vertical matching of required and valid areas as well as + // horizontal. - if (bufferIsBinResolution && (m_params.binDisplay != BinDisplay::PeakFrequencies)) { + if (renderType == DrawBufferBinResolution) { + renderToCacheBinResolution(v, x0, x1 - x0); - } else { + + } else { // must be DrawBufferPixelResolution, handled DirectTranslucent earlier + renderToCachePixelResolution(v, x0, x1 - x0, rightToLeft, timeConstrained); } @@ -212,14 +220,201 @@ //!!! should we own the Dense3DModelPeakCache here? or should it persist } -bool -Colour3DPlotRenderer::useBinResolutionForDrawBuffer(LayerGeometryProvider *v) const +Colour3DPlotRenderer::RenderType +Colour3DPlotRenderer::decideRenderType(LayerGeometryProvider *v) const { const DenseThreeDimensionalModel *model = m_sources.source; - if (!model) return false; + if (!model || !v || !(v->getViewManager())) { + return DrawBufferPixelResolution; // or anything + } + int binResolution = model->getResolution(); int zoomLevel = v->getZoomLevel(); - return (binResolution > zoomLevel); + sv_samplerate_t modelRate = model->getSampleRate(); + + double rateRatio = v->getViewManager()->getMainModelSampleRate() / modelRate; + double relativeBinResolution = binResolution * rateRatio; + + if (m_params.binDisplay == BinDisplay::PeakFrequencies) { + // no alternative works here + return DrawBufferPixelResolution; + } + + if (!m_params.alwaysOpaque && !m_params.interpolate) { + + // consider translucent option -- only if not smoothing & not + // explicitly requested opaque & sufficiently zoomed-in + + if (model->getHeight() < v->getPaintHeight() && + relativeBinResolution >= 2 * zoomLevel) { + return DirectTranslucent; + } + } + + if (relativeBinResolution > zoomLevel) { + return DrawBufferBinResolution; + } else { + return DrawBufferPixelResolution; + } +} + +void +Colour3DPlotRenderer::renderDirectTranslucent(LayerGeometryProvider *v, + QPainter &paint, + QRect rect) +{ +//!!! QPoint illuminatePos; +// bool illuminate = v->shouldIlluminateLocalFeatures +// (m_sources.verticalBinLayer, illuminatePos); + + const DenseThreeDimensionalModel *model = m_sources.source; + + int x0 = rect.left(); + int x1 = rect.right() + 1; + + int h = v->getPaintHeight(); + + sv_frame_t modelStart = model->getStartFrame(); + sv_frame_t modelEnd = model->getEndFrame(); + int modelResolution = model->getResolution(); + + double rateRatio = + v->getViewManager()->getMainModelSampleRate() / model->getSampleRate(); + + // the s-prefix values are source, i.e. model, column and bin numbers + int sx0 = int((double(v->getFrameForX(x0)) / rateRatio - double(modelStart)) + / modelResolution); + int sx1 = int((double(v->getFrameForX(x1)) / rateRatio - double(modelStart)) + / modelResolution); + + int sh = model->getHeight(); + + const int buflen = 40; + char labelbuf[buflen]; + + int minbin = 0; + int maxbin = sh - 1; //!!! + + int psx = -1; + + vector preparedColumn; + + int modelWidth = model->getWidth(); + + for (int sx = sx0; sx <= sx1; ++sx) { + + if (sx < 0 || sx >= modelWidth) { + continue; + } + + if (sx != psx) { + + //!!! this is in common with renderDrawBuffer - pull it out + + // order: + // get column -> scale -> record extents -> + // normalise -> peak pick -> apply display gain -> + // distribute/interpolate + + ColumnOp::Column fullColumn = model->getColumn(sx); + +// cerr << "x " << x << ", sx " << sx << ", col height " << fullColumn.size() +// << ", minbin " << minbin << ", maxbin " << maxbin << endl; + + ColumnOp::Column column = + vector(fullColumn.data() + minbin, + fullColumn.data() + maxbin + 1); + +//!!! fft scale if (m_colourScale != ColourScaleType::Phase) { +// column = ColumnOp::fftScale(column, m_fftSize); +// } + +//!!! extents recordColumnExtents(column, +// sx, +// overallMag, +// overallMagChanged); + +// if (m_colourScale != ColourScaleType::Phase) { + column = ColumnOp::normalize(column, m_params.normalization); +// } + + if (m_params.binDisplay == BinDisplay::PeakBins) { + column = ColumnOp::peakPick(column); + } + + preparedColumn = column; //!!! unnecessary dup + + psx = sx; + } + + sv_frame_t fx = sx * modelResolution + modelStart; + + if (fx + modelResolution <= modelStart || fx > modelEnd) continue; + + int rx0 = v->getXForFrame(int(double(fx) * rateRatio)); + int rx1 = v->getXForFrame(int(double(fx + modelResolution + 1) * rateRatio)); + + int rw = rx1 - rx0; + if (rw < 1) rw = 1; + + bool showLabel = (rw > 10 && + paint.fontMetrics().width("0.000000") < rw - 3 && + paint.fontMetrics().height() < (h / sh)); + + for (int sy = minbin; sy <= maxbin; ++sy) { + + int ry0 = m_sources.verticalBinLayer->getIYForBin(v, sy); + int ry1 = m_sources.verticalBinLayer->getIYForBin(v, sy + 1); + QRect r(rx0, ry1, rw, ry0 - ry1); + + float value = preparedColumn[sy - minbin]; + QColor colour = m_params.colourScale.getColour(value, 0);//!!! +rotation + + if (rw == 1) { + paint.setPen(colour); + paint.setBrush(Qt::NoBrush); + paint.drawLine(r.x(), r.y(), r.x(), r.y() + r.height() - 1); + continue; + } + + QColor pen(255, 255, 255, 80); + QColor brush(colour); + + if (rw > 3 && r.height() > 3) { + brush.setAlpha(160); + } + + paint.setPen(Qt::NoPen); + paint.setBrush(brush); + +//!!! if (illuminate) { +// if (r.contains(illuminatePos)) { +// paint.setPen(v->getForeground()); +// } +// } + +#ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT +// cerr << "rect " << r.x() << "," << r.y() << " " +// << r.width() << "x" << r.height() << endl; +#endif + + paint.drawRect(r); + + if (showLabel) { + double value = model->getValueAt(sx, sy); + snprintf(labelbuf, buflen, "%06f", value); + QString text(labelbuf); + PaintAssistant::drawVisibleText + (v, + paint, + rx0 + 2, + ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(), + text, + PaintAssistant::OutlinedText); + } + } + } + } void diff -r edbe229860ac -r 477521f95a84 layer/Colour3DPlotRenderer.h --- a/layer/Colour3DPlotRenderer.h Thu Jul 14 17:14:30 2016 +0100 +++ b/layer/Colour3DPlotRenderer.h Mon Jul 18 15:37:15 2016 +0100 @@ -181,13 +181,16 @@ // then repainting from cache to the requested painter. ScrollableImageCache m_cache; - bool useBinResolutionForDrawBuffer(LayerGeometryProvider *) const; - RenderResult render(LayerGeometryProvider *v, QPainter &paint, QRect rect, bool timeConstrained); + + void renderDirectTranslucent(LayerGeometryProvider *v, + QPainter &paint, QRect rect); + void renderToCachePixelResolution(LayerGeometryProvider *v, int x0, int repaintWidth, bool rightToLeft, bool timeConstrained); + void renderToCacheBinResolution(LayerGeometryProvider *v, int x0, int repaintWidth); @@ -207,6 +210,14 @@ void recreateDrawBuffer(int w, int h); void clearDrawBuffer(int w, int h); + + enum RenderType { + DrawBufferPixelResolution, + DrawBufferBinResolution, + DirectTranslucent + }; + + RenderType decideRenderType(LayerGeometryProvider *) const; }; #endif