Mercurial > hg > svgui
comparison layer/Colour3DPlotRenderer.cpp @ 1090:c8c747783110 spectrogram-minor-refactor
Cut over to using the renderer (though it's very incomplete) and fix some cache problems and pointer lifetime misunderstandings
author | Chris Cannam |
---|---|
date | Tue, 05 Jul 2016 17:48:26 +0100 |
parents | db976e9f385a |
children | 8a815776151c |
comparison
equal
deleted
inserted
replaced
1089:c8683d94442a | 1090:c8c747783110 |
---|---|
26 #include <vector> | 26 #include <vector> |
27 | 27 |
28 using namespace std; | 28 using namespace std; |
29 | 29 |
30 Colour3DPlotRenderer::RenderResult | 30 Colour3DPlotRenderer::RenderResult |
31 Colour3DPlotRenderer::render(QPainter &paint, QRect rect) | 31 Colour3DPlotRenderer::render(LayerGeometryProvider *v, QPainter &paint, QRect rect) |
32 { | 32 { |
33 return render(paint, rect, false); | 33 return render(v, paint, rect, false); |
34 } | 34 } |
35 | 35 |
36 Colour3DPlotRenderer::RenderResult | 36 Colour3DPlotRenderer::RenderResult |
37 Colour3DPlotRenderer::renderTimeConstrained(QPainter &paint, QRect rect) | 37 Colour3DPlotRenderer::renderTimeConstrained(LayerGeometryProvider *v, |
38 QPainter &paint, QRect rect) | |
38 { | 39 { |
39 return render(paint, rect, true); | 40 return render(v, paint, rect, true); |
40 } | 41 } |
41 | 42 |
42 Colour3DPlotRenderer::RenderResult | 43 Colour3DPlotRenderer::RenderResult |
43 Colour3DPlotRenderer::render(QPainter &paint, QRect rect, bool timeConstrained) | 44 Colour3DPlotRenderer::render(LayerGeometryProvider *v, |
45 QPainter &paint, QRect rect, bool timeConstrained) | |
44 { | 46 { |
45 LayerGeometryProvider *v = m_sources.geometryProvider; | |
46 if (!v) { | |
47 throw std::logic_error("no LayerGeometryProvider provided"); | |
48 } | |
49 | |
50 sv_frame_t startFrame = v->getStartFrame(); | 47 sv_frame_t startFrame = v->getStartFrame(); |
51 | 48 |
52 int x0 = v->getXForViewX(rect.x()); | 49 int x0 = v->getXForViewX(rect.x()); |
53 int x1 = v->getXForViewX(rect.x() + rect.width()); | 50 int x1 = v->getXForViewX(rect.x() + rect.width()); |
54 if (x0 < 0) x0 = 0; | 51 if (x0 < 0) x0 = 0; |
55 if (x1 > v->getPaintWidth()) x1 = v->getPaintWidth(); | 52 if (x1 > v->getPaintWidth()) x1 = v->getPaintWidth(); |
56 | 53 |
57 m_cache.resize(v->getPaintSize()); | 54 m_cache.resize(v->getPaintSize()); |
58 m_cache.setZoomLevel(v->getZoomLevel()); | 55 m_cache.setZoomLevel(v->getZoomLevel()); |
59 | 56 |
57 cerr << "cache start " << m_cache.getStartFrame() | |
58 << " view start " << startFrame | |
59 << " valid left " << m_cache.getValidLeft() | |
60 << " valid right " << m_cache.getValidRight() | |
61 << " x0 " << x0 | |
62 << " x1 " << x1 | |
63 << endl; | |
64 | |
65 | |
60 if (m_cache.isValid()) { // some part of the cache is valid | 66 if (m_cache.isValid()) { // some part of the cache is valid |
61 | 67 |
62 if (v->getXForFrame(m_cache.getStartFrame()) == | 68 if (v->getXForFrame(m_cache.getStartFrame()) == |
63 v->getXForFrame(startFrame) && | 69 v->getXForFrame(startFrame) && |
64 m_cache.getValidLeft() <= x0 && | 70 m_cache.getValidLeft() <= x0 && |
65 m_cache.getValidRight() >= x1) { | 71 m_cache.getValidRight() >= x1) { |
66 | 72 |
73 cerr << "cache hit" << endl; | |
74 | |
67 // cache is valid for the complete requested area | 75 // cache is valid for the complete requested area |
68 paint.drawImage(rect, m_cache.getImage(), rect); | 76 paint.drawImage(rect, m_cache.getImage(), rect); |
69 return { rect, {} }; | 77 return { rect, {} }; |
70 | 78 |
71 } else { | 79 } else { |
80 cerr << "cache partial hit" << endl; | |
81 | |
72 // cache doesn't begin at the right frame or doesn't | 82 // cache doesn't begin at the right frame or doesn't |
73 // contain the complete view, but might be scrollable or | 83 // contain the complete view, but might be scrollable or |
74 // partially usable | 84 // partially usable |
75 m_cache.scrollTo(startFrame); | 85 m_cache.scrollTo(v, startFrame); |
76 | 86 |
77 // if we are not time-constrained, then we want to paint | 87 // if we are not time-constrained, then we want to paint |
78 // the whole area in one go; we don't return a partial | 88 // the whole area in one go; we don't return a partial |
79 // paint. To avoid providing the more complex logic to | 89 // paint. To avoid providing the more complex logic to |
80 // handle painting discontiguous areas, if the only valid | 90 // handle painting discontiguous areas, if the only valid |
85 m_cache.getValidRight() < x1) { | 95 m_cache.getValidRight() < x1) { |
86 m_cache.invalidate(); | 96 m_cache.invalidate(); |
87 } | 97 } |
88 } | 98 } |
89 } | 99 } |
100 } else { | |
101 // cache completely invalid | |
102 m_cache.setStartFrame(startFrame); | |
90 } | 103 } |
91 | 104 |
92 bool rightToLeft = false; | 105 bool rightToLeft = false; |
93 | 106 |
94 if (!m_cache.isValid() && timeConstrained) { | 107 if (!m_cache.isValid() && timeConstrained) { |
102 x0 = int(x1 * 0.3); | 115 x0 = int(x1 * 0.3); |
103 } | 116 } |
104 } | 117 } |
105 | 118 |
106 if (m_cache.isValid()) { | 119 if (m_cache.isValid()) { |
120 cerr << "cache somewhat valid" << endl; | |
121 | |
107 // When rendering only a part of the cache, we need to make | 122 // When rendering only a part of the cache, we need to make |
108 // sure that the part we're rendering is adjacent to (or | 123 // sure that the part we're rendering is adjacent to (or |
109 // overlapping) a valid area of cache, if we have one. The | 124 // overlapping) a valid area of cache, if we have one. The |
110 // alternative is to ditch the valid area of cache and render | 125 // alternative is to ditch the valid area of cache and render |
111 // only the requested area, but that's risky because this can | 126 // only the requested area, but that's risky because this can |
123 // sub-regions of our target region in right-to-left order in | 138 // sub-regions of our target region in right-to-left order in |
124 // order to ensure contiguity | 139 // order to ensure contiguity |
125 rightToLeft = isLeftOfValidArea; | 140 rightToLeft = isLeftOfValidArea; |
126 } | 141 } |
127 | 142 |
128 renderToCache(x0, x1 - x0, rightToLeft, timeConstrained); | 143 renderToCache(v, x0, x1 - x0, rightToLeft, timeConstrained); |
129 | 144 |
130 QRect pr = rect & m_cache.getValidArea(); | 145 QRect pr = rect & m_cache.getValidArea(); |
131 paint.drawImage(pr.x(), pr.y(), m_cache.getImage(), | 146 paint.drawImage(pr.x(), pr.y(), m_cache.getImage(), |
132 pr.x(), pr.y(), pr.width(), pr.height()); | 147 pr.x(), pr.y(), pr.width(), pr.height()); |
133 | 148 |
159 | 174 |
160 //!!! should we own the Dense3DModelPeakCache here? or should it persist | 175 //!!! should we own the Dense3DModelPeakCache here? or should it persist |
161 } | 176 } |
162 | 177 |
163 void | 178 void |
164 Colour3DPlotRenderer::renderToCache(int x0, int repaintWidth, | 179 Colour3DPlotRenderer::renderToCache(LayerGeometryProvider *v, |
180 int x0, int repaintWidth, | |
165 bool rightToLeft, bool timeConstrained) | 181 bool rightToLeft, bool timeConstrained) |
166 { | 182 { |
167 // Draw to the draw buffer, and then scale-copy from there. | 183 // Draw to the draw buffer, and then scale-copy from there. |
168 | 184 |
169 DenseThreeDimensionalModel *model = m_sources.source; | 185 DenseThreeDimensionalModel *model = m_sources.source; |
170 if (!model || !model->isOK() || !model->isReady()) { | 186 if (!model || !model->isOK() || !model->isReady()) { |
171 throw std::logic_error("no source model provided, or model not ready"); | 187 throw std::logic_error("no source model provided, or model not ready"); |
172 } | 188 } |
173 | |
174 LayerGeometryProvider *v = m_sources.geometryProvider; // already checked | |
175 | 189 |
176 // The draw buffer contains a fragment at either our pixel | 190 // The draw buffer contains a fragment at either our pixel |
177 // resolution (if there is more than one time-bin per pixel) or | 191 // resolution (if there is more than one time-bin per pixel) or |
178 // time-bin resolution (if a time-bin spans more than one pixel). | 192 // time-bin resolution (if a time-bin spans more than one pixel). |
179 // We need to ensure that it starts and ends at points where a | 193 // We need to ensure that it starts and ends at points where a |
249 // case because it means we're well zoomed in | 263 // case because it means we're well zoomed in |
250 timeConstrained = false; | 264 timeConstrained = false; |
251 | 265 |
252 } else { | 266 } else { |
253 for (int x = 0; x < drawWidth; ++x) { | 267 for (int x = 0; x < drawWidth; ++x) { |
254 sv_frame_t f0 = v->getFrameForX(x); | 268 sv_frame_t f0 = v->getFrameForX(x0 + x); |
255 double s0 = double(f0 - model->getStartFrame()) / binResolution; | 269 double s0 = double(f0 - model->getStartFrame()) / binResolution; |
256 binforx[x] = int(s0 + 0.0001); | 270 binforx[x] = int(s0 + 0.0001); |
257 } | 271 } |
258 | 272 |
259 if (m_sources.peaks) { // peaks cache exists | 273 if (m_sources.peaks) { // peaks cache exists |
267 } | 281 } |
268 } | 282 } |
269 } | 283 } |
270 | 284 |
271 for (int y = 0; y < h; ++y) { | 285 for (int y = 0; y < h; ++y) { |
272 binfory[y] = | 286 binfory[y] = m_sources.verticalBinLayer->getBinForY(v, h - y - 1); |
273 m_sources.verticalBinLayer->getBinForY(m_sources.geometryProvider, y); | |
274 } | 287 } |
275 | 288 |
276 int attainedWidth = renderDrawBuffer(repaintWidth, | 289 int attainedWidth = renderDrawBuffer(repaintWidth, |
277 h, | 290 h, |
278 binforx, | 291 binforx, |
332 m_cache.drawImage(paintedLeft, attainedWidth, | 345 m_cache.drawImage(paintedLeft, attainedWidth, |
333 m_drawBuffer, | 346 m_drawBuffer, |
334 paintedLeft - x0, attainedWidth); | 347 paintedLeft - x0, attainedWidth); |
335 } | 348 } |
336 } | 349 } |
337 | |
338 | 350 |
339 int | 351 int |
340 Colour3DPlotRenderer::renderDrawBuffer(int w, int h, | 352 Colour3DPlotRenderer::renderDrawBuffer(int w, int h, |
341 const vector<int> &binforx, | 353 const vector<int> &binforx, |
342 const vector<double> &binfory, | 354 const vector<double> &binfory, |
414 // get column -> scale -> record extents -> | 426 // get column -> scale -> record extents -> |
415 // normalise -> peak pick -> apply display gain -> | 427 // normalise -> peak pick -> apply display gain -> |
416 // distribute/interpolate | 428 // distribute/interpolate |
417 | 429 |
418 ColumnOp::Column fullColumn = sourceModel->getColumn(sx); | 430 ColumnOp::Column fullColumn = sourceModel->getColumn(sx); |
431 | |
432 cerr << "x " << x << ", sx " << sx << ", col height " << fullColumn.size() | |
433 << ", minbin " << minbin << ", maxbin " << maxbin << endl; | |
434 | |
419 ColumnOp::Column column = | 435 ColumnOp::Column column = |
420 vector<float>(fullColumn.data() + minbin, | 436 vector<float>(fullColumn.data() + minbin, |
421 fullColumn.data() + maxbin + 1); | 437 fullColumn.data() + maxbin + 1); |
422 | 438 |
423 //!!! fft scale if (m_colourScale != PhaseColourScale) { | 439 //!!! fft scale if (m_colourScale != PhaseColourScale) { |