Chris@1071: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1071: Chris@1071: /* Chris@1071: Sonic Visualiser Chris@1071: An audio file viewer and annotation editor. Chris@1071: Centre for Digital Music, Queen Mary, University of London. Chris@1071: This file copyright 2006-2016 Chris Cannam and QMUL. Chris@1071: Chris@1071: This program is free software; you can redistribute it and/or Chris@1071: modify it under the terms of the GNU General Public License as Chris@1071: published by the Free Software Foundation; either version 2 of the Chris@1071: License, or (at your option) any later version. See the file Chris@1071: COPYING included with this distribution for more information. Chris@1071: */ Chris@1071: Chris@1071: #ifndef COLOUR_3D_PLOT_RENDERER_H Chris@1071: #define COLOUR_3D_PLOT_RENDERER_H Chris@1071: Chris@1071: #include "ColourScale.h" Chris@1073: #include "ScrollableImageCache.h" Chris@1071: Chris@1071: #include "base/ColumnOp.h" Chris@1073: #include "base/MagnitudeRange.h" Chris@1071: Chris@1073: #include Chris@1073: #include Chris@1073: #include Chris@1073: Chris@1073: class LayerGeometryProvider; Chris@1082: class VerticalBinLayer; Chris@1071: class DenseThreeDimensionalModel; Chris@1071: class Dense3DModelPeakCache; Chris@1071: class FFTModel; Chris@1071: Chris@1071: class Colour3DPlotRenderer Chris@1071: { Chris@1071: public: Chris@1071: enum BinDisplay { Chris@1071: AllBins, Chris@1071: PeakBins, Chris@1071: PeakFrequencies Chris@1071: }; Chris@1071: Chris@1071: enum BinScale { Chris@1071: LinearBinScale, Chris@1071: LogBinScale Chris@1071: }; Chris@1073: Chris@1073: struct Sources { Chris@1082: Sources() : geometryProvider(0), verticalBinLayer(0), Chris@1082: source(0), peaks(0), fft(0) { } Chris@1073: Chris@1073: // These must all outlive this class Chris@1089: LayerGeometryProvider *geometryProvider; // always Chris@1089: const VerticalBinLayer *verticalBinLayer; // always Chris@1089: DenseThreeDimensionalModel *source; // always Chris@1089: Dense3DModelPeakCache *peaks; // optionally Chris@1089: FFTModel *fft; // optionally Chris@1073: }; Chris@1073: Chris@1071: struct Parameters { Chris@1071: Parameters() : Chris@1071: colourScale(ColourScale::Parameters()), Chris@1071: normalization(ColumnOp::NoNormalization), Chris@1073: binDisplay(AllBins), Chris@1073: binScale(LinearBinScale), Chris@1073: alwaysOpaque(false), Chris@1073: interpolate(false), Chris@1073: invertVertical(false) { } Chris@1071: Chris@1071: ColourScale colourScale; // complete ColourScale object by value Chris@1071: ColumnOp::Normalization normalization; Chris@1071: BinDisplay binDisplay; Chris@1071: BinScale binScale; Chris@1071: bool alwaysOpaque; Chris@1071: bool interpolate; Chris@1071: bool invertVertical; Chris@1071: }; Chris@1073: Chris@1073: Colour3DPlotRenderer(Sources sources, Parameters parameters) : Chris@1073: m_sources(sources), Chris@1079: m_params(parameters) Chris@1071: { } Chris@1071: Chris@1073: struct RenderResult { Chris@1073: /** Chris@1073: * The rect that was actually rendered. May be equal to the Chris@1073: * rect that was requested to render, or may be smaller if Chris@1073: * time ran out and the complete flag was not set. Chris@1073: */ Chris@1073: QRect rendered; Chris@1073: Chris@1073: /** Chris@1073: * The magnitude range of the data in the rendered area. Chris@1073: */ Chris@1073: MagnitudeRange range; Chris@1073: }; Chris@1073: Chris@1073: /** Chris@1073: * Render the requested area using the given painter, obtaining Chris@1073: * geometry (e.g. start frame) from the stored Chris@1073: * LayerGeometryProvider. Chris@1073: * Chris@1076: * The whole rect will be rendered and the returned QRect will be Chris@1076: * equal to the passed QRect. (See renderTimeConstrained for an Chris@1076: * alternative that may render only part of the rect in cases Chris@1076: * where obtaining source data is slow and retaining Chris@1076: * responsiveness is important.) Chris@1075: * Chris@1075: * If the model to render from is not ready, this will throw a Chris@1075: * std::logic_error exception. The model must be ready and the Chris@1075: * layer requesting the render must not be dormant in its view, so Chris@1075: * that the LayerGeometryProvider returns valid results; it is the Chris@1075: * caller's responsibility to ensure these. Chris@1073: */ Chris@1076: RenderResult render(QPainter &paint, QRect rect); Chris@1076: Chris@1076: /** Chris@1076: * Render the requested area using the given painter, obtaining Chris@1076: * geometry (e.g. start frame) from the stored Chris@1076: * LayerGeometryProvider. Chris@1076: * Chris@1076: * As much of the rect will be rendered as can be managed given Chris@1076: * internal time constraints (using a RenderTimer object Chris@1076: * internally). The returned QRect (the rendered field in the Chris@1076: * RenderResult struct) will contain the area that was Chris@1076: * rendered. Note that we always render the full requested height, Chris@1076: * it's only width that is time-constrained. Chris@1076: * Chris@1076: * If the model to render from is not ready, this will throw a Chris@1076: * std::logic_error exception. The model must be ready and the Chris@1076: * layer requesting the render must not be dormant in its view, so Chris@1076: * that the LayerGeometryProvider returns valid results; it is the Chris@1076: * caller's responsibility to ensure these. Chris@1076: */ Chris@1076: RenderResult renderTimeConstrained(QPainter &paint, QRect rect); Chris@1073: Chris@1071: private: Chris@1073: Sources m_sources; Chris@1071: Parameters m_params; Chris@1072: Chris@1073: // Draw buffer is the target of each partial repaint. It is always Chris@1073: // at view height (not model height) and is cleared and repainted Chris@1073: // on each fragment render. The only reason it's stored as a data Chris@1073: // member is to avoid reallocation. Chris@1073: QImage m_drawBuffer; Chris@1072: Chris@1073: // Image cache is our persistent record of the visible area. It is Chris@1073: // always the same size as the view (i.e. the paint size reported Chris@1073: // by the LayerGeometryProvider) and is scrolled and partially Chris@1073: // repainted internally as appropriate. A render request is Chris@1073: // carried out by repainting to cache (via the draw buffer) any Chris@1073: // area that is being requested but is not valid in the cache, and Chris@1073: // then repainting from cache to the requested painter. Chris@1073: ScrollableImageCache m_cache; Chris@1073: Chris@1076: RenderResult render(QPainter &paint, QRect rect, bool timeConstrained); Chris@1080: void renderToCache(int x0, int repaintWidth, Chris@1080: bool rightToLeft, bool timeConstrained); Chris@1083: int renderDrawBuffer(int w, int h, Chris@1083: const std::vector &binforx, Chris@1083: const std::vector &binfory, Chris@1083: bool usePeaksCache, Chris@1083: bool rightToLeft, Chris@1083: bool timeConstrained); Chris@1079: void clearDrawBuffer(int w, int h); Chris@1071: }; Chris@1071: Chris@1071: #endif Chris@1071: