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