Mercurial > hg > svgui
comparison layer/Colour3DPlotRenderer.h @ 1216:dc2af6616c83
Merge from branch 3.0-integration
author | Chris Cannam |
---|---|
date | Fri, 13 Jan 2017 10:29:50 +0000 |
parents | 34df6ff25472 |
children | eaab8bab3522 |
comparison
equal
deleted
inserted
replaced
1048:e8102ff5573b | 1216:dc2af6616c83 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 This file copyright 2006-2016 Chris Cannam and QMUL. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #ifndef COLOUR_3D_PLOT_RENDERER_H | |
17 #define COLOUR_3D_PLOT_RENDERER_H | |
18 | |
19 #include "ColourScale.h" | |
20 #include "ScrollableImageCache.h" | |
21 #include "ScrollableMagRangeCache.h" | |
22 | |
23 #include "base/ColumnOp.h" | |
24 #include "base/MagnitudeRange.h" | |
25 | |
26 #include <QRect> | |
27 #include <QPainter> | |
28 #include <QImage> | |
29 | |
30 class LayerGeometryProvider; | |
31 class VerticalBinLayer; | |
32 class DenseThreeDimensionalModel; | |
33 class Dense3DModelPeakCache; | |
34 class FFTModel; | |
35 | |
36 enum class BinDisplay { | |
37 AllBins, | |
38 PeakBins, | |
39 PeakFrequencies | |
40 }; | |
41 | |
42 enum class BinScale { | |
43 Linear, | |
44 Log | |
45 }; | |
46 | |
47 class Colour3DPlotRenderer | |
48 { | |
49 public: | |
50 struct Sources { | |
51 Sources() : verticalBinLayer(0), source(0), fft(0) { } | |
52 | |
53 // These must all outlive this class | |
54 const VerticalBinLayer *verticalBinLayer; // always | |
55 const DenseThreeDimensionalModel *source; // always | |
56 const FFTModel *fft; // optionally | |
57 std::vector<Dense3DModelPeakCache *> peakCaches; // zero or more | |
58 }; | |
59 | |
60 struct Parameters { | |
61 Parameters() : | |
62 colourScale(ColourScale::Parameters()), | |
63 normalization(ColumnNormalization::None), | |
64 binDisplay(BinDisplay::AllBins), | |
65 binScale(BinScale::Linear), | |
66 alwaysOpaque(false), | |
67 interpolate(false), | |
68 invertVertical(false), | |
69 scaleFactor(1.0), | |
70 colourRotation(0) { } | |
71 | |
72 /** A complete ColourScale object by value, used for colour | |
73 * map conversion. Note that the final display gain setting is | |
74 * also encapsulated here. */ | |
75 ColourScale colourScale; | |
76 | |
77 /** Type of column normalization. */ | |
78 ColumnNormalization normalization; | |
79 | |
80 /** Selection of bins to display. */ | |
81 BinDisplay binDisplay; | |
82 | |
83 /** Scale for vertical bin spacing (linear or logarithmic). */ | |
84 BinScale binScale; | |
85 | |
86 /** Whether cells should always be opaque. If false, then | |
87 * large cells (when zoomed in a long way) will be rendered | |
88 * translucent in order not to obscure anything in a layer | |
89 * beneath. */ | |
90 bool alwaysOpaque; | |
91 | |
92 /** Whether to apply smoothing when rendering cells at more | |
93 * than one pixel per cell. !!! todo: decide about separating | |
94 * out x-interpolate and y-interpolate as the spectrogram | |
95 * actually does (or used to) | |
96 */ | |
97 bool interpolate; | |
98 | |
99 /** Whether to render the whole caboodle upside-down. */ | |
100 bool invertVertical; | |
101 | |
102 /** Initial scale factor (e.g. for FFT scaling). This factor | |
103 * is applied to all values read from the underlying model | |
104 * *before* magnitude ranges are calculated, in contrast to | |
105 * the display gain found in the ColourScale parameter. */ | |
106 double scaleFactor; | |
107 | |
108 /** Colourmap rotation, in the range 0-255. */ | |
109 int colourRotation; | |
110 }; | |
111 | |
112 Colour3DPlotRenderer(Sources sources, Parameters parameters) : | |
113 m_sources(sources), | |
114 m_params(parameters) | |
115 { } | |
116 | |
117 struct RenderResult { | |
118 /** | |
119 * The rect that was actually rendered. May be equal to the | |
120 * rect that was requested to render, or may be smaller if | |
121 * time ran out and the complete flag was not set. | |
122 */ | |
123 QRect rendered; | |
124 | |
125 /** | |
126 * The magnitude range of the data in the rendered area. | |
127 */ | |
128 MagnitudeRange range; | |
129 }; | |
130 | |
131 /** | |
132 * Render the requested area using the given painter, obtaining | |
133 * geometry (e.g. start frame) from the given | |
134 * LayerGeometryProvider. | |
135 * | |
136 * The whole of the supplied rect will be rendered and the | |
137 * returned QRect will be equal to the supplied QRect. (See | |
138 * renderTimeConstrained for an alternative that may render only | |
139 * part of the rect in cases where obtaining source data is slow | |
140 * and retaining responsiveness is important.) | |
141 * | |
142 * Note that Colour3DPlotRenderer retains internal cache state | |
143 * related to the size and position of the supplied | |
144 * LayerGeometryProvider. Although it is valid to call render() | |
145 * successively on the same Colour3DPlotRenderer with different | |
146 * LayerGeometryProviders, it will be much faster to use a | |
147 * dedicated Colour3DPlotRenderer for each LayerGeometryProvider. | |
148 * | |
149 * If the model to render from is not ready, this will throw a | |
150 * std::logic_error exception. The model must be ready and the | |
151 * layer requesting the render must not be dormant in its view, so | |
152 * that the LayerGeometryProvider returns valid results; it is the | |
153 * caller's responsibility to ensure these. | |
154 */ | |
155 RenderResult render(const LayerGeometryProvider *v, | |
156 QPainter &paint, QRect rect); | |
157 | |
158 /** | |
159 * Render the requested area using the given painter, obtaining | |
160 * geometry (e.g. start frame) from the stored | |
161 * LayerGeometryProvider. | |
162 * | |
163 * As much of the rect will be rendered as can be managed given | |
164 * internal time constraints (using a RenderTimer object | |
165 * internally). The returned QRect (the rendered field in the | |
166 * RenderResult struct) will contain the area that was | |
167 * rendered. Note that we always render the full requested height, | |
168 * it's only width that is time-constrained. | |
169 * | |
170 * Note that Colour3DPlotRenderer retains internal cache state | |
171 * related to the size and position of the supplied | |
172 * LayerGeometryProvider. Although it is valid to call render() | |
173 * successively on the same Colour3DPlotRenderer with different | |
174 * LayerGeometryProviders, it will be much faster to use a | |
175 * dedicated Colour3DPlotRenderer for each LayerGeometryProvider. | |
176 * | |
177 * If the model to render from is not ready, this will throw a | |
178 * std::logic_error exception. The model must be ready and the | |
179 * layer requesting the render must not be dormant in its view, so | |
180 * that the LayerGeometryProvider returns valid results; it is the | |
181 * caller's responsibility to ensure these. | |
182 */ | |
183 RenderResult renderTimeConstrained(const LayerGeometryProvider *v, | |
184 QPainter &paint, QRect rect); | |
185 | |
186 /** | |
187 * Return the area of the largest rectangle within the entire area | |
188 * of the cache that is unavailable in the cache. This is only | |
189 * valid in relation to a preceding render() call which is | |
190 * presumed to have set the area, start frame, and zoom level for | |
191 * the cache. It could be used to establish a suitable region for | |
192 * a subsequent paint request (because if an area is not in the | |
193 * cache, it cannot have been rendered since the cache was | |
194 * cleared). | |
195 * | |
196 * Returns an empty QRect if the cache is entirely valid. | |
197 */ | |
198 QRect getLargestUncachedRect(const LayerGeometryProvider *v); | |
199 | |
200 /** | |
201 * Return true if the provider's geometry differs from the cache, | |
202 * or if we are not using a cache. i.e. if the cache will be | |
203 * regenerated for the next render, or the next render performed | |
204 * from scratch. | |
205 */ | |
206 bool geometryChanged(const LayerGeometryProvider *v); | |
207 | |
208 /** | |
209 * Return true if the rendering will be opaque. This may be used | |
210 * by the calling layer to determine whether it can scroll | |
211 * directly without regard to any other layers beneath. | |
212 */ | |
213 bool willRenderOpaque(const LayerGeometryProvider *v) { | |
214 return decideRenderType(v) != DirectTranslucent; | |
215 } | |
216 | |
217 /** | |
218 * Return the colour corresponding to the given value. | |
219 * \see ColourScale::getPixel | |
220 * \see ColourScale::getColour | |
221 */ | |
222 QColor getColour(double value) const { | |
223 return m_params.colourScale.getColour(value, m_params.colourRotation); | |
224 } | |
225 | |
226 /** | |
227 * Return the enclosing rectangle for the region of similar colour | |
228 * to the given point within the cache. Return an empty QRect if | |
229 * this is not possible. \see ImageRegionFinder | |
230 */ | |
231 QRect findSimilarRegionExtents(QPoint point) const; | |
232 | |
233 private: | |
234 Sources m_sources; | |
235 Parameters m_params; | |
236 | |
237 // Draw buffer is the target of each partial repaint. It is always | |
238 // at view height (not model height) and is cleared and repainted | |
239 // on each fragment render. The only reason it's stored as a data | |
240 // member is to avoid reallocation. | |
241 QImage m_drawBuffer; | |
242 | |
243 // A temporary store of magnitude ranges per-column, used when | |
244 // rendering to the draw buffer. This always has the same length | |
245 // as the width of the draw buffer, and the x coordinates of the | |
246 // two containers are equivalent. | |
247 std::vector<MagnitudeRange> m_magRanges; | |
248 | |
249 // The image cache is our persistent record of the visible | |
250 // area. It is always the same size as the view (i.e. the paint | |
251 // size reported by the LayerGeometryProvider) and is scrolled and | |
252 // partially repainted internally as appropriate. A render request | |
253 // is carried out by repainting to cache (via the draw buffer) any | |
254 // area that is being requested but is not valid in the cache, and | |
255 // then repainting from cache to the requested painter. | |
256 ScrollableImageCache m_cache; | |
257 | |
258 // The mag range cache is our record of the column magnitude | |
259 // ranges for each of the columns in the cache. It always has the | |
260 // same start frame and width as the image cache, and the column | |
261 // indices match up across both. Our cache update mechanism | |
262 // guarantees that every valid column in the image cache has a | |
263 // valid range in the magnitude cache, but not necessarily vice | |
264 // versa (as the image cache is limited to contiguous ranges). | |
265 ScrollableMagRangeCache m_magCache; | |
266 | |
267 RenderResult render(const LayerGeometryProvider *v, | |
268 QPainter &paint, QRect rect, bool timeConstrained); | |
269 | |
270 MagnitudeRange renderDirectTranslucent(const LayerGeometryProvider *v, | |
271 QPainter &paint, QRect rect); | |
272 | |
273 void renderToCachePixelResolution(const LayerGeometryProvider *v, int x0, | |
274 int repaintWidth, bool rightToLeft, | |
275 bool timeConstrained); | |
276 | |
277 void renderToCacheBinResolution(const LayerGeometryProvider *v, int x0, | |
278 int repaintWidth); | |
279 | |
280 int renderDrawBuffer(int w, int h, | |
281 const std::vector<int> &binforx, | |
282 const std::vector<double> &binfory, | |
283 int peakCacheIndex, // -1 => don't use a peak cache | |
284 bool rightToLeft, | |
285 bool timeConstrained); | |
286 | |
287 int renderDrawBufferPeakFrequencies(const LayerGeometryProvider *v, | |
288 int w, int h, | |
289 const std::vector<int> &binforx, | |
290 const std::vector<double> &binfory, | |
291 bool rightToLeft, | |
292 bool timeConstrained); | |
293 | |
294 void recreateDrawBuffer(int w, int h); | |
295 void clearDrawBuffer(int w, int h); | |
296 | |
297 enum RenderType { | |
298 DrawBufferPixelResolution, | |
299 DrawBufferBinResolution, | |
300 DirectTranslucent | |
301 }; | |
302 | |
303 RenderType decideRenderType(const LayerGeometryProvider *) const; | |
304 | |
305 QImage scaleDrawBufferImage(QImage source, int targetWidth, int targetHeight) | |
306 const; | |
307 | |
308 ColumnOp::Column getColumn(int sx, int minbin, int nbins, | |
309 int peakCacheIndex) const; // -1 => don't use cache | |
310 | |
311 void getPreferredPeakCache(const LayerGeometryProvider *, | |
312 int &peakCacheIndex, int &binsPerPeak) const; | |
313 }; | |
314 | |
315 #endif | |
316 |