Equalizer  1.8.0
Parallel Rendering Framework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
eVolve/channel.cpp
1 
2 /* Copyright (c) 2006-2014, 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& )
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& )
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  const eq::Matrix4f& modelview = _computeModelView();
179 
180  // set fancy data colors
181  const eq::Vector4f taintColor = _getTaintColor( frameData.getColorMode(),
182  getUniqueColor( ));
183  const int normalsQuality = _getFrameData().getNormalsQuality();
184 
185  const eq::Range& range = getRange();
186  renderer->render( range, modelview, invRotationM, taintColor,
187  normalsQuality );
188  checkError( "error during rendering " );
189 
190  _drawRange = range;
191 
192 #ifndef NDEBUG
193  outlineViewport();
194 #endif
195 }
196 
197 bool Channel::useOrtho() const
198 {
199  const FrameData& frameData = _getFrameData();
200  return frameData.useOrtho();
201 }
202 
203 const FrameData& Channel::_getFrameData() const
204 {
205  const Pipe* pipe = static_cast< const Pipe* >( getPipe( ));
206  return pipe->getFrameData();
207 }
208 
209 eq::Matrix4f Channel::_computeModelView() const
210 {
211  const FrameData& frameData = _getFrameData();
212  const Pipe* pipe = static_cast< const Pipe* >( getPipe( ));
213  const Renderer* renderer = pipe->getRenderer();
214  eq::Matrix4f modelView( eq::Matrix4f::IDENTITY );
215 
216  if( renderer )
217  {
218  const VolumeScaling& volScaling = renderer->getVolumeScaling();
219 
220  eq::Matrix4f scale( eq::Matrix4f::ZERO );
221  scale.at(0,0) = volScaling.W;
222  scale.at(1,1) = volScaling.H;
223  scale.at(2,2) = volScaling.D;
224  scale.at(3,3) = 1.f;
225 
226  modelView = scale * frameData.getRotation();
227  }
228  modelView.set_translation( frameData.getTranslation( ));
229  return getHeadTransform() * modelView;
230 }
231 
232 
233 static void _expandPVP( eq::PixelViewport& pvp, const eq::Images& images,
234  const eq::Vector2i& offset )
235 {
236  for( eq::Images::const_iterator i = images.begin();
237  i != images.end(); ++i )
238  {
239  const eq::PixelViewport imagePVP = (*i)->getPixelViewport() + offset;
240  pvp.merge( imagePVP );
241  }
242 }
243 
244 
245 void Channel::clearViewport( const eq::PixelViewport &pvp )
246 {
247  // clear given area
248  glScissor( pvp.x, pvp.y, pvp.w, pvp.h );
249 
250  if( _drawRange == eq::Range::ALL )
251  glClearColor( _bgColor.r(), _bgColor.g(), _bgColor.b(), 1.0f );
252  else
253  glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
254 
255  glClear( GL_COLOR_BUFFER_BIT );
256 
257  // restore assembly state
258  const eq::PixelViewport& windowPVP = getWindow()->getPixelViewport();
259  glScissor( 0, 0, windowPVP.w, windowPVP.h );
260 }
261 
262 void Channel::_orderFrames( eq::Frames& frames )
263 {
264  const FrameData& frameData = _getFrameData();
265  const eq::Matrix4f& rotation = frameData.getRotation();
266 
267  const eq::Matrix4f& modelView = useOrtho() ? eq::Matrix4f::IDENTITY :
268  _computeModelView();
269 
270  //calculate modelview inversed transposed matrix
271  eq::Matrix3f modelviewITM;
272  eq::Matrix4f modelviewIM;
273  modelView.inverse( modelviewIM );
274  eq::Matrix3f( modelviewIM ).transpose_to( modelviewITM );
275 
276  orderFrames( frames, modelView, modelviewITM, rotation, useOrtho( ));
277 }
278 
279 
280 void Channel::frameAssemble( const eq::uint128_t&, const eq::Frames& frames )
281 {
282  const bool composeOnly = (_drawRange == eq::Range::ALL);
283 
284  _startAssemble();
285 
286  eq::PixelViewport coveredPVP;
287  eq::Frames dbFrames;
288  eq::Zoom zoom( eq::Zoom::NONE );
289 
290  // Make sure all frames are ready and gather some information on them
291  for( eq::Frames::const_iterator i = frames.begin();
292  i != frames.end(); ++i )
293  {
294  eq::Frame* frame = *i;
295  {
296  eq::ChannelStatistics stat( eq::Statistic::CHANNEL_FRAME_WAIT_READY,
297  this );
298  frame->waitReady( );
299  }
300  const eq::Range& range = frame->getRange();
301  if( range == eq::Range::ALL ) // 2D frame, assemble directly
302  eq::Compositor::assembleFrame( frame, this );
303  else
304  {
305  dbFrames.push_back( frame );
306  zoom = frame->getZoom();
307  _expandPVP( coveredPVP, frame->getImages(), frame->getOffset() );
308  }
309  }
310  coveredPVP.intersect( getPixelViewport( ));
311 
312  if( dbFrames.empty( ))
313  {
315  return;
316  }
317 
318  // calculate correct frames sequence
319  eq::FrameDataPtr data = _frame.getFrameData();
320  if( !composeOnly && coveredPVP.hasArea( ))
321  {
322  _frame.clear();
323  data->setRange( _drawRange );
324  dbFrames.push_back( &_frame );
325  }
326 
327  _orderFrames( dbFrames );
328 
329  // Update range
330  eq::Range newRange( 1.f, 0.f );
331  for( size_t i = 0; i < dbFrames.size(); ++i )
332  {
333  const eq::Range range = dbFrames[i]->getRange();
334  if( newRange.start > range.start ) newRange.start = range.start;
335  if( newRange.end < range.end ) newRange.end = range.end;
336  }
337  _drawRange = newRange;
338 
339  // check if current frame is in proper position, read back if not
340  if( !composeOnly )
341  {
342  if( _bgColor == eq::Vector3f::ZERO && dbFrames.front() == &_frame )
343  dbFrames.erase( dbFrames.begin( ));
344  else if( coveredPVP.hasArea())
345  {
347 
348  _frame.setOffset( eq::Vector2i( 0, 0 ));
349  _frame.setZoom( zoom );
350  data->setPixelViewport( coveredPVP );
351  _frame.readback( glObjects, getDrawableConfig(), getRegions( ));
352  clearViewport( coveredPVP );
353 
354  // offset for assembly
355  _frame.setOffset( eq::Vector2i( coveredPVP.x, coveredPVP.y ));
356  }
357  }
358 
359  // blend DB frames in order
360  try
361  {
362  eq::Compositor::assembleFramesSorted( dbFrames, this, 0,
363  true /*blendAlpha*/ );
364  }
365  catch( const co::Exception& e )
366  {
367  LBWARN << e.what() << std::endl;
368  }
369 
371 }
372 
373 void Channel::_startAssemble()
374 {
375  applyBuffer();
376  applyViewport();
378 }
379 
380 void Channel::frameReadback( const eq::uint128_t& frameID,
381  const eq::Frames& frames )
382 {
383  // Drop depth buffer flag from all output frames
384  const FrameData& frameData = _getFrameData();
385  for( eq::FramesCIter i = frames.begin(); i != frames.end(); ++i )
386  {
387  eq::Frame* frame = *i;
388  frame->setQuality( eq::Frame::BUFFER_COLOR, frameData.getQuality());
390  frame->getFrameData()->setRange( _drawRange );
391  }
392 
393  eq::Channel::frameReadback( frameID, frames );
394 }
395 
396 void Channel::frameViewFinish( const eq::uint128_t& frameID )
397 {
398  _drawHelp();
399  _drawLogo();
400  eq::Channel::frameViewFinish( frameID );
401 }
402 
403 void Channel::_drawLogo( )
404 {
405  // Draw the overlay logo
406  const Window* window = static_cast<Window*>( getWindow( ));
407  const eq::util::Texture* texture = window->getLogoTexture();
408  if( !texture )
409  return;
410 
411  glMatrixMode( GL_PROJECTION );
412  glLoadIdentity();
414  glMatrixMode( GL_MODELVIEW );
415  glLoadIdentity();
416 
417  glDisable( GL_DEPTH_TEST );
418  glDisable( GL_LIGHTING );
419  glEnable( GL_BLEND );
420  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
421 
422  glColor3f( 1.0f, 1.0f, 1.0f );
423  const GLenum target = texture->getTarget();
424  glEnable( target );
425  texture->bind();
426  glTexParameteri( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
427  glTexParameteri( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
428 
429  const float tWidth = float( texture->getWidth( ) );
430  const float tHeight = float( texture->getHeight( ) );
431 
432  const float width = target == GL_TEXTURE_2D ? 1.0f : tWidth;
433  const float height = target == GL_TEXTURE_2D ? 1.0f : tHeight;
434 
435  glBegin( GL_QUADS ); {
436  glTexCoord2f( 0, 0 );
437  glVertex3f( 5.0f, 5.0f, 0.0f );
438 
439  glTexCoord2f( width, 0 );
440  glVertex3f( tWidth + 5.0f, 5.0f, 0.0f );
441 
442  glTexCoord2f( width, height );
443  glVertex3f( tWidth + 5.0f, tHeight + 5.0f, 0.0f );
444 
445  glTexCoord2f( 0, height );
446  glVertex3f( 5.0f, tHeight + 5.0f, 0.0f );
447 
448  } glEnd();
449 
450  glDisable( target );
451  glDisable( GL_BLEND );
452 }
453 
454 void Channel::_drawHelp()
455 {
456  const FrameData& frameData = _getFrameData();
457  std::string message = frameData.getMessage();
458 
459  if( !frameData.showHelp() && message.empty( ))
460  return;
461 
462  applyBuffer();
463  applyViewport();
465 
466  glDisable( GL_LIGHTING );
467  glDisable( GL_DEPTH_TEST );
468 
469  glColor3f( 1.f, 1.f, 1.f );
470 
471  if( frameData.showHelp( ))
472  {
473  const eq::util::BitmapFont* font = getWindow()->getSmallFont();
474  std::string help = EVolve::getHelp();
475  float y = 340.f;
476 
477  for( size_t pos = help.find( '\n' ); pos != std::string::npos;
478  pos = help.find( '\n' ))
479  {
480  glRasterPos3f( 10.f, y, 0.99f );
481 
482  font->draw( help.substr( 0, pos ));
483  help = help.substr( pos + 1 );
484  y -= 16.f;
485  }
486  // last line
487  glRasterPos3f( 10.f, y, 0.99f );
488  font->draw( help );
489  }
490 
491  if( !message.empty( ))
492  {
493  const eq::util::BitmapFont* font = getWindow()->getMediumFont();
494 
495  const eq::Viewport& vp = getViewport();
496  const eq::PixelViewport& pvp = getPixelViewport();
497 
498  const float width = pvp.w / vp.w;
499  const float xOffset = vp.x * width;
500 
501  const float height = pvp.h / vp.h;
502  const float yOffset = vp.y * height;
503  const float yMiddle = 0.5f * height;
504  float y = yMiddle - yOffset;
505 
506  for( size_t pos = message.find( '\n' ); pos != std::string::npos;
507  pos = message.find( '\n' ))
508  {
509  glRasterPos3f( 10.f - xOffset, y, 0.99f );
510 
511  font->draw( message.substr( 0, pos ));
512  message = message.substr( pos + 1 );
513  y -= 22.f;
514  }
515  // last line
516  glRasterPos3f( 10.f - xOffset, y, 0.99f );
517  font->draw( message );
518  }
519 
520  EQ_GL_CALL( resetAssemblyState( ));
521 }
522 }
const PixelViewport & getPixelViewport() const
Unique color.
Definition: eVolve.h:75
virtual EQ_API void frameReadback(const uint128_t &frameID, const Frames &frames)
Read back the rendered frame buffer into the output frames.
void frameAssemble(const eq::uint128_t &, const eq::Frames &) override
Assemble all input frames.
virtual EQ_API void outlineViewport()
Outline the current pixel viewport.
A channel represents a two-dimensional viewport within a Window.
White background.
Definition: eVolve.h:74
ColorMode
Definition: eVolve.h:63
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.
void frameReadback(const eq::uint128_t &, const eq::Frames &) override
Read back the rendered frame buffer into the output frames.
EQ_API void setBuffers(const uint32_t buffers)
Set the enabled frame buffer attachments.
EQ_API void bind() const
Bind the texture.
EQ_API const Range & getRange() const
A wrapper around AGL, WGL and GLX bitmap fonts.
Definition: bitmapFont.h:31
EQ_API void readback(util::ObjectManager &glObjects, const DrawableConfig &config)
Read back an image.
virtual EQ_API void applyViewport() const
Apply the OpenGL viewport for the current rendering task.
virtual EQ_API void applyFrustum() const
Apply the frustum matrix for the current rendering task.
A wrapper around OpenGL textures.
Definition: texture.h:38
void frameClear(const eq::uint128_t &frameID) override
Clear the frame buffer.
EQFABRIC_INL const PixelViewport & getPixelViewport() const
EQFABRIC_INL void setNearFar(const float nearPlane, const float farPlane)
Set the near and far planes for this channel.
static void assembleFrame(const Frame *frame, Channel *channel)
Assemble a frame into the frame buffer using the default algorithm.
EQFABRIC_API void setOffset(const Vector2i &offset)
Set the position of the frame wrt the channel.
BackgroundMode
Definition: eVolve.h:71
EQ_API void draw(const std::string &text) const
Draw text on the current raster position.
void frameViewFinish(const eq::uint128_t &frameID) override
Finish updating a destination channel.
std::vector< Image * > Images
A vector of pointers to eq::Image.
void frameStart(const eq::uint128_t &frameID, const uint32_t frameNumber) override
Start rendering a frame.
bool configInit(const eq::uint128_t &initID) override
Initialize this channel.
EQ_API util::ObjectManager & getObjectManager()
EQ_API void setQuality(const Frame::Buffer buffer, const float quality)
Set the minimum quality after compression.
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...
A Window represents an on-screen or off-screen drawable.
bool useOrtho() const override
Select perspective or orthographic rendering.
EQ_API const Vector3ub & getUniqueColor() const
virtual EQ_API void applyHeadTransform() const
Apply the transformation to position the view frustum.
EQ_API void waitReady(const uint32_t timeout=LB_TIMEOUT_INDEFINITE) const
Wait for the frame to become available.
EQFABRIC_API const Zoom & getZoom() const
EQ_API Pipe * getPipe()
A holder for multiple images.
EQ_API const DrawableConfig & getDrawableConfig() const
EQ_API void disableBuffer(const Buffer buffer)
Disable the usage of a frame buffer attachment for all images.
virtual EQ_API bool configExit()
Exit this channel.
std::vector< Frame * > Frames
A vector of pointers to eq::Frame.
void frameDraw(const eq::uint128_t &frameID) override
Draw the scene.
Frames::const_iterator FramesCIter
A const_iterator over a eq::Frame vector.
EQ_API const Images & getImages() const
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
A facility class to manage OpenGL objects across shared contexts.
Definition: objectManager.h:51
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.
lunchbox::RefPtr< FrameData > FrameDataPtr
A reference-counted pointer to an eq::FrameData.
virtual EQ_API void resetAssemblyState()
Reset the OpenGL state after an assembly operation.
bool configExit() override
Exit this channel.
Render using the colors defined in the ply file.
Definition: eVolve.h:65
EQ_API const PixelViewports & getRegions() const
Get the current regions of interest.
50% unique color + 50% original color
Definition: eVolve.h:67
EQFABRIC_API void setZoom(const Zoom &zoom)
Set the zoom for this frame holder.
EQFABRIC_API const Vector2i & getOffset() const
EQ_API FrameDataPtr getFrameData()
Samples one channel statistics event.