Line data Source code
1 :
2 : /* Copyright (c) 2009, Maxim Makhinya
3 : * 2010-2014, Stefan Eilemann <eile@equalizergraphics.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #define EQ_ROI_USE_TRACKER // disable ROI in case it can't help
20 : //#define EQ_ROI_USE_DEPTH_TEXTURE // use depth texture instead of color
21 :
22 : #include "roiFinder.h"
23 :
24 : #ifdef EQ_ROI_USE_DEPTH_TEXTURE
25 : #include "roiFragmentShader_glsl.h"
26 : #else
27 : #include "roiFragmentShaderRGB_glsl.h"
28 : #endif
29 :
30 : #include "gl.h"
31 : #include "log.h"
32 :
33 : #include <eq/util/frameBufferObject.h>
34 : #include <eq/util/objectManager.h>
35 : #include <eq/util/shader.h>
36 : #include <lunchbox/os.h>
37 : #include <pression/plugins/compressor.h>
38 :
39 : namespace eq
40 : {
41 : #define glewGetContext glObjects.glewGetContext
42 :
43 : // use to address one shader and program per shared context set
44 : static const char seeds = 42;
45 : static const char* shaderRBInfo = &seeds;
46 :
47 : #define GRID_SIZE 16 // will be replaced later by variable
48 :
49 2 : ROIFinder::ROIFinder()
50 : : _dim()
51 : , _w(0)
52 : , _h(0)
53 : , _wh(0)
54 : , _wb(0)
55 : , _hb(0)
56 : , _wbhb(0)
57 : , _histX()
58 2 : , _histY()
59 : {
60 2 : _tmpAreas[0].pvp = PixelViewport(0, 0, 0, 0);
61 2 : _tmpAreas[0].hole = PixelViewport(0, 0, 0, 0);
62 2 : _tmpAreas[0].emptySize = 0;
63 2 : }
64 :
65 0 : PixelViewport ROIFinder::_getObjectPVP(const PixelViewport& pvp,
66 : const uint8_t* src)
67 : {
68 0 : LBASSERT(pvp.x >= 0 && pvp.x + pvp.w <= _wb && pvp.y >= 0 &&
69 : pvp.y + pvp.h <= _hb);
70 :
71 : // Calculate per-pixel histograms
72 0 : const uint8_t* s = src + pvp.y * _wb + pvp.x;
73 :
74 0 : memset(_histX, 0, pvp.w);
75 0 : memset(_histY, 0, pvp.h);
76 0 : for (int32_t y = 0; y < pvp.h; y++)
77 : {
78 0 : for (int32_t x = 0; x < pvp.w; x++)
79 : {
80 0 : const uint8_t val = s[x] & 1;
81 0 : _histX[x] += val;
82 0 : _histY[y] += val;
83 : }
84 0 : s += _wb;
85 : }
86 :
87 : // Find AABB based on X and Y axis historgams
88 0 : int32_t xMin = pvp.w;
89 0 : for (int32_t x = 0; x < pvp.w; x++)
90 0 : if (_histX[x] != 0)
91 : {
92 0 : xMin = x;
93 0 : break;
94 : }
95 :
96 0 : int32_t xMax = 0;
97 0 : for (int32_t x = pvp.w - 1; x >= 0; x--)
98 0 : if (_histX[x] != 0)
99 : {
100 0 : xMax = x;
101 0 : break;
102 : }
103 :
104 0 : if (xMax < xMin)
105 0 : return PixelViewport(pvp.x, pvp.y, 0, 0);
106 :
107 0 : int32_t yMin = pvp.h;
108 0 : for (int32_t y = 0; y < pvp.h; y++)
109 0 : if (_histY[y] != 0)
110 : {
111 0 : yMin = y;
112 0 : break;
113 : }
114 :
115 0 : int32_t yMax = 0;
116 0 : for (int32_t y = pvp.h - 1; y >= 0; y--)
117 0 : if (_histY[y] != 0)
118 : {
119 0 : yMax = y;
120 0 : break;
121 : }
122 :
123 0 : if (yMax < yMin)
124 0 : return PixelViewport(pvp.x, pvp.y, 0, 0);
125 :
126 0 : return PixelViewport(pvp.x + xMin, pvp.y + yMin, xMax - xMin + 1,
127 0 : yMax - yMin + 1);
128 : }
129 :
130 0 : void ROIFinder::_resize(const PixelViewport& pvp)
131 : {
132 0 : _pvp = pvp;
133 :
134 0 : _w = _pvp.w;
135 0 : _h = _pvp.h;
136 0 : _wh = _w * _h;
137 0 : _wb = _w + 1; // borders are only on left and
138 0 : _hb = _h + 1; // top borders of the image
139 0 : _wbhb = _wb * _hb;
140 :
141 0 : if (static_cast<int32_t>(_mask.size()) < _wbhb)
142 : {
143 0 : _mask.resize(_wbhb);
144 :
145 : // w * h * sizeof( GL_FLOAT ) * RGBA
146 0 : _perBlockInfo.resize(_wh * 4);
147 : }
148 0 : }
149 :
150 0 : void ROIFinder::_init()
151 : {
152 0 : _areasToCheck.clear();
153 0 : memset(&_mask[0], 0, _mask.size());
154 :
155 0 : LBASSERT(static_cast<int32_t>(_perBlockInfo.size()) >= _w * _h * 4);
156 0 : LBASSERT(static_cast<int32_t>(_mask.size()) >= _wb * _h);
157 :
158 0 : const float* src = &_perBlockInfo[0];
159 0 : uint8_t* dst = &_mask[0];
160 :
161 0 : for (int32_t y = 0; y < _h; y++)
162 : {
163 0 : for (int32_t x = 0; x < _w; x++)
164 : {
165 0 : if (src[x * 4] < 1.0)
166 0 : dst[x] = 255;
167 : }
168 0 : src += _w * 4;
169 0 : dst += _wb;
170 : }
171 0 : }
172 :
173 0 : void ROIFinder::_invalidateAreas(Area* areas, uint8_t num)
174 : {
175 0 : for (uint8_t i = 0; i < num; i++)
176 0 : areas[i].valid = false;
177 0 : }
178 :
179 0 : void ROIFinder::_updateSubArea(const uint8_t type)
180 : {
181 0 : LBASSERT(type <= 16);
182 :
183 0 : if (type == 0)
184 0 : return;
185 :
186 0 : PixelViewport pvp;
187 0 : switch (type)
188 : {
189 : case 1:
190 0 : pvp = PixelViewport(_dim.x1, _dim.y2, _dim.w1, _dim.h2);
191 0 : break;
192 : case 2:
193 0 : pvp = PixelViewport(_dim.x2, _dim.y3, _dim.w2, _dim.h3);
194 0 : break;
195 : case 3:
196 0 : pvp = PixelViewport(_dim.x3, _dim.y2, _dim.w3, _dim.h2);
197 0 : break;
198 : case 4:
199 0 : pvp = PixelViewport(_dim.x2, _dim.y1, _dim.w2, _dim.h1);
200 0 : break;
201 : case 5:
202 0 : pvp = PixelViewport(_dim.x1, _dim.y1, _dim.w1, _dim.h4);
203 0 : break;
204 : case 6:
205 0 : pvp = PixelViewport(_dim.x1, _dim.y3, _dim.w4, _dim.h3);
206 0 : break;
207 : case 7:
208 0 : pvp = PixelViewport(_dim.x3, _dim.y2, _dim.w3, _dim.h5);
209 0 : break;
210 : case 8:
211 0 : pvp = PixelViewport(_dim.x2, _dim.y1, _dim.w5, _dim.h1);
212 0 : break;
213 : case 9:
214 0 : pvp = PixelViewport(_dim.x1, _dim.y2, _dim.w1, _dim.h5);
215 0 : break;
216 : case 10:
217 0 : pvp = PixelViewport(_dim.x2, _dim.y3, _dim.w5, _dim.h3);
218 0 : break;
219 : case 11:
220 0 : pvp = PixelViewport(_dim.x3, _dim.y1, _dim.w3, _dim.h4);
221 0 : break;
222 : case 12:
223 0 : pvp = PixelViewport(_dim.x1, _dim.y1, _dim.w4, _dim.h1);
224 0 : break;
225 : case 13:
226 0 : pvp = PixelViewport(_dim.x1, _dim.y1, _dim.w1, _dim.h6);
227 0 : break;
228 : case 14:
229 0 : pvp = PixelViewport(_dim.x3, _dim.y1, _dim.w3, _dim.h6);
230 0 : break;
231 : case 15:
232 0 : pvp = PixelViewport(_dim.x1, _dim.y3, _dim.w6, _dim.h3);
233 0 : break;
234 : case 16:
235 0 : pvp = PixelViewport(_dim.x1, _dim.y1, _dim.w6, _dim.h1);
236 0 : break;
237 : default:
238 0 : LBUNIMPLEMENTED;
239 : }
240 :
241 0 : LBASSERT(pvp.hasArea());
242 0 : LBASSERT(pvp.x >= 0 && pvp.y >= 0 && pvp.x + pvp.w <= _w &&
243 : pvp.y + pvp.h <= _h);
244 :
245 0 : Area& a = _tmpAreas[type];
246 :
247 0 : a.pvp = _getObjectPVP(pvp, &_mask[0]);
248 :
249 0 : a.hole = _emptyFinder.getLargestEmptyArea(a.pvp);
250 :
251 0 : a.emptySize = pvp.getArea() - a.pvp.getArea() + a.hole.getArea();
252 :
253 : #ifndef NDEBUG
254 0 : LBASSERT(!a.valid);
255 0 : a.valid = true;
256 : #endif
257 : }
258 :
259 : // positions of a hole:
260 : //
261 : // 1 7 5
262 : // 2 8 6
263 : // 0 4 3
264 : //
265 : // 0, 1, 3, 5 - corners
266 : // 2, 4, 6, 7 - sides
267 : // 8 - center
268 : //
269 :
270 : static const uint8_t _interests[10][8] = {
271 : {2, 3, 7, 10, 0, 0, 0, 0}, // corner
272 : {3, 4, 8, 11, 0, 0, 0, 0}, // corner
273 : {2, 3, 4, 7, 8, 10, 11, 14}, // side
274 : {1, 2, 6, 9, 0, 0, 0, 0}, // corner
275 : {1, 2, 3, 6, 7, 9, 10, 15}, // side
276 : {1, 4, 5, 12, 0, 0, 0, 0}, // corner
277 : {1, 2, 4, 5, 6, 9, 12, 13}, // side
278 : {1, 3, 4, 5, 8, 11, 12, 16}, // side
279 : {1, 3, 0, 0, 0, 0, 0, 0}, // vertical
280 : {2, 4, 0, 0, 0, 0, 0, 0}, // horizontal
281 : }; // center is 1..16
282 :
283 : static const uint8_t _compilNums[11][2] = {{2, 2}, {2, 2}, {4, 3}, {2, 2},
284 : {4, 3}, {2, 2}, {4, 3}, {4, 3},
285 : {1, 2}, {1, 2}, {18, 4}};
286 :
287 : static const uint8_t _compilations[10][4][3] = {
288 : {{2, 7, 0}, {3, 10, 0}, {0, 0, 0}, {0, 0, 0}}, // corner
289 : {{3, 8, 0}, {4, 11, 0}, {0, 0, 0}, {0, 0, 0}}, // corner
290 : {{2, 4, 14}, {4, 10, 11}, {3, 8, 10}, {2, 7, 8}}, // side
291 : {{1, 6, 0}, {2, 9, 0}, {0, 0, 0}, {0, 0, 0}}, // corner
292 : {{1, 3, 15}, {3, 9, 10}, {2, 7, 9}, {1, 6, 7}}, // side
293 : {{1, 12, 0}, {4, 5, 0}, {0, 0, 0}, {0, 0, 0}}, // corner
294 : {{2, 4, 13}, {4, 5, 6}, {1, 6, 12}, {2, 9, 12}}, // side
295 : {{1, 3, 16}, {1, 11, 12}, {5, 4, 11}, {3, 5, 8}}, // side
296 : {{1, 3, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, // vertical
297 : {{2, 4, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, // horizontal
298 : };
299 :
300 : static const uint8_t _compilations16[18][4] = // center
301 : {{13, 2, 4, 14}, {13, 4, 10, 11}, {13, 3, 8, 10}, {13, 2, 7, 8},
302 : {16, 1, 3, 15}, {16, 3, 9, 10}, {16, 2, 7, 9}, {16, 1, 6, 7},
303 : {14, 2, 4, 13}, {14, 4, 5, 6}, {14, 1, 6, 12}, {14, 2, 9, 12},
304 : {15, 1, 3, 16}, {15, 1, 11, 12}, {15, 5, 4, 11}, {15, 3, 5, 8},
305 : {5, 6, 7, 8}, {9, 10, 11, 12}};
306 :
307 0 : uint8_t ROIFinder::_splitArea(Area& a)
308 : {
309 0 : LBASSERT(a.hole.getArea() > 0);
310 : #ifndef NDEBUG
311 0 : _invalidateAreas(_tmpAreas, 17);
312 : #endif
313 :
314 0 : _dim.x1 = a.pvp.x;
315 0 : _dim.x2 = a.hole.x;
316 0 : _dim.x3 = a.hole.x + a.hole.w;
317 :
318 0 : _dim.w1 = _dim.x2 - _dim.x1;
319 0 : _dim.w2 = a.hole.w;
320 0 : _dim.w3 = a.pvp.x + a.pvp.w - _dim.x3;
321 0 : _dim.w4 = _dim.w1 + _dim.w2;
322 0 : _dim.w5 = _dim.w2 + _dim.w3;
323 0 : _dim.w6 = _dim.w4 + _dim.w3;
324 :
325 0 : _dim.y1 = a.pvp.y;
326 0 : _dim.y2 = a.hole.y;
327 0 : _dim.y3 = a.hole.y + a.hole.h;
328 :
329 0 : _dim.h1 = _dim.y2 - _dim.y1;
330 0 : _dim.h2 = a.hole.h;
331 0 : _dim.h3 = a.pvp.y + a.pvp.h - _dim.y3;
332 0 : _dim.h4 = _dim.h1 + _dim.h2;
333 0 : _dim.h5 = _dim.h2 + _dim.h3;
334 0 : _dim.h6 = _dim.h4 + _dim.h3;
335 :
336 : // other cases
337 : uint8_t type;
338 0 : if (a.pvp.h == a.hole.h) // hole through the whole block
339 : {
340 0 : LBASSERT(a.pvp.w != a.hole.w);
341 0 : type = 8;
342 : }
343 0 : else if (a.pvp.w == a.hole.w) // hole through the whole block
344 : {
345 0 : type = 9;
346 : }
347 0 : else if (a.pvp.x == a.hole.x) // left side
348 : {
349 0 : if (a.pvp.y == a.hole.y)
350 : // in the lower left corner
351 0 : type = 0;
352 0 : else if (a.pvp.y + a.pvp.h == a.hole.y + a.hole.h)
353 : // in the upper left corner
354 0 : type = 1;
355 : else
356 : // in the left middle
357 0 : type = 2;
358 : }
359 0 : else if (a.pvp.y == a.hole.y) // bottom side
360 : {
361 0 : if (a.pvp.x + a.pvp.w == a.hole.x + a.hole.w)
362 : // in the bottom right corner
363 0 : type = 3;
364 : else
365 : // in the bottom middle
366 0 : type = 4;
367 : }
368 0 : else if (a.pvp.x + a.pvp.w == a.hole.x + a.hole.w) // right side
369 : {
370 0 : if (a.pvp.y + a.pvp.h == a.hole.y + a.hole.h)
371 : // in the upper right corner
372 0 : type = 5;
373 : else
374 : // in the right middle
375 0 : type = 6;
376 : }
377 0 : else if (a.pvp.y + a.pvp.h == a.hole.y + a.hole.h) // top side
378 : // in the upper middle corner
379 0 : type = 7;
380 : else
381 : // must be in the center
382 0 : type = 10;
383 :
384 : // Calculate areas of interest
385 0 : if (type == 10) // center hole position
386 : {
387 0 : for (uint8_t i = 1; i <= 16; i++)
388 0 : _updateSubArea(i);
389 : }
390 : else
391 : {
392 0 : for (uint8_t i = 0; i < 8; i++)
393 0 : _updateSubArea(_interests[type][i]);
394 : }
395 :
396 : // find best combinations of areas of interest
397 0 : const uint8_t varaintsNum = _compilNums[type][0];
398 0 : const uint8_t areasPerVariant = _compilNums[type][1];
399 :
400 0 : int32_t maxSum = 0;
401 0 : int32_t variant = 0;
402 0 : if (type == 10) // center hole
403 : {
404 0 : for (uint8_t i = 0; i < varaintsNum; i++)
405 : {
406 0 : int32_t sum = 0;
407 0 : for (uint8_t j = 0; j < areasPerVariant; j++)
408 : {
409 0 : LBASSERT(_tmpAreas[_compilations16[i][j]].valid);
410 0 : sum += _tmpAreas[_compilations16[i][j]].emptySize;
411 : }
412 :
413 0 : if (sum > maxSum)
414 : {
415 0 : maxSum = sum;
416 0 : variant = i;
417 : }
418 : }
419 :
420 0 : for (uint8_t j = 0; j < areasPerVariant; j++)
421 : {
422 0 : LBASSERT(_tmpAreas[_compilations16[variant][j]].valid);
423 0 : _finalAreas[j] = _tmpAreas[_compilations16[variant][j]];
424 : }
425 :
426 0 : return areasPerVariant;
427 : }
428 : // else any other hole
429 :
430 0 : for (uint8_t i = 0; i < varaintsNum; i++)
431 : {
432 0 : int32_t sum = 0;
433 0 : for (uint8_t j = 0; j < areasPerVariant; j++)
434 : {
435 0 : LBASSERT(_tmpAreas[_compilations[type][i][j]].valid);
436 0 : sum += _tmpAreas[_compilations[type][i][j]].emptySize;
437 : }
438 :
439 0 : if (sum > maxSum)
440 : {
441 0 : maxSum = sum;
442 0 : variant = i;
443 : }
444 : }
445 :
446 0 : for (uint8_t j = 0; j < areasPerVariant; j++)
447 : {
448 0 : LBASSERT(_tmpAreas[_compilations[type][variant][j]].valid);
449 0 : _finalAreas[j] = _tmpAreas[_compilations[type][variant][j]];
450 : }
451 :
452 0 : return areasPerVariant;
453 : }
454 :
455 0 : void ROIFinder::_findAreas(PixelViewports& resultPVPs)
456 : {
457 0 : LBASSERT(_areasToCheck.empty());
458 :
459 0 : Area area(PixelViewport(0, 0, _w, _h));
460 0 : area.pvp = _getObjectPVP(area.pvp, &_mask[0]);
461 :
462 0 : if (area.pvp.w <= 0 || area.pvp.h <= 0)
463 0 : return;
464 :
465 0 : area.hole = _emptyFinder.getLargestEmptyArea(area.pvp);
466 :
467 0 : if (area.hole.getArea() == 0)
468 0 : resultPVPs.push_back(area.pvp);
469 : else
470 0 : _areasToCheck.push_back(area);
471 :
472 : // try to split areas
473 0 : while (!_areasToCheck.empty())
474 : {
475 0 : Area curArea = _areasToCheck.back();
476 0 : _areasToCheck.pop_back();
477 :
478 0 : uint8_t n = _splitArea(curArea);
479 0 : LBASSERT(n >= 2 && n <= 4);
480 :
481 0 : for (uint8_t i = 0; i < n; i++)
482 : {
483 0 : LBASSERT(_finalAreas[i].valid);
484 0 : LBASSERT(_finalAreas[i].pvp.hasArea());
485 :
486 0 : if (_finalAreas[i].hole.getArea() == 0)
487 0 : resultPVPs.push_back(_finalAreas[i].pvp);
488 : else
489 0 : _areasToCheck.push_back(_finalAreas[i]);
490 : }
491 : }
492 :
493 : // correct position and sizes
494 0 : for (uint32_t i = 0; i < resultPVPs.size(); i++)
495 : {
496 0 : PixelViewport& pvp = resultPVPs[i];
497 0 : pvp.x += _pvp.x;
498 0 : pvp.y += _pvp.y;
499 :
500 0 : pvp.apply(Zoom(GRID_SIZE, GRID_SIZE));
501 : }
502 : }
503 :
504 0 : const void* ROIFinder::_getInfoKey() const
505 : {
506 0 : return (reinterpret_cast<const char*>(this) + 3);
507 : }
508 :
509 0 : void ROIFinder::_readbackInfo(util::ObjectManager& glObjects)
510 : {
511 0 : LBASSERT(glObjects.supportsEqTexture());
512 0 : LBASSERT(glObjects.supportsEqFrameBufferObject());
513 :
514 0 : PixelViewport pvp = _pvp;
515 0 : pvp.apply(Zoom(GRID_SIZE, GRID_SIZE));
516 0 : pvp.w = LB_MIN(pvp.w + pvp.x, _pvpOriginal.w + _pvpOriginal.x) - pvp.x;
517 0 : pvp.h = LB_MIN(pvp.h + pvp.y, _pvpOriginal.h + _pvpOriginal.y) - pvp.y;
518 :
519 0 : LBASSERT(pvp.isValid());
520 :
521 : // copy frame buffer to texture
522 0 : const void* bufferKey = _getInfoKey();
523 : util::Texture* texture =
524 0 : glObjects.obtainEqTexture(bufferKey, GL_TEXTURE_RECTANGLE_ARB);
525 :
526 : #ifdef EQ_ROI_USE_DEPTH_TEXTURE
527 : texture->copyFromFrameBuffer(GL_DEPTH_COMPONENT, pvp);
528 : #else
529 0 : texture->copyFromFrameBuffer(GL_RGBA, pvp);
530 : #endif
531 :
532 : // draw zoomed quad into FBO
533 0 : const void* fboKey = _getInfoKey();
534 0 : util::FrameBufferObject* fbo = glObjects.getEqFrameBufferObject(fboKey);
535 :
536 0 : if (fbo)
537 : {
538 0 : LBCHECK(fbo->resize(_pvp.w, _pvp.h));
539 : }
540 : else
541 : {
542 0 : fbo = glObjects.newEqFrameBufferObject(fboKey);
543 0 : LBCHECK(fbo->init(_pvp.w, _pvp.h, GL_RGBA32F, 0, 0));
544 : }
545 0 : fbo->bind();
546 :
547 0 : texture->bind();
548 :
549 : // Enable & download depth texture
550 0 : glEnable(GL_TEXTURE_RECTANGLE_ARB);
551 :
552 0 : texture->applyWrap();
553 0 : texture->applyZoomFilter(FILTER_LINEAR);
554 :
555 : // Enable shaders
556 0 : GLuint program = glObjects.getProgram(shaderRBInfo);
557 0 : if (program == util::ObjectManager::INVALID)
558 : {
559 : // Create fragment shader which reads depth values from
560 : // rectangular textures
561 : const GLuint shader =
562 0 : glObjects.newShader(shaderRBInfo, GL_FRAGMENT_SHADER);
563 0 : LBASSERT(shader != util::ObjectManager::INVALID);
564 :
565 : #ifdef EQ_ROI_USE_DEPTH_TEXTURE
566 : const GLchar* fShaderPtr = roiFragmentShader_glsl.c_str();
567 : #else
568 0 : const GLchar* fShaderPtr = roiFragmentShaderRGB_glsl.c_str();
569 : #endif
570 0 : LBCHECK(util::shader::compile(glewGetContext(), shader, fShaderPtr));
571 0 : program = glObjects.newProgram(shaderRBInfo);
572 :
573 0 : EQ_GL_CALL(glAttachShader(program, shader));
574 0 : EQ_GL_CALL(glLinkProgram(program));
575 :
576 : GLint status;
577 0 : glGetProgramiv(program, GL_LINK_STATUS, &status);
578 0 : if (!status)
579 : {
580 0 : LBWARN << "Failed to link shader program for ROI finder"
581 0 : << std::endl;
582 0 : return;
583 : }
584 :
585 : // use fragment shader and setup uniforms
586 0 : EQ_GL_CALL(glUseProgram(program));
587 :
588 0 : GLint param = glGetUniformLocation(program, "texture");
589 0 : glUniform1i(param, 0);
590 : }
591 : else
592 : {
593 : // use fragment shader
594 0 : EQ_GL_CALL(glUseProgram(program));
595 : }
596 :
597 : // Draw Quad
598 0 : glDisable(GL_LIGHTING);
599 0 : glColor3f(1.0f, 1.0f, 1.0f);
600 :
601 0 : glBegin(GL_QUADS);
602 0 : glVertex3i(0, 0, 0);
603 0 : glVertex3i(_pvp.w, 0, 0);
604 0 : glVertex3i(_pvp.w, _pvp.h, 0);
605 0 : glVertex3i(0, _pvp.h, 0);
606 0 : glEnd();
607 :
608 : // restore state
609 0 : glDisable(GL_TEXTURE_RECTANGLE_ARB);
610 0 : EQ_GL_CALL(glUseProgram(0));
611 :
612 0 : fbo->unbind();
613 :
614 : // finish readback of info
615 0 : LBASSERT(static_cast<int32_t>(_perBlockInfo.size()) >= _pvp.w * _pvp.h * 4);
616 :
617 0 : texture = fbo->getColorTextures()[0];
618 0 : LBASSERT(texture->getFormat() == GL_RGBA);
619 0 : LBASSERT(texture->getType() == GL_FLOAT);
620 0 : texture->download(&_perBlockInfo[0]);
621 : }
622 :
623 0 : static PixelViewport _getBoundingPVP(const PixelViewport& pvp)
624 : {
625 0 : PixelViewport pvp_;
626 :
627 0 : pvp_.x = (pvp.x / GRID_SIZE);
628 0 : pvp_.y = (pvp.y / GRID_SIZE);
629 :
630 0 : pvp_.w = ((pvp.x + pvp.w + GRID_SIZE - 1) / GRID_SIZE) - pvp_.x;
631 0 : pvp_.h = ((pvp.y + pvp.h + GRID_SIZE - 1) / GRID_SIZE) - pvp_.y;
632 :
633 0 : return pvp_;
634 : }
635 :
636 0 : PixelViewports ROIFinder::findRegions(const uint32_t buffers,
637 : const PixelViewport& pvp,
638 : const Zoom& zoom, const uint32_t stage,
639 : const uint128_t& frameID,
640 : util::ObjectManager& glObjects)
641 : {
642 0 : PixelViewports result;
643 0 : result.push_back(pvp);
644 :
645 0 : LBLOG(LOG_ASSEMBLY) << "ROIFinder::getObjects " << pvp << ", buffers "
646 0 : << buffers << std::endl;
647 :
648 0 : if (zoom != Zoom::NONE)
649 : {
650 0 : LBWARN << "R-B optimization impossible when zoom is used" << std::endl;
651 0 : return result;
652 : }
653 :
654 : #ifdef EQ_ROI_USE_TRACKER
655 : uint8_t* ticket;
656 0 : if (!_roiTracker.useROIFinder(pvp, stage, frameID, ticket))
657 0 : return result;
658 : #endif
659 :
660 0 : _pvpOriginal = pvp;
661 0 : _resize(_getBoundingPVP(pvp));
662 :
663 : // go through depth buffer and check min/max/BG values
664 : // render to and read-back usefull info from FBO
665 0 : _readbackInfo(glObjects);
666 0 : glObjects.clear();
667 :
668 : // Analyze readed back data and find regions of interest
669 0 : _init();
670 :
671 0 : _emptyFinder.update(&_mask[0], _wb, _hb);
672 0 : _emptyFinder.setLimits(200, 0.002f);
673 :
674 0 : result.clear();
675 0 : _findAreas(result);
676 :
677 : #ifdef EQ_ROI_USE_TRACKER
678 0 : _roiTracker.updateDelay(result, ticket);
679 : #endif
680 :
681 0 : return result;
682 : }
683 30 : }
|