Equalizer  1.8.0
Parallel Rendering Framework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
eqPly/channel.cpp
1 
2 /* Copyright (c) 2006-2014, Stefan Eilemann <eile@equalizergraphics.com>
3  * 2011-2012, Daniel Nachbaur <danielnachbaur@gmail.com>
4  * 2010, Cedric Stalder <cedric.stalder@gmail.com>
5  * 2007, Tobias Wolf <twolf@access.unizh.ch>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  * - Neither the name of Eyescale Software GmbH nor the names of its
16  * contributors may be used to endorse or promote products derived from this
17  * software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "channel.h"
33 
34 #include "initData.h"
35 #include "config.h"
36 #include "configEvent.h"
37 #include "pipe.h"
38 #include "view.h"
39 #include "window.h"
40 #include "vertexBufferState.h"
41 
42 // light parameters
43 static GLfloat lightPosition[] = {0.0f, 0.0f, 1.0f, 0.0f};
44 static GLfloat lightAmbient[] = {0.1f, 0.1f, 0.1f, 1.0f};
45 static GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
46 static GLfloat lightSpecular[] = {0.8f, 0.8f, 0.8f, 1.0f};
47 
48 // material properties
49 static GLfloat materialAmbient[] = {0.2f, 0.2f, 0.2f, 1.0f};
50 static GLfloat materialDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
51 static GLfloat materialSpecular[] = {0.5f, 0.5f, 0.5f, 1.0f};
52 static GLint materialShininess = 64;
53 
54 #ifndef M_SQRT3_2
55 # define M_SQRT3_2 0.86603f /* sqrt(3)/2 */
56 #endif
57 
58 namespace eqPly
59 {
60 
61 Channel::Channel( eq::Window* parent )
62  : eq::Channel( parent )
63  , _model(0)
64  , _frameRestart( 0 )
65 {
66 }
67 
68 bool Channel::configInit( const eq::uint128_t& initID )
69 {
70  if( !eq::Channel::configInit( initID ))
71  return false;
72 
73  setNearFar( 0.1f, 10.0f );
74  _model = 0;
75  _modelID = 0;
76  return true;
77 }
78 
80 {
81  for( size_t i = 0; i < eq::NUM_EYES; ++i )
82  {
83  delete _accum[ i ].buffer;
84  _accum[ i ].buffer = 0;
85  }
86 
87  return eq::Channel::configExit();
88 }
89 
90 void Channel::frameClear( const eq::uint128_t& /*frameID*/ )
91 {
92  if( stopRendering( ))
93  return;
94 
95  _initJitter();
96  resetRegions();
97 
98  const FrameData& frameData = _getFrameData();
99  const int32_t eyeIndex = lunchbox::getIndexOfLastBit( getEye() );
100  if( _isDone() && !_accum[ eyeIndex ].transfer )
101  return;
102 
103  applyBuffer();
104  applyViewport();
105 
106  const eq::View* view = getView();
107  if( view && frameData.getCurrentViewID() == view->getID( ))
108  glClearColor( 1.f, 1.f, 1.f, 0.f );
109 #ifndef NDEBUG
110  else if( getenv( "EQ_TAINT_CHANNELS" ))
111  {
112  const eq::Vector3ub color = getUniqueColor();
113  glClearColor( color.r()/255.f, color.g()/255.f, color.b()/255.f, 0.f );
114  }
115 #endif // NDEBUG
116  else
117  glClearColor( 0.f, 0.f, 0.f, 0.0f );
118 
119  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
120 }
121 
122 void Channel::frameDraw( const eq::uint128_t& frameID )
123 {
124  if( stopRendering( ))
125  return;
126 
127  _initJitter();
128  if( _isDone( ))
129  return;
130 
131  Window* window = static_cast< Window* >( getWindow( ));
132  VertexBufferState& state = window->getState();
133  const Model* oldModel = _model;
134  const Model* model = _getModel();
135 
136  if( oldModel != model )
137  state.setFrustumCulling( false ); // create all display lists/VBOs
138 
139  if( model )
140  _updateNearFar( model->getBoundingSphere( ));
141 
142  eq::Channel::frameDraw( frameID ); // Setup OpenGL state
143 
144  glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );
145  glLightfv( GL_LIGHT0, GL_AMBIENT, lightAmbient );
146  glLightfv( GL_LIGHT0, GL_DIFFUSE, lightDiffuse );
147  glLightfv( GL_LIGHT0, GL_SPECULAR, lightSpecular );
148 
149  glMaterialfv( GL_FRONT, GL_AMBIENT, materialAmbient );
150  glMaterialfv( GL_FRONT, GL_DIFFUSE, materialDiffuse );
151  glMaterialfv( GL_FRONT, GL_SPECULAR, materialSpecular );
152  glMateriali( GL_FRONT, GL_SHININESS, materialShininess );
153 
154  const FrameData& frameData = _getFrameData();
155  glPolygonMode( GL_FRONT_AND_BACK,
156  frameData.useWireframe() ? GL_LINE : GL_FILL );
157 
158  const eq::Vector3f& position = frameData.getCameraPosition();
159 
160  glMultMatrixf( frameData.getCameraRotation().array );
161  glTranslatef( position.x(), position.y(), position.z() );
162  glMultMatrixf( frameData.getModelRotation().array );
163 
164  if( frameData.getColorMode() == COLOR_DEMO )
165  {
166  const eq::Vector3ub color = getUniqueColor();
167  glColor3ub( color.r(), color.g(), color.b() );
168  }
169  else
170  glColor3f( .75f, .75f, .75f );
171 
172  if( model )
173  _drawModel( model );
174  else
175  {
176  glNormal3f( 0.f, -1.f, 0.f );
177  glBegin( GL_TRIANGLE_STRIP );
178  glVertex3f( .25f, 0.f, .25f );
179  glVertex3f( -.25f, 0.f, .25f );
180  glVertex3f( .25f, 0.f, -.25f );
181  glVertex3f( -.25f, 0.f, -.25f );
182  glEnd();
183  }
184 
185  state.setFrustumCulling( true );
186  Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ];
187  accum.stepsDone = LB_MAX( accum.stepsDone,
188  getSubPixel().size * getPeriod( ));
189  accum.transfer = true;
190 }
191 
192 void Channel::frameAssemble( const eq::uint128_t& frameID,
193  const eq::Frames& frames )
194 {
195  if( stopRendering( ))
196  return;
197 
198  if( _isDone( ))
199  return;
200 
201  Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ];
202 
203  if( getPixelViewport() != _currentPVP )
204  {
205  accum.transfer = true;
206 
207  if( accum.buffer && !accum.buffer->usesFBO( ))
208  {
209  LBWARN << "Current viewport different from view viewport, "
210  << "idle anti-aliasing not implemented." << std::endl;
211  accum.step = 0;
212  }
213 
214  eq::Channel::frameAssemble( frameID, frames );
215  return;
216  }
217  // else
218 
219  accum.transfer = true;
220  for( eq::Frames::const_iterator i = frames.begin(); i != frames.end(); ++i )
221  {
222  eq::Frame* frame = *i;
223  const eq::SubPixel& curSubPixel = frame->getSubPixel();
224 
225  if( curSubPixel != eq::SubPixel::ALL )
226  accum.transfer = false;
227 
228  accum.stepsDone = LB_MAX( accum.stepsDone, frame->getSubPixel().size *
229  frame->getPeriod( ));
230  }
231 
232  applyBuffer();
233  applyViewport();
235 
236  try
237  {
238  eq::Compositor::assembleFrames( frames, this, accum.buffer );
239  }
240  catch( const co::Exception& e )
241  {
242  LBWARN << e.what() << std::endl;
243  }
244 
246 }
247 
248 void Channel::frameReadback( const eq::uint128_t& frameID,
249  const eq::Frames& frames )
250 {
251  if( stopRendering() || _isDone( ))
252  return;
253 
254  const FrameData& frameData = _getFrameData();
255  for( eq::FramesCIter i = frames.begin(); i != frames.end(); ++i )
256  {
257  eq::Frame* frame = *i;
258  // OPT: Drop alpha channel from all frames during network transport
259  frame->setAlphaUsage( false );
260 
261  if( frameData.isIdle( ))
262  frame->setQuality( eq::Frame::BUFFER_COLOR, 1.f );
263  else
264  frame->setQuality( eq::Frame::BUFFER_COLOR, frameData.getQuality());
265 
266  if( frameData.useCompression( ))
267  frame->useCompressor( eq::Frame::BUFFER_COLOR, EQ_COMPRESSOR_AUTO );
268  else
269  frame->useCompressor( eq::Frame::BUFFER_COLOR, EQ_COMPRESSOR_NONE );
270  }
271 
272  eq::Channel::frameReadback( frameID, frames );
273 }
274 
275 void Channel::frameStart( const eq::uint128_t& frameID,
276  const uint32_t frameNumber )
277 {
278  if( stopRendering( ))
279  return;
280 
281  for( size_t i = 0; i < eq::NUM_EYES; ++i )
282  _accum[ i ].stepsDone = 0;
283 
284  eq::Channel::frameStart( frameID, frameNumber );
285 }
286 
287 void Channel::frameViewStart( const eq::uint128_t& frameID )
288 {
289  if( stopRendering( ))
290  return;
291 
292  _currentPVP = getPixelViewport();
293  _initJitter();
294  eq::Channel::frameViewStart( frameID );
295 }
296 
297 void Channel::frameFinish( const eq::uint128_t& frameID,
298  const uint32_t frameNumber )
299 {
300  if( stopRendering( ))
301  return;
302 
303  for( size_t i = 0; i < eq::NUM_EYES; ++i )
304  {
305  Accum& accum = _accum[ i ];
306  if( accum.step > 0 )
307  {
308  if( int32_t( accum.stepsDone ) > accum.step )
309  accum.step = 0;
310  else
311  accum.step -= accum.stepsDone;
312  }
313  }
314 
315  eq::Channel::frameFinish( frameID, frameNumber );
316 }
317 
318 void Channel::frameViewFinish( const eq::uint128_t& frameID )
319 {
320  if( stopRendering( ))
321  return;
322 
323  applyBuffer();
324 
325  const FrameData& frameData = _getFrameData();
326  Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ];
327 
328  if( accum.buffer )
329  {
330  const eq::PixelViewport& pvp = getPixelViewport();
331  const bool isResized = accum.buffer->resize( pvp );
332 
333  if( isResized )
334  {
335  const View* view = static_cast< const View* >( getView( ));
336  accum.buffer->clear();
337  accum.step = view->getIdleSteps();
338  accum.stepsDone = 0;
339  }
340  else if( frameData.isIdle( ))
341  {
343 
344  if( !_isDone() && accum.transfer )
345  accum.buffer->accum();
346  accum.buffer->display();
347 
349  }
350  }
351 
352  applyViewport();
353  _drawOverlay();
354  _drawHelp();
355 
356  if( frameData.useStatistics())
357  drawStatistics();
358 
359  int32_t steps = 0;
360  if( frameData.isIdle( ))
361  {
362  for( size_t i = 0; i < eq::NUM_EYES; ++i )
363  steps = LB_MAX( steps, _accum[i].step );
364  }
365  else
366  {
367  const View* view = static_cast< const View* >( getView( ));
368  steps = view ? view->getIdleSteps() : 0;
369  }
370 
371  // if _jitterStep == 0 and no user redraw event happened, the app will exit
372  // FSAA idle mode and block on the next redraw event.
373  eq::Config* config = getConfig();
374  config->sendEvent( IDLE_AA_LEFT ) << steps;
375 
376  eq::Channel::frameViewFinish( frameID );
377 }
378 
379 bool Channel::useOrtho() const
380 {
381  const FrameData& frameData = _getFrameData();
382  return frameData.useOrtho();
383 }
384 
385 const FrameData& Channel::_getFrameData() const
386 {
387  const Pipe* pipe = static_cast<const Pipe*>( getPipe( ));
388  return pipe->getFrameData();
389 }
390 
391 bool Channel::_isDone() const
392 {
393  const FrameData& frameData = _getFrameData();
394  if( !frameData.isIdle( ))
395  return false;
396 
397  const eq::SubPixel& subpixel = getSubPixel();
398  const Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ];
399  return int32_t( subpixel.index ) >= accum.step;
400 }
401 
402 void Channel::_initJitter()
403 {
404  if( !_initAccum( ))
405  return;
406 
407  const FrameData& frameData = _getFrameData();
408  if( frameData.isIdle( ))
409  return;
410 
411  const View* view = static_cast< const View* >( getView( ));
412  if( !view )
413  return;
414 
415  const int32_t idleSteps = view->getIdleSteps();
416  if( idleSteps == 0 )
417  return;
418 
419  // ready for the next FSAA
420  Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ];
421  if( accum.buffer )
422  accum.buffer->clear();
423  accum.step = idleSteps;
424 }
425 
426 bool Channel::_initAccum()
427 {
428  View* view = static_cast< View* >( getNativeView( ));
429  if( !view ) // Only alloc accum for dest
430  return true;
431 
432  const eq::Eye eye = getEye();
433  Accum& accum = _accum[ lunchbox::getIndexOfLastBit( eye ) ];
434 
435  if( accum.buffer ) // already done
436  return true;
437 
438  if( accum.step == -1 ) // accum init failed last time
439  return false;
440 
441  // Check unsupported cases
443  {
444  for( size_t i = 0; i < eq::NUM_EYES; ++i )
445  {
446  if( _accum[ i ].buffer )
447  {
448  LBWARN << "glAccum-based accumulation does not support "
449  << "stereo, disabling idle anti-aliasing."
450  << std::endl;
451  for( size_t j = 0; j < eq::NUM_EYES; ++j )
452  {
453  delete _accum[ j ].buffer;
454  _accum[ j ].buffer = 0;
455  _accum[ j ].step = -1;
456  }
457 
458  view->setIdleSteps( 0 );
459  return false;
460  }
461  }
462  }
463 
464  // set up accumulation buffer
465  accum.buffer = new eq::util::Accum( glewGetContext( ));
466  const eq::PixelViewport& pvp = getPixelViewport();
467  LBASSERT( pvp.isValid( ));
468 
469  if( !accum.buffer->init( pvp, getWindow()->getColorFormat( )) ||
470  accum.buffer->getMaxSteps() < 256 )
471  {
472  LBWARN <<"Accumulation buffer initialization failed, "
473  << "idle AA not available." << std::endl;
474  delete accum.buffer;
475  accum.buffer = 0;
476  accum.step = -1;
477  return false;
478  }
479 
480  // else
481  LBVERB << "Initialized "
482  << (accum.buffer->usesFBO() ? "FBO accum" : "glAccum")
483  << " buffer for " << getName() << " " << getEye()
484  << std::endl;
485 
486  view->setIdleSteps( accum.buffer ? 256 : 0 );
487  return true;
488 }
489 
490 bool Channel::stopRendering() const
491 {
492  return getPipe()->getCurrentFrame() < _frameRestart;
493 }
494 
495 eq::Vector2f Channel::getJitter() const
496 {
497  const FrameData& frameData = _getFrameData();
498  const Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ];
499 
500  if( !frameData.isIdle() || accum.step <= 0 )
501  return eq::Channel::getJitter();
502 
503  const View* view = static_cast< const View* >( getView( ));
504  if( !view || view->getIdleSteps() != 256 )
505  return eq::Vector2f::ZERO;
506 
507  const eq::Vector2i jitterStep = _getJitterStep();
508  if( jitterStep == eq::Vector2i::ZERO )
509  return eq::Vector2f::ZERO;
510 
511  const eq::PixelViewport& pvp = getPixelViewport();
512  const float pvp_w = float( pvp.w );
513  const float pvp_h = float( pvp.h );
514  const float frustum_w = float(( getFrustum().get_width( )));
515  const float frustum_h = float(( getFrustum().get_height( )));
516 
517  const float pixel_w = frustum_w / pvp_w;
518  const float pixel_h = frustum_h / pvp_h;
519 
520  const float sampleSize = 16.f; // sqrt( 256 )
521  const float subpixel_w = pixel_w / sampleSize;
522  const float subpixel_h = pixel_h / sampleSize;
523 
524  // Sample value randomly computed within the subpixel
525  lunchbox::RNG rng;
526  const eq::Pixel& pixel = getPixel();
527 
528  const float i = ( rng.get< float >() * subpixel_w +
529  float( jitterStep.x( )) * subpixel_w ) / float( pixel.w );
530  const float j = ( rng.get< float >() * subpixel_h +
531  float( jitterStep.y( )) * subpixel_h ) / float( pixel.h );
532 
533  return eq::Vector2f( i, j );
534 }
535 
536 static const uint32_t _primes[100] = {
537  739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
538  839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
539  947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033,
540  1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109,
541  1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213,
542  1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
543  1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399,
544  1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451 };
545 
546 eq::Vector2i Channel::_getJitterStep() const
547 {
548  const eq::SubPixel& subPixel = getSubPixel();
549  const uint32_t channelID = subPixel.index;
550  const View* view = static_cast< const View* >( getView( ));
551  if( !view )
552  return eq::Vector2i::ZERO;
553 
554  const uint32_t totalSteps = uint32_t( view->getIdleSteps( ));
555  if( totalSteps != 256 )
556  return eq::Vector2i::ZERO;
557 
558  const Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ];
559  const uint32_t subset = totalSteps / getSubPixel().size;
560  const uint32_t index = ( accum.step * _primes[ channelID % 100 ] )%subset +
561  ( channelID * subset );
562  const uint32_t sampleSize = 16;
563  const int dx = index % sampleSize;
564  const int dy = index / sampleSize;
565 
566  return eq::Vector2i( dx, dy );
567 }
568 
569 const Model* Channel::_getModel()
570 {
571  Config* config = static_cast< Config* >( getConfig( ));
572  const View* view = static_cast< const View* >( getView( ));
573  const FrameData& frameData = _getFrameData();
574  LBASSERT( !view || dynamic_cast< const View* >( getView( )));
575 
576  eq::uint128_t id = view ? view->getModelID() : frameData.getModelID();
577  if( id == 0 )
578  id = frameData.getModelID();
579  if( id != _modelID )
580  {
581  _model = config->getModel( id );
582  _modelID = id;
583  }
584 
585  return _model;
586 }
587 
588 void Channel::_drawModel( const Model* scene )
589 {
590  Window* window = static_cast< Window* >( getWindow( ));
591  VertexBufferState& state = window->getState();
592  const FrameData& frameData = _getFrameData();
593 
594  if( frameData.getColorMode() == COLOR_MODEL && scene->hasColors( ))
595  state.setColors( true );
596  else
597  state.setColors( false );
598  state.setChannel( this );
599 
600  // Compute cull matrix
601  const eq::Matrix4f& rotation = frameData.getCameraRotation();
602  const eq::Matrix4f& modelRotation = frameData.getModelRotation();
603  eq::Matrix4f position = eq::Matrix4f::IDENTITY;
604  position.set_translation( frameData.getCameraPosition());
605 
606  const eq::Frustumf& frustum = getFrustum();
607  const eq::Matrix4f projection = useOrtho() ? frustum.compute_ortho_matrix():
608  frustum.compute_matrix();
609  const eq::Matrix4f& view = getHeadTransform();
610  const eq::Matrix4f model = rotation * position * modelRotation;
611 
612  state.setProjectionModelViewMatrix( projection * view * model );
613  state.setRange( &getRange().start);
614 
615  const eq::Pipe* pipe = getPipe();
616  const GLuint program = state.getProgram( pipe );
617  if( program != VertexBufferState::INVALID )
618  glUseProgram( program );
619 
620  scene->cullDraw( state );
621 
622  state.setChannel( 0 );
623  if( program != VertexBufferState::INVALID )
624  glUseProgram( 0 );
625 
626  const InitData& initData =
627  static_cast<Config*>( getConfig( ))->getInitData();
628  if( initData.useROI( ))
629  // declare empty region in case nothing is in frustum
630  declareRegion( eq::PixelViewport( ));
631  else
633 
634 #ifndef NDEBUG
635  outlineViewport();
636 #endif
637 }
638 
639 void Channel::_drawOverlay()
640 {
641  // Draw the overlay logo
642  const Window* window = static_cast<Window*>( getWindow( ));
643  const eq::util::Texture* texture = window->getLogoTexture();
644  if( !texture )
645  return;
646 
647  glMatrixMode( GL_PROJECTION );
648  glLoadIdentity();
650  glMatrixMode( GL_MODELVIEW );
651  glLoadIdentity();
652 
653  glDisable( GL_DEPTH_TEST );
654  glDisable( GL_LIGHTING );
655  glColor3f( 1.0f, 1.0f, 1.0f );
656  glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
657 
658  // logo
659  glEnable( GL_BLEND );
660  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
661  const GLenum target = texture->getTarget();
662  glEnable( target );
663  texture->bind();
664  glTexParameteri( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
665  glTexParameteri( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
666 
667  const float tWidth = float( texture->getWidth( ) );
668  const float tHeight = float( texture->getHeight( ) );
669 
670  const float width = target == GL_TEXTURE_2D ? 1.0f : tWidth;
671  const float height = target == GL_TEXTURE_2D ? 1.0f : tHeight;
672 
673  glBegin( GL_QUADS ); {
674  glTexCoord2f( 0, 0 );
675  glVertex3f( 5.0f, 5.0f, 0.0f );
676 
677  glTexCoord2f( width, 0 );
678  glVertex3f( tWidth + 5.0f, 5.0f, 0.0f );
679 
680  glTexCoord2f( width, height );
681  glVertex3f( tWidth + 5.0f, tHeight + 5.0f, 0.0f );
682 
683  glTexCoord2f( 0, height );
684  glVertex3f( 5.0f, tHeight + 5.0f, 0.0f );
685 
686  } glEnd();
687 
688  glDisable( target );
689  glDisable( GL_BLEND );
690  glEnable( GL_LIGHTING );
691  glEnable( GL_DEPTH_TEST );
692 }
693 
694 void Channel::_drawHelp()
695 {
696  const FrameData& frameData = _getFrameData();
697  std::string message = frameData.getMessage();
698 
699  if( !frameData.showHelp() && message.empty( ))
700  return;
701 
702  applyBuffer();
703  applyViewport();
705 
706  glLogicOp( GL_XOR );
707  glEnable( GL_COLOR_LOGIC_OP );
708  glDisable( GL_LIGHTING );
709  glDisable( GL_DEPTH_TEST );
710 
711  glColor3f( 1.f, 1.f, 1.f );
712 
713  const eq::PixelViewport& pvp = getPixelViewport();
714  const eq::Viewport& vp = getViewport();
715  const float height = pvp.h / vp.h;
716 
717  if( !message.empty( ))
718  {
719  const eq::util::BitmapFont* font = getWindow()->getMediumFont();
720 
721  const float width = pvp.w / vp.w;
722  const float xOffset = vp.x * width;
723 
724  const float yOffset = vp.y * height;
725  const float yPos = 0.618f * height;
726  float y = yPos - yOffset;
727 
728  for( size_t pos = message.find( '\n' ); pos != std::string::npos;
729  pos = message.find( '\n' ))
730  {
731  glRasterPos3f( 10.f - xOffset, y, 0.99f );
732  font->draw( message.substr( 0, pos ));
733  message = message.substr( pos + 1 );
734  y -= 22.f;
735  }
736  // last line
737  glRasterPos3f( 10.f - xOffset, y, 0.99f );
738  font->draw( message );
739  }
740 
741  glMatrixMode( GL_PROJECTION );
742  glLoadIdentity();
744  glMatrixMode( GL_MODELVIEW );
745 
746  if( frameData.showHelp( ))
747  {
748  const eq::util::BitmapFont* font = getWindow()->getSmallFont();
749  std::string help = EqPly::getHelp();
750  float y = height - 16.f;
751 
752  for( size_t pos = help.find( '\n' ); pos != std::string::npos;
753  pos = help.find( '\n' ))
754  {
755  glRasterPos3f( 10.f, y, 0.99f );
756 
757  font->draw( help.substr( 0, pos ));
758  help = help.substr( pos + 1 );
759  y -= 16.f;
760  }
761  // last line
762  glRasterPos3f( 10.f, y, 0.99f );
763  font->draw( help );
764  }
765 
767 }
768 
769 void Channel::_updateNearFar( const triply::BoundingSphere& boundingSphere )
770 {
771  // compute dynamic near/far plane of whole model
772  const FrameData& frameData = _getFrameData();
773  const eq::Matrix4f& rotation = frameData.getCameraRotation();
774  const eq::Matrix4f& view = getHeadTransform() * rotation;
775 
776  eq::Matrix4f viewInv;
777  compute_inverse( view, viewInv );
778 
779  const eq::Vector3f& zero = viewInv * eq::Vector3f::ZERO;
780  eq::Vector3f front = viewInv * eq::Vector3f( 0.0f, 0.0f, -1.0f );
781 
782  front -= zero;
783  front.normalize();
784  front *= boundingSphere.w();
785 
786  const eq::Vector3f& center = frameData.getCameraPosition() -
787  boundingSphere.get_sub_vector< 3 >();
788  const eq::Vector3f nearPoint = view * ( center - front );
789  const eq::Vector3f farPoint = view * ( center + front );
790 
791  if( useOrtho( ))
792  {
793  LBASSERTINFO( fabs( farPoint.z() - nearPoint.z() ) >
794  std::numeric_limits< float >::epsilon(),
795  nearPoint << " == " << farPoint );
796  setNearFar( -nearPoint.z(), -farPoint.z() );
797  }
798  else
799  {
800  // estimate minimal value of near plane based on frustum size
801  const eq::Frustumf& frustum = getFrustum();
802  const float width = fabs( frustum.right() - frustum.left() );
803  const float height = fabs( frustum.top() - frustum.bottom() );
804  const float size = LB_MIN( width, height );
805  const float minNear = frustum.near_plane() / size * .001f;
806 
807  const float zNear = LB_MAX( minNear, -nearPoint.z() );
808  const float zFar = LB_MAX( zNear * 2.f, -farPoint.z() );
809 
810  setNearFar( zNear, zFar );
811  }
812 }
813 
814 }
virtual EQ_API void frameFinish(const uint128_t &frameID, const uint32_t frameNumber)
Finish rendering a frame.
const PixelViewport & getPixelViewport() const
virtual EQ_API Vector2f getJitter() const
static uint32_t assembleFrames(const Frames &frames, Channel *channel, util::Accum *accum)
Assemble all frames in an arbitrary order using the fastest implemented algorithm on the given channe...
virtual EQ_API void frameReadback(const uint128_t &frameID, const Frames &frames)
Read back the rendered frame buffer into the output frames.
virtual EQ_API void outlineViewport()
Outline the current pixel viewport.
The representation of one GPU.
A C++ class to abstract an accumulation buffer.
Definition: accum.h:39
A configuration is a visualization session driven by an application.
EQ_API uint32_t getCurrentFrame() const
Return the current frame number.
virtual void frameDraw(const eq::uint128_t &frameID)
Draw the scene.
EQ_API const SubPixel & getSubPixel() const
virtual EQ_API void frameStart(const uint128_t &frameID, const uint32_t frameNumber)
Start rendering a frame.
EQ_API void applyScreenFrustum() const
Apply an orthographic frustum for pixel-based 2D operations.
virtual EQ_API bool configInit(const uint128_t &initID)
Initialize this channel.
virtual EQ_API void frameDraw(const uint128_t &frameID)
Draw the scene.
EQ_API void bind() const
Bind the texture.
A Pipe represents a graphics card (GPU) on a Node.
A wrapper around AGL, WGL and GLX bitmap fonts.
Definition: bitmapFont.h:31
virtual EQ_API void applyViewport() const
Apply the OpenGL viewport for the current rendering task.
A wrapper around OpenGL textures.
Definition: texture.h:38
EQFABRIC_INL void setNearFar(const float nearPlane, const float farPlane)
Set the near and far planes for this channel.
virtual void frameStart(const eq::uint128_t &frameID, const uint32_t frameNumber)
Start rendering a frame.
EQ_API void sendEvent(ConfigEvent &event)
Send an (old) event to the application node.
virtual bool configExit()
Exit this channel.
EQ_API void draw(const std::string &text) const
Draw text on the current raster position.
EQ_API bool usesFBO() const
Test if the accumulation uses the FBO implementation.
EQ_API void setAlphaUsage(const bool useAlpha)
Set alpha usage for newly allocated images.
EQ_API void useCompressor(const Frame::Buffer buffer, const uint32_t name)
Sets a compressor for compression for following transmissions.
EQ_API void setQuality(const Frame::Buffer buffer, const float quality)
Set the minimum quality after compression.
EQFABRIC_API const std::string & getName() const
A Window represents an on-screen or off-screen drawable.
virtual bool useOrtho() const
Select perspective or orthographic rendering.
EQ_API Config * getConfig()
EQ_API const GLEWContext * glewGetContext() const
Get the GLEW context for this channel.
virtual EQ_API void frameViewStart(const uint128_t &frameID)
Start updating a destination channel.
EQ_API const Vector3ub & getUniqueColor() const
EQ_API View * getNativeView()
Get the channel's native view.
virtual EQ_API void frameClear(const uint128_t &frameID)
Clear the frame buffer.
virtual EQ_API void drawStatistics()
Draw a statistics overlay.
EQ_API Pipe * getPipe()
virtual EQ_API bool configExit()
Exit this channel.
std::vector< Frame * > Frames
A vector of pointers to eq::Frame.
A View is a 2D area of a Layout.
A window represent an OpenGL drawable and context.
virtual EQ_API void resetRegions()
Reset the declared regions of interest.
Frames::const_iterator FramesCIter
A const_iterator over a eq::Frame vector.
uint32_t size
Total number of contributors.
Definition: subPixel.h:103
EQ_API View * getView()
Get the channel's current View.
const Matrix4f & getHeadTransform() const
Return the view matrix.
virtual EQ_API void frameViewFinish(const uint128_t &frameID)
Finish updating a destination channel.
EQ_API int32_t getWidth() const
EQ_API int32_t getHeight() const
virtual EQ_API void setupAssemblyState()
Setup the OpenGL state for a readback or assemble operation.
EQ_API unsigned getTarget() const
A holder for a frame data and related parameters.
Definition: client/frame.h:42
virtual EQ_API void applyBuffer()
Apply the current rendering buffer, including the color mask.
virtual EQ_API void frameAssemble(const uint128_t &frameID, const Frames &frames)
Assemble all input frames.
virtual EQ_API void resetAssemblyState()
Reset the OpenGL state after an assembly operation.
Render using the colors defined in the ply file.
Definition: eVolve.h:65
virtual EQ_API void declareRegion(const eq::PixelViewport &region)
Declare a region covered by the current draw or assemble operation.
EQ_API uint32_t getPeriod() const