Mercurial > hg > svgui
comparison layer/Colour3DPlotRenderer.cpp @ 1109:477521f95a84 spectrogram-minor-refactor
Start introducing translucent renderer
author | Chris Cannam |
---|---|
date | Mon, 18 Jul 2016 15:37:15 +0100 |
parents | ea5ae9dd10ba |
children | 67dd16e33a3d |
comparison
equal
deleted
inserted
replaced
1108:edbe229860ac | 1109:477521f95a84 |
---|---|
20 #include "data/model/Dense3DModelPeakCache.h" | 20 #include "data/model/Dense3DModelPeakCache.h" |
21 #include "data/model/FFTModel.h" | 21 #include "data/model/FFTModel.h" |
22 | 22 |
23 #include "LayerGeometryProvider.h" | 23 #include "LayerGeometryProvider.h" |
24 #include "VerticalBinLayer.h" | 24 #include "VerticalBinLayer.h" |
25 #include "PaintAssistant.h" | |
26 | |
27 #include "view/ViewManager.h" // for main model sample rate. Pity | |
25 | 28 |
26 #include <vector> | 29 #include <vector> |
27 | 30 |
28 //#define DEBUG_SPECTROGRAM_REPAINT 1 | 31 //#define DEBUG_SPECTROGRAM_REPAINT 1 |
29 | 32 |
60 | 63 |
61 Colour3DPlotRenderer::RenderResult | 64 Colour3DPlotRenderer::RenderResult |
62 Colour3DPlotRenderer::render(LayerGeometryProvider *v, | 65 Colour3DPlotRenderer::render(LayerGeometryProvider *v, |
63 QPainter &paint, QRect rect, bool timeConstrained) | 66 QPainter &paint, QRect rect, bool timeConstrained) |
64 { | 67 { |
68 RenderType renderType = decideRenderType(v); | |
69 | |
70 if (renderType != DrawBufferPixelResolution) { | |
71 // Rendering should be fast in bin-resolution and direct draw | |
72 // cases because we are quite well zoomed-in, and the sums are | |
73 // easier this way. Calculating boundaries later will be | |
74 // fiddly for partial paints otherwise. | |
75 timeConstrained = false; | |
76 } | |
77 | |
78 if (renderType == DirectTranslucent) { | |
79 renderDirectTranslucent(v, paint, rect); | |
80 return { rect, {} }; //!!! this return arg is not very useful | |
81 } | |
82 | |
65 sv_frame_t startFrame = v->getStartFrame(); | 83 sv_frame_t startFrame = v->getStartFrame(); |
66 | 84 |
67 int x0 = v->getXForViewX(rect.x()); | 85 int x0 = v->getXForViewX(rect.x()); |
68 int x1 = v->getXForViewX(rect.x() + rect.width()); | 86 int x1 = v->getXForViewX(rect.x() + rect.width()); |
69 if (x0 < 0) x0 = 0; | 87 if (x0 < 0) x0 = 0; |
78 << endl; | 96 << endl; |
79 cerr << " view start " << startFrame | 97 cerr << " view start " << startFrame |
80 << " x0 " << x0 | 98 << " x0 " << x0 |
81 << " x1 " << x1 | 99 << " x1 " << x1 |
82 << endl; | 100 << endl; |
83 | |
84 bool bufferIsBinResolution = useBinResolutionForDrawBuffer(v); | |
85 | |
86 if (bufferIsBinResolution) { | |
87 // Rendering should be fast in this situation because we are | |
88 // quite well zoomed-in, and the sums are easier this | |
89 // way. Calculating boundaries later will be fiddly for | |
90 // partial paints otherwise. | |
91 timeConstrained = false; | |
92 } | |
93 | 101 |
94 if (m_cache.isValid()) { // some part of the cache is valid | 102 if (m_cache.isValid()) { // some part of the cache is valid |
95 | 103 |
96 if (v->getXForFrame(m_cache.getStartFrame()) == | 104 if (v->getXForFrame(m_cache.getStartFrame()) == |
97 v->getXForFrame(startFrame) && | 105 v->getXForFrame(startFrame) && |
143 x0 = int(x1 * 0.3); | 151 x0 = int(x1 * 0.3); |
144 } | 152 } |
145 } | 153 } |
146 | 154 |
147 if (m_cache.isValid()) { | 155 if (m_cache.isValid()) { |
148 cerr << "cache somewhat valid" << endl; | |
149 | 156 |
150 // When rendering only a part of the cache, we need to make | 157 // When rendering only a part of the cache, we need to make |
151 // sure that the part we're rendering is adjacent to (or | 158 // sure that the part we're rendering is adjacent to (or |
152 // overlapping) a valid area of cache, if we have one. The | 159 // overlapping) a valid area of cache, if we have one. The |
153 // alternative is to ditch the valid area of cache and render | 160 // alternative is to ditch the valid area of cache and render |
166 // sub-regions of our target region in right-to-left order in | 173 // sub-regions of our target region in right-to-left order in |
167 // order to ensure contiguity | 174 // order to ensure contiguity |
168 rightToLeft = isLeftOfValidArea; | 175 rightToLeft = isLeftOfValidArea; |
169 } | 176 } |
170 | 177 |
171 // Note, we always paint the full height. Smaller heights can be | 178 // Note, we always paint the full height to cache. We want to |
172 // used when painting direct from cache (outside this function), | 179 // ensure the cache is coherent without having to worry about |
173 // but we want to ensure the cache is coherent without having to | 180 // vertical matching of required and valid areas as well as |
174 // worry about vertical matching of required and valid areas as | 181 // horizontal. |
175 // well as horizontal. That's why this function didn't take any | 182 |
176 // y/height parameters. | 183 if (renderType == DrawBufferBinResolution) { |
177 | 184 |
178 if (bufferIsBinResolution && (m_params.binDisplay != BinDisplay::PeakFrequencies)) { | |
179 renderToCacheBinResolution(v, x0, x1 - x0); | 185 renderToCacheBinResolution(v, x0, x1 - x0); |
180 } else { | 186 |
187 } else { // must be DrawBufferPixelResolution, handled DirectTranslucent earlier | |
188 | |
181 renderToCachePixelResolution(v, x0, x1 - x0, rightToLeft, timeConstrained); | 189 renderToCachePixelResolution(v, x0, x1 - x0, rightToLeft, timeConstrained); |
182 } | 190 } |
183 | 191 |
184 QRect pr = rect & m_cache.getValidArea(); | 192 QRect pr = rect & m_cache.getValidArea(); |
185 paint.drawImage(pr.x(), pr.y(), m_cache.getImage(), | 193 paint.drawImage(pr.x(), pr.y(), m_cache.getImage(), |
210 //!!! fft model scaling? | 218 //!!! fft model scaling? |
211 | 219 |
212 //!!! should we own the Dense3DModelPeakCache here? or should it persist | 220 //!!! should we own the Dense3DModelPeakCache here? or should it persist |
213 } | 221 } |
214 | 222 |
215 bool | 223 Colour3DPlotRenderer::RenderType |
216 Colour3DPlotRenderer::useBinResolutionForDrawBuffer(LayerGeometryProvider *v) const | 224 Colour3DPlotRenderer::decideRenderType(LayerGeometryProvider *v) const |
217 { | 225 { |
218 const DenseThreeDimensionalModel *model = m_sources.source; | 226 const DenseThreeDimensionalModel *model = m_sources.source; |
219 if (!model) return false; | 227 if (!model || !v || !(v->getViewManager())) { |
228 return DrawBufferPixelResolution; // or anything | |
229 } | |
230 | |
220 int binResolution = model->getResolution(); | 231 int binResolution = model->getResolution(); |
221 int zoomLevel = v->getZoomLevel(); | 232 int zoomLevel = v->getZoomLevel(); |
222 return (binResolution > zoomLevel); | 233 sv_samplerate_t modelRate = model->getSampleRate(); |
234 | |
235 double rateRatio = v->getViewManager()->getMainModelSampleRate() / modelRate; | |
236 double relativeBinResolution = binResolution * rateRatio; | |
237 | |
238 if (m_params.binDisplay == BinDisplay::PeakFrequencies) { | |
239 // no alternative works here | |
240 return DrawBufferPixelResolution; | |
241 } | |
242 | |
243 if (!m_params.alwaysOpaque && !m_params.interpolate) { | |
244 | |
245 // consider translucent option -- only if not smoothing & not | |
246 // explicitly requested opaque & sufficiently zoomed-in | |
247 | |
248 if (model->getHeight() < v->getPaintHeight() && | |
249 relativeBinResolution >= 2 * zoomLevel) { | |
250 return DirectTranslucent; | |
251 } | |
252 } | |
253 | |
254 if (relativeBinResolution > zoomLevel) { | |
255 return DrawBufferBinResolution; | |
256 } else { | |
257 return DrawBufferPixelResolution; | |
258 } | |
259 } | |
260 | |
261 void | |
262 Colour3DPlotRenderer::renderDirectTranslucent(LayerGeometryProvider *v, | |
263 QPainter &paint, | |
264 QRect rect) | |
265 { | |
266 //!!! QPoint illuminatePos; | |
267 // bool illuminate = v->shouldIlluminateLocalFeatures | |
268 // (m_sources.verticalBinLayer, illuminatePos); | |
269 | |
270 const DenseThreeDimensionalModel *model = m_sources.source; | |
271 | |
272 int x0 = rect.left(); | |
273 int x1 = rect.right() + 1; | |
274 | |
275 int h = v->getPaintHeight(); | |
276 | |
277 sv_frame_t modelStart = model->getStartFrame(); | |
278 sv_frame_t modelEnd = model->getEndFrame(); | |
279 int modelResolution = model->getResolution(); | |
280 | |
281 double rateRatio = | |
282 v->getViewManager()->getMainModelSampleRate() / model->getSampleRate(); | |
283 | |
284 // the s-prefix values are source, i.e. model, column and bin numbers | |
285 int sx0 = int((double(v->getFrameForX(x0)) / rateRatio - double(modelStart)) | |
286 / modelResolution); | |
287 int sx1 = int((double(v->getFrameForX(x1)) / rateRatio - double(modelStart)) | |
288 / modelResolution); | |
289 | |
290 int sh = model->getHeight(); | |
291 | |
292 const int buflen = 40; | |
293 char labelbuf[buflen]; | |
294 | |
295 int minbin = 0; | |
296 int maxbin = sh - 1; //!!! | |
297 | |
298 int psx = -1; | |
299 | |
300 vector<float> preparedColumn; | |
301 | |
302 int modelWidth = model->getWidth(); | |
303 | |
304 for (int sx = sx0; sx <= sx1; ++sx) { | |
305 | |
306 if (sx < 0 || sx >= modelWidth) { | |
307 continue; | |
308 } | |
309 | |
310 if (sx != psx) { | |
311 | |
312 //!!! this is in common with renderDrawBuffer - pull it out | |
313 | |
314 // order: | |
315 // get column -> scale -> record extents -> | |
316 // normalise -> peak pick -> apply display gain -> | |
317 // distribute/interpolate | |
318 | |
319 ColumnOp::Column fullColumn = model->getColumn(sx); | |
320 | |
321 // cerr << "x " << x << ", sx " << sx << ", col height " << fullColumn.size() | |
322 // << ", minbin " << minbin << ", maxbin " << maxbin << endl; | |
323 | |
324 ColumnOp::Column column = | |
325 vector<float>(fullColumn.data() + minbin, | |
326 fullColumn.data() + maxbin + 1); | |
327 | |
328 //!!! fft scale if (m_colourScale != ColourScaleType::Phase) { | |
329 // column = ColumnOp::fftScale(column, m_fftSize); | |
330 // } | |
331 | |
332 //!!! extents recordColumnExtents(column, | |
333 // sx, | |
334 // overallMag, | |
335 // overallMagChanged); | |
336 | |
337 // if (m_colourScale != ColourScaleType::Phase) { | |
338 column = ColumnOp::normalize(column, m_params.normalization); | |
339 // } | |
340 | |
341 if (m_params.binDisplay == BinDisplay::PeakBins) { | |
342 column = ColumnOp::peakPick(column); | |
343 } | |
344 | |
345 preparedColumn = column; //!!! unnecessary dup | |
346 | |
347 psx = sx; | |
348 } | |
349 | |
350 sv_frame_t fx = sx * modelResolution + modelStart; | |
351 | |
352 if (fx + modelResolution <= modelStart || fx > modelEnd) continue; | |
353 | |
354 int rx0 = v->getXForFrame(int(double(fx) * rateRatio)); | |
355 int rx1 = v->getXForFrame(int(double(fx + modelResolution + 1) * rateRatio)); | |
356 | |
357 int rw = rx1 - rx0; | |
358 if (rw < 1) rw = 1; | |
359 | |
360 bool showLabel = (rw > 10 && | |
361 paint.fontMetrics().width("0.000000") < rw - 3 && | |
362 paint.fontMetrics().height() < (h / sh)); | |
363 | |
364 for (int sy = minbin; sy <= maxbin; ++sy) { | |
365 | |
366 int ry0 = m_sources.verticalBinLayer->getIYForBin(v, sy); | |
367 int ry1 = m_sources.verticalBinLayer->getIYForBin(v, sy + 1); | |
368 QRect r(rx0, ry1, rw, ry0 - ry1); | |
369 | |
370 float value = preparedColumn[sy - minbin]; | |
371 QColor colour = m_params.colourScale.getColour(value, 0);//!!! +rotation | |
372 | |
373 if (rw == 1) { | |
374 paint.setPen(colour); | |
375 paint.setBrush(Qt::NoBrush); | |
376 paint.drawLine(r.x(), r.y(), r.x(), r.y() + r.height() - 1); | |
377 continue; | |
378 } | |
379 | |
380 QColor pen(255, 255, 255, 80); | |
381 QColor brush(colour); | |
382 | |
383 if (rw > 3 && r.height() > 3) { | |
384 brush.setAlpha(160); | |
385 } | |
386 | |
387 paint.setPen(Qt::NoPen); | |
388 paint.setBrush(brush); | |
389 | |
390 //!!! if (illuminate) { | |
391 // if (r.contains(illuminatePos)) { | |
392 // paint.setPen(v->getForeground()); | |
393 // } | |
394 // } | |
395 | |
396 #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT | |
397 // cerr << "rect " << r.x() << "," << r.y() << " " | |
398 // << r.width() << "x" << r.height() << endl; | |
399 #endif | |
400 | |
401 paint.drawRect(r); | |
402 | |
403 if (showLabel) { | |
404 double value = model->getValueAt(sx, sy); | |
405 snprintf(labelbuf, buflen, "%06f", value); | |
406 QString text(labelbuf); | |
407 PaintAssistant::drawVisibleText | |
408 (v, | |
409 paint, | |
410 rx0 + 2, | |
411 ry0 - h / sh - 1 + 2 + paint.fontMetrics().ascent(), | |
412 text, | |
413 PaintAssistant::OutlinedText); | |
414 } | |
415 } | |
416 } | |
417 | |
223 } | 418 } |
224 | 419 |
225 void | 420 void |
226 Colour3DPlotRenderer::renderToCachePixelResolution(LayerGeometryProvider *v, | 421 Colour3DPlotRenderer::renderToCachePixelResolution(LayerGeometryProvider *v, |
227 int x0, int repaintWidth, | 422 int x0, int repaintWidth, |