Equalizer  1.6.1
eVolve/channel.cpp
1 
2 /* Copyright (c) 2006-2012, Stefan Eilemann <eile@equalizergraphics.com>
3  * 2007-2011, Maxim Makhinya <maxmah@gmail.com>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright notice, this
9  * list of conditions and the following disclaimer.
10  * - Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  * - Neither the name of Eyescale Software GmbH nor the names of its
14  * contributors may be used to endorse or promote products derived from this
15  * software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "channel.h"
31 
32 #include "frameData.h"
33 #include "initData.h"
34 #include "node.h"
35 #include "pipe.h"
36 #include "window.h"
37 #include "hlp.h"
38 #include "framesOrderer.h"
39 
40 namespace eVolve
41 {
42 Channel::Channel( eq::Window* parent )
43  : eq::Channel( parent )
44  , _bgColor( eq::Vector3f::ZERO )
45  , _drawRange( eq::Range::ALL )
46  , _taint( getenv( "EQ_TAINT_CHANNELS" ))
47 {
48  eq::FrameDataPtr frameData = new eq::FrameData;
49  frameData->setBuffers( eq::Frame::BUFFER_COLOR );
50  _frame.setFrameData( frameData );
51 }
52 
53 static void checkError( const std::string& msg )
54 {
55  const GLenum error = glGetError();
56  if (error != GL_NO_ERROR)
57  LBERROR << msg << " GL Error: " << error << std::endl;
58 }
59 
60 
61 bool Channel::configInit( const eq::uint128_t& initID )
62 {
63  if( !eq::Channel::configInit( initID ))
64  return false;
65 
66  setNearFar( 0.001f, 10.0f );
67  return true;
68 }
69 
71 {
72  eq::FrameDataPtr frameData = _frame.getFrameData();
73  frameData->resetPlugins();
74 
75  return eq::Channel::configExit();
76 }
77 
78 void Channel::frameStart( const eq::uint128_t& frameID,
79  const uint32_t frameNumber )
80 {
81  _drawRange = eq::Range::ALL;
82  _bgColor = eq::Vector3f( 0.f, 0.f, 0.f );
83 
84  const BackgroundMode bgMode = _getFrameData().getBackgroundMode();
85 
86  if( bgMode == BG_WHITE )
87  _bgColor = eq::Vector3f( 1.f, 1.f, 1.f );
88  else
89  if( bgMode == BG_COLOR || _taint )
90  _bgColor = eq::Vector3f( getUniqueColor( )) / 255.f;
91 
92  eq::Channel::frameStart( frameID, frameNumber );
93 }
94 
95 void Channel::frameClear( const eq::uint128_t& frameID )
96 {
97  applyBuffer();
98  applyViewport();
99 
100  _drawRange = getRange();
101  if( _drawRange == eq::Range::ALL )
102  glClearColor( _bgColor.r(), _bgColor.g(), _bgColor.b(), 1.0f );
103  else
104  glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
105 
106  glClear( GL_COLOR_BUFFER_BIT );
107 }
108 
109 
110 static void setLights( eq::Matrix4f& invRotationM )
111 {
112  GLfloat lightAmbient[] = {0.05f, 0.05f, 0.05f, 1.0f};
113  GLfloat lightDiffuse[] = {0.9f , 0.9f , 0.9f , 1.0f};
114  GLfloat lightSpecular[] = {0.8f , 0.8f , 0.8f , 1.0f};
115  GLfloat lightPosition[] = {1.0f , 1.0f , 1.0f , 0.0f};
116 
117  glLightfv( GL_LIGHT0, GL_AMBIENT, lightAmbient );
118  glLightfv( GL_LIGHT0, GL_DIFFUSE, lightDiffuse );
119  glLightfv( GL_LIGHT0, GL_SPECULAR, lightSpecular );
120 
121  // rotate light in the opposite direction of the model rotation to keep
122  // light position constant and avoid recalculating normals in the fragment
123  // shader
124  glPushMatrix();
125  glMultMatrixf( invRotationM.array );
126  glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );
127  glPopMatrix();
128 }
129 
130 
131 static eq::Vector4f _getTaintColor( const ColorMode colorMode,
132  const eq::Vector3f& color )
133 {
134  if( colorMode == COLOR_MODEL )
135  return eq::Vector4f::ZERO;
136 
137  eq::Vector4f taintColor( color.r(), color.g(), color.b(), 1.0 );
138  const float alpha = ( colorMode == COLOR_HALF_DEMO ) ? 0.5 : 1.0;
139 
140  taintColor /= 255.f;
141  taintColor *= alpha;
142  taintColor.a() = alpha;
143  return taintColor;
144 }
145 
146 void Channel::frameDraw( const eq::uint128_t& frameID )
147 {
148  // Setup frustum
149  EQ_GL_CALL( applyBuffer( ));
150  EQ_GL_CALL( applyViewport( ));
151 
152  EQ_GL_CALL( glMatrixMode( GL_PROJECTION ));
153  EQ_GL_CALL( glLoadIdentity( ));
154  EQ_GL_CALL( applyFrustum( ));
155 
156  EQ_GL_CALL( glMatrixMode( GL_MODELVIEW ));
157  EQ_GL_CALL( glLoadIdentity( ));
158 
159  // Setup lights before applying head transform, so the light will be
160  // consistent in the cave
161  const FrameData& frameData = _getFrameData();
162  const eq::Matrix4f& rotation = frameData.getRotation();
163  const eq::Vector3f& translation = frameData.getTranslation();
164 
165  eq::Matrix4f invRotationM;
166  rotation.inverse( invRotationM );
167  setLights( invRotationM );
168 
169  EQ_GL_CALL( applyHeadTransform( ));
170 
171  glTranslatef( translation.x(), translation.y(), translation.z() );
172  glMultMatrixf( rotation.array );
173 
174  Pipe* pipe = static_cast<Pipe*>( getPipe( ));
175  Renderer* renderer = pipe->getRenderer();
176  LBASSERT( renderer );
177 
178  eq::Matrix4f modelviewM; // modelview matrix
179  eq::Matrix3f modelviewITM; // modelview inversed transposed matrix
180  _calcMVandITMV( modelviewM, modelviewITM );
181 
182  // set fancy data colors
183  const eq::Vector4f taintColor = _getTaintColor( frameData.getColorMode(),
184  getUniqueColor( ));
185  const int normalsQuality = _getFrameData().getNormalsQuality();
186 
187  const eq::Range& range = getRange();
188  renderer->render( range, modelviewM, modelviewITM, invRotationM,
189  taintColor, normalsQuality );
190  checkError( "error during rendering " );
191 
192  _drawRange = range;
193 
194 #ifndef NDEBUG
195  outlineViewport();
196 #endif
197 }
198 
199 bool Channel::useOrtho() const
200 {
201  const FrameData& frameData = _getFrameData();
202  return frameData.useOrtho();
203 }
204 
205 const FrameData& Channel::_getFrameData() const
206 {
207  const Pipe* pipe = static_cast< const Pipe* >( getPipe( ));
208  return pipe->getFrameData();
209 }
210 
211 void Channel::_calcMVandITMV(
212  eq::Matrix4f& modelviewM,
213  eq::Matrix3f& modelviewITM ) const
214 {
215  const FrameData& frameData = _getFrameData();
216  const Pipe* pipe = static_cast< const Pipe* >( getPipe( ));
217  const Renderer* renderer = pipe->getRenderer();
218 
219  if( renderer )
220  {
221  const VolumeScaling& volScaling = renderer->getVolumeScaling();
222 
223  eq::Matrix4f scale( eq::Matrix4f::ZERO );
224  scale.at(0,0) = volScaling.W;
225  scale.at(1,1) = volScaling.H;
226  scale.at(2,2) = volScaling.D;
227  scale.at(3,3) = 1.f;
228 
229  modelviewM = scale * frameData.getRotation();
230  }
231  modelviewM.set_translation( frameData.getTranslation( ));
232  modelviewM = getHeadTransform() * modelviewM;
233 
234  //calculate inverse transposed matrix
235  eq::Matrix4f modelviewIM;
236  modelviewM.inverse( modelviewIM );
237  eq::Matrix3f( modelviewIM ).transpose_to( modelviewITM );
238 }
239 
240 
241 static void _expandPVP( eq::PixelViewport& pvp, const eq::Images& images,
242  const eq::Vector2i& offset )
243 {
244  for( eq::Images::const_iterator i = images.begin();
245  i != images.end(); ++i )
246  {
247  const eq::PixelViewport imagePVP = (*i)->getPixelViewport() + offset;
248  pvp.merge( imagePVP );
249  }
250 }
251 
252 
253 void Channel::clearViewport( const eq::PixelViewport &pvp )
254 {
255  // clear given area
256  glScissor( pvp.x, pvp.y, pvp.w, pvp.h );
257 
258  if( _drawRange == eq::Range::ALL )
259  glClearColor( _bgColor.r(), _bgColor.g(), _bgColor.b(), 1.0f );
260  else
261  glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
262 
263  glClear( GL_COLOR_BUFFER_BIT );
264 
265  // restore assembly state
266  const eq::PixelViewport& windowPVP = getWindow()->getPixelViewport();
267  glScissor( 0, 0, windowPVP.w, windowPVP.h );
268 }
269 
270 void Channel::_orderFrames( eq::Frames& frames )
271 {
272  eq::Matrix4f modelviewM; // modelview matrix
273  eq::Matrix3f modelviewITM; // modelview inversed transposed matrix
274  const FrameData& frameData = _getFrameData();
275  const eq::Matrix4f& rotation = frameData.getRotation();
276 
277  if( !useOrtho( ))
278  _calcMVandITMV( modelviewM, modelviewITM );
279 
280  orderFrames( frames, modelviewM, modelviewITM, rotation, useOrtho( ));
281 }
282 
283 
284 void Channel::frameAssemble( const eq::uint128_t& frameID )
285 {
286  const bool composeOnly = (_drawRange == eq::Range::ALL);
287 
288  _startAssemble();
289 
290  const eq::Frames& frames = getInputFrames();
291  eq::PixelViewport coveredPVP;
292  eq::Frames dbFrames;
293  eq::Zoom zoom( eq::Zoom::NONE );
294 
295  // Make sure all frames are ready and gather some information on them
296  for( eq::Frames::const_iterator i = frames.begin();
297  i != frames.end(); ++i )
298  {
299  eq::Frame* frame = *i;
300  {
302  this );
303  frame->waitReady( );
304  }
305  const eq::Range& range = frame->getRange();
306  if( range == eq::Range::ALL ) // 2D frame, assemble directly
307  eq::Compositor::assembleFrame( frame, this );
308  else
309  {
310  dbFrames.push_back( frame );
311  zoom = frame->getZoom();
312  _expandPVP( coveredPVP, frame->getImages(), frame->getOffset() );
313  }
314  }
315  coveredPVP.intersect( getPixelViewport( ));
316 
317  if( dbFrames.empty( ))
318  {
320  return;
321  }
322 
323  // calculate correct frames sequence
324  eq::FrameDataPtr data = _frame.getFrameData();
325  if( !composeOnly && coveredPVP.hasArea( ))
326  {
327  _frame.clear();
328  data->setRange( _drawRange );
329  dbFrames.push_back( &_frame );
330  }
331 
332  _orderFrames( dbFrames );
333 
334  // Update range
335  eq::Range newRange( 1.f, 0.f );
336  for( size_t i = 0; i < dbFrames.size(); ++i )
337  {
338  const eq::Range range = dbFrames[i]->getRange();
339  if( newRange.start > range.start ) newRange.start = range.start;
340  if( newRange.end < range.end ) newRange.end = range.end;
341  }
342  _drawRange = newRange;
343 
344  // check if current frame is in proper position, read back if not
345  if( !composeOnly )
346  {
347  if( _bgColor == eq::Vector3f::ZERO && dbFrames.front() == &_frame )
348  dbFrames.erase( dbFrames.begin( ));
349  else if( coveredPVP.hasArea())
350  {
352 
353  _frame.setOffset( eq::Vector2i( 0, 0 ));
354  _frame.setZoom( zoom );
355  data->setPixelViewport( coveredPVP );
356  _frame.readback( glObjects, getDrawableConfig(), getRegions( ));
357  clearViewport( coveredPVP );
358 
359  // offset for assembly
360  _frame.setOffset( eq::Vector2i( coveredPVP.x, coveredPVP.y ));
361  }
362  }
363 
364  // blend DB frames in order
365  try
366  {
367  eq::Compositor::assembleFramesSorted( dbFrames, this, 0,
368  true /*blendAlpha*/ );
369  }
370  catch( const co::Exception& e )
371  {
372  LBWARN << e.what() << std::endl;
373  }
374 
376 }
377 
378 void Channel::_startAssemble()
379 {
380  applyBuffer();
381  applyViewport();
383 }
384 
385 void Channel::frameReadback( const eq::uint128_t& frameID )
386 {
387  // Drop depth buffer flag from all output frames
388  const eq::Frames& frames = getOutputFrames();
389  const FrameData& frameData = _getFrameData();
390  for( eq::FramesCIter i = frames.begin(); i != frames.end(); ++i )
391  {
392  eq::Frame* frame = *i;
393  frame->setQuality( eq::Frame::BUFFER_COLOR, frameData.getQuality());
395  frame->getFrameData()->setRange( _drawRange );
396  }
397 
398  eq::Channel::frameReadback( frameID );
399 }
400 
401 void Channel::frameViewFinish( const eq::uint128_t& frameID )
402 {
403  _drawHelp();
404  _drawLogo();
405  eq::Channel::frameViewFinish( frameID );
406 }
407 
408 void Channel::_drawLogo( )
409 {
410  // Draw the overlay logo
411  const Window* window = static_cast<Window*>( getWindow( ));
412  const eq::util::Texture* texture = window->getLogoTexture();
413  if( !texture )
414  return;
415 
416  glMatrixMode( GL_PROJECTION );
417  glLoadIdentity();
419  glMatrixMode( GL_MODELVIEW );
420  glLoadIdentity();
421 
422  glDisable( GL_DEPTH_TEST );
423  glDisable( GL_LIGHTING );
424  glEnable( GL_BLEND );
425  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
426 
427  glColor3f( 1.0f, 1.0f, 1.0f );
428  const GLenum target = texture->getTarget();
429  glEnable( target );
430  texture->bind();
431  glTexParameteri( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
432  glTexParameteri( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
433 
434  const float tWidth = float( texture->getWidth( ) );
435  const float tHeight = float( texture->getHeight( ) );
436 
437  const float width = target == GL_TEXTURE_2D ? 1.0f : tWidth;
438  const float height = target == GL_TEXTURE_2D ? 1.0f : tHeight;
439 
440  glBegin( GL_QUADS ); {
441  glTexCoord2f( 0, 0 );
442  glVertex3f( 5.0f, 5.0f, 0.0f );
443 
444  glTexCoord2f( width, 0 );
445  glVertex3f( tWidth + 5.0f, 5.0f, 0.0f );
446 
447  glTexCoord2f( width, height );
448  glVertex3f( tWidth + 5.0f, tHeight + 5.0f, 0.0f );
449 
450  glTexCoord2f( 0, height );
451  glVertex3f( 5.0f, tHeight + 5.0f, 0.0f );
452 
453  } glEnd();
454 
455  glDisable( target );
456  glDisable( GL_BLEND );
457 }
458 
459 void Channel::_drawHelp()
460 {
461  const FrameData& frameData = _getFrameData();
462  std::string message = frameData.getMessage();
463 
464  if( !frameData.showHelp() && message.empty( ))
465  return;
466 
467  applyBuffer();
468  applyViewport();
470 
471  glDisable( GL_LIGHTING );
472  glDisable( GL_DEPTH_TEST );
473 
474  glColor3f( 1.f, 1.f, 1.f );
475 
476  if( frameData.showHelp( ))
477  {
478  const eq::Window::Font* font = getWindow()->getSmallFont();
479  std::string help = EVolve::getHelp();
480  float y = 340.f;
481 
482  for( size_t pos = help.find( '\n' ); pos != std::string::npos;
483  pos = help.find( '\n' ))
484  {
485  glRasterPos3f( 10.f, y, 0.99f );
486 
487  font->draw( help.substr( 0, pos ));
488  help = help.substr( pos + 1 );
489  y -= 16.f;
490  }
491  // last line
492  glRasterPos3f( 10.f, y, 0.99f );
493  font->draw( help );
494  }
495 
496  if( !message.empty( ))
497  {
498  const eq::Window::Font* font = getWindow()->getMediumFont();
499 
500  const eq::Viewport& vp = getViewport();
501  const eq::PixelViewport& pvp = getPixelViewport();
502 
503  const float width = pvp.w / vp.w;
504  const float xOffset = vp.x * width;
505 
506  const float height = pvp.h / vp.h;
507  const float yOffset = vp.y * height;
508  const float yMiddle = 0.5f * height;
509  float y = yMiddle - yOffset;
510 
511  for( size_t pos = message.find( '\n' ); pos != std::string::npos;
512  pos = message.find( '\n' ))
513  {
514  glRasterPos3f( 10.f - xOffset, y, 0.99f );
515 
516  font->draw( message.substr( 0, pos ));
517  message = message.substr( pos + 1 );
518  y -= 22.f;
519  }
520  // last line
521  glRasterPos3f( 10.f - xOffset, y, 0.99f );
522  font->draw( message );
523  }
524 
525  EQ_GL_CALL( resetAssemblyState( ));
526 }
527 }
A holder for multiple images.
A channel represents a two-dimensional viewport within a Window.
White background.
Definition: eVolve.h:75
virtual void setupAssemblyState()
Setup the OpenGL state for a readback or assemble operation.
const Images & getImages() const
virtual void applyViewport() const
Apply the OpenGL viewport for the current rendering task.
Sampling of Frame::waitReady.
Definition: statistic.h:46
virtual void frameStart(const uint128_t &frameID, const uint32_t frameNumber)
Start rendering a frame.
const PixelViewport & getPixelViewport() const
virtual void frameViewFinish(const eq::uint128_t &frameID)
Finish updating a destination channel.
virtual void frameDraw(const eq::uint128_t &frameID)
Draw the scene.
virtual void frameAssemble(const eq::uint128_t &frameID)
Assemble all input frames.
const PixelViewports & getRegions() const
Get the current regions of interest.
A Window represents an on-screen or off-screen drawable.
void setBuffers(const uint32_t buffers)
Set the enabled frame buffer attachments.
virtual void frameStart(const eq::uint128_t &frameID, const uint32_t frameNumber)
Start rendering a frame.
const Frames & getInputFrames()
void applyScreenFrustum() const
Apply an orthographic frustum for pixel-based 2D operations.
const Vector2i & getOffset() const
static uint32_t assembleFramesSorted(const Frames &frames, Channel *channel, util::Accum *accum, const bool blendAlpha=false)
Assemble all frames in the given order using the fastest implemented algorithm on the given channel...
virtual void outlineViewport()
Outline the current pixel viewport.
A wrapper around AGL, WGL and GLX bitmap fonts.
void disableBuffer(const Buffer buffer)
Disable the usage of a frame buffer attachment for all images.
const Frames & getOutputFrames()
virtual void applyBuffer()
Apply the current rendering buffer, including the color mask.
void waitReady(const uint32_t timeout=LB_TIMEOUT_INDEFINITE) const
Wait for the frame to become available.
void draw(const std::string &text) const
Draw text on the current raster position.
int32_t getHeight() const
virtual bool configExit()
Exit this channel.
A facility class to manage OpenGL objects across shared contexts.
void readback(ObjectManager *glObjects, const DrawableConfig &config)
Read back an image.
std::vector< Image * > Images
A vector of pointers to eq::Image.
Pipe * getPipe()
void bind() const
Bind the texture.
const Matrix4f & getHeadTransform() const
Return the view matrix.
const Range & getRange() const
virtual void applyHeadTransform() const
Apply the transformation to position the view frustum.
virtual void frameReadback(const eq::uint128_t &frameID)
Read back the rendered frame buffer into the output frames.
void setZoom(const Zoom &zoom)
Set the zoom for this frame holder.
const Vector3ub & getUniqueColor() const
Samples one channel statistics event.
50% unique color + 50% original color
Definition: eVolve.h:68
Unique color.
Definition: eVolve.h:76
A holder for a frame data and related parameters.
Definition: client/frame.h:42
virtual bool configInit(const eq::uint128_t &initID)
Initialize this channel.
FrameDataPtr getFrameData()
virtual void applyFrustum() const
Apply the frustum matrix for the current rendering task.
const Zoom & getZoom() const
virtual bool configExit()
Exit this channel.
const DrawableConfig & getDrawableConfig() const
std::vector< Frame * > Frames
A vector of pointers to eq::Frame.
void setOffset(const Vector2i &offset)
Set the position of the frame wrt the channel.
virtual bool configInit(const uint128_t &initID)
Initialize this channel.
ColorMode
Definition: eVolve.h:64
EQFABRIC_INL void setNearFar(const float nearPlane, const float farPlane)
Set the near and far planes for this channel.
Frames::const_iterator FramesCIter
A const_iterator over a eq::Frame vector.
BackgroundMode
Definition: eVolve.h:72
A wrapper around OpenGL textures.
Definition: texture.h:38
virtual void frameViewFinish(const uint128_t &frameID)
Finish updating a destination channel.
const PixelViewport & getPixelViewport() const
ObjectManager * getObjectManager()
static void assembleFrame(const Frame *frame, Channel *channel)
Assemble a frame into the frame buffer using the default algorithm.
virtual void frameClear(const eq::uint128_t &frameID)
Clear the frame buffer.
int32_t getWidth() const
virtual bool useOrtho() const
Select perspective or orthographic rendering.
lunchbox::RefPtr< FrameData > FrameDataPtr
A reference-counted pointer to an eq::FrameData.
virtual void frameReadback(const uint128_t &frameID)
Read back the rendered frame buffer into the output frames.
Render using the colors defined in the ply file.
Definition: eVolve.h:66
unsigned getTarget() const
void setQuality(const Frame::Buffer buffer, const float quality)
Set the minimum quality after compression.
virtual void resetAssemblyState()
Reset the OpenGL state after an assembly operation.