examples/eVolve/channel.cpp

00001 
00002 /* Copyright (c) 2006-2009, Stefan Eilemann <eile@equalizergraphics.com>
00003                  2007-2009, Maxim Makhinya
00004  *
00005  * This library is free software; you can redistribute it and/or modify it under
00006  * the terms of the GNU Lesser General Public License version 2.1 as published
00007  * by the Free Software Foundation.
00008  *  
00009  * This library is distributed in the hope that it will be useful, but WITHOUT
00010  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00012  * details.
00013  * 
00014  * You should have received a copy of the GNU Lesser General Public License
00015  * along with this library; if not, write to the Free Software Foundation, Inc.,
00016  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00017  */
00018 
00019 #include "channel.h"
00020 
00021 #include "frameData.h"
00022 #include "initData.h"
00023 #include "node.h"
00024 #include "pipe.h"
00025 #include "window.h"
00026 #include "hlp.h"
00027 #include "framesOrderer.h"
00028 #include <eq/client/zoom.h>
00029 
00030 using namespace eq::base;
00031 using namespace std;
00032 
00033 namespace eVolve
00034 {
00035 Channel::Channel( eq::Window* parent )
00036     : eq::Channel( parent )
00037     , _bgColor( eq::Vector3f::ZERO )
00038     , _drawRange( eq::Range::ALL )
00039 {
00040     eq::FrameData* frameData = new eq::FrameData;
00041     frameData->setBuffers( eq::Frame::BUFFER_COLOR );
00042     _frame.setData( frameData );
00043 }
00044 
00045 static void checkError( const std::string& msg ) 
00046 {
00047     const GLenum error = glGetError();
00048     if (error != GL_NO_ERROR)
00049         EQERROR << msg << " GL Error: " << error << endl;
00050 }
00051 
00052 
00053 bool Channel::configInit( const uint32_t initID )
00054 {
00055     if( !eq::Channel::configInit( initID ))
00056         return false;
00057     EQINFO << "Init channel initID " << initID << " ptr " << this << endl;
00058 
00059     // chose projection type
00060     setNearFar( 0.001f, 10.0f );
00061 
00062     if( getenv( "EQ_TAINT_CHANNELS" ))
00063     {
00064         _bgColor = getUniqueColor();
00065         _bgColor /= 255.f;
00066     }
00067 
00068     return true;
00069 }
00070 
00071 void Channel::frameStart( const uint32_t frameID, const uint32_t frameNumber )
00072 {
00073     _drawRange = eq::Range::ALL;
00074     eq::Channel::frameStart( frameID, frameNumber );
00075 }
00076 
00077 void Channel::frameClear( const uint32_t frameID )
00078 {
00079     applyBuffer();
00080     applyViewport();
00081 
00082     if( getRange() == eq::Range::ALL )
00083         glClearColor( _bgColor.r(), _bgColor.g(), _bgColor.b(), 1.0f );
00084     else
00085         glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
00086 
00087     glClear( GL_COLOR_BUFFER_BIT );
00088 }
00089 
00090 
00091 static void setLights( eq::Matrix4f& invRotationM )
00092 {
00093     GLfloat lightAmbient[]  = {0.05f, 0.05f, 0.05f, 1.0f};
00094     GLfloat lightDiffuse[]  = {0.9f , 0.9f , 0.9f , 1.0f};
00095     GLfloat lightSpecular[] = {0.8f , 0.8f , 0.8f , 1.0f};
00096     GLfloat lightPosition[] = {1.0f , 1.0f , 1.0f , 0.0f};
00097 
00098     glLightfv( GL_LIGHT0, GL_AMBIENT,  lightAmbient  );
00099     glLightfv( GL_LIGHT0, GL_DIFFUSE,  lightDiffuse  );
00100     glLightfv( GL_LIGHT0, GL_SPECULAR, lightSpecular );
00101 
00102     // rotate light in the opposite direction of the model rotation to keep
00103     // light position constant and avoid recalculating normals in the fragment
00104     // shader
00105     glPushMatrix();
00106     glMultMatrixf( invRotationM.array );
00107     glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );
00108     glPopMatrix();
00109 }
00110 
00111 
00112 void Channel::frameDraw( const uint32_t frameID )
00113 {
00114     // Setup frustum
00115     EQ_GL_CALL( applyBuffer( ));
00116     EQ_GL_CALL( applyViewport( ));
00117     
00118     EQ_GL_CALL( glMatrixMode( GL_PROJECTION ));
00119     EQ_GL_CALL( glLoadIdentity( ));
00120     EQ_GL_CALL( applyFrustum( ));
00121 
00122     EQ_GL_CALL( glMatrixMode( GL_MODELVIEW ));
00123     EQ_GL_CALL( glLoadIdentity( ));
00124 
00125     // Setup lights before applying head transform, so the light will be
00126     // consistent in the cave
00127     const FrameData&    frameData   = _getFrameData();
00128     const eq::Matrix4f& rotation    = frameData.getRotation();
00129     const eq::Vector3f& translation = frameData.getTranslation();
00130 
00131     eq::Matrix4f     invRotationM;
00132     rotation.inverse( invRotationM );
00133     setLights( invRotationM );
00134 
00135     EQ_GL_CALL( applyHeadTransform( ));
00136 
00137     glTranslatef(  translation.x(), translation.y(), translation.z() );
00138     glMultMatrixf( rotation.array );
00139 
00140     Pipe*     pipe     = static_cast<Pipe*>( getPipe( ));
00141     Renderer* renderer = pipe->getRenderer();
00142     EQASSERT( renderer );
00143 
00144     eq::Matrix4f  modelviewM;     // modelview matrix
00145     eq::Matrix3f  modelviewITM;   // modelview inversed transposed matrix
00146     _calcMVandITMV( modelviewM, modelviewITM );
00147 
00148     const eq::Range& range = getRange();
00149     renderer->render( range, modelviewM, modelviewITM, invRotationM );
00150 
00151     checkError( "error during rendering " );
00152 
00153     _drawRange = range;
00154 
00155 #ifndef NDEBUG
00156     outlineViewport();
00157 #endif
00158 }
00159 
00160 const FrameData& Channel::_getFrameData() const
00161 {
00162     const Pipe* pipe = static_cast< const Pipe* >( getPipe( ));
00163     return pipe->getFrameData();
00164 }
00165 
00166 void Channel::applyFrustum() const
00167 {
00168     const FrameData& frameData = _getFrameData();
00169 
00170     if( frameData.useOrtho( ))
00171         eq::Channel::applyOrtho();
00172     else
00173         eq::Channel::applyFrustum();
00174 }
00175 
00176 
00177 void Channel::_calcMVandITMV(
00178                             eq::Matrix4f& modelviewM,
00179                             eq::Matrix3f& modelviewITM ) const
00180 {
00181     const FrameData& frameData = _getFrameData();
00182     const Pipe*      pipe      = static_cast< const Pipe* >( getPipe( ));
00183     const Renderer*  renderer  = pipe->getRenderer();
00184 
00185     if( renderer )
00186     {
00187         const VolumeScaling& volScaling = renderer->getVolumeScaling();
00188         
00189         eq::Matrix4f scale( eq::Matrix4f::ZERO );
00190         scale.at(0,0) = volScaling.W;
00191         scale.at(1,1) = volScaling.H;
00192         scale.at(2,2) = volScaling.D;
00193         scale.at(3,3) = 1.f;
00194         
00195         modelviewM = scale * frameData.getRotation();
00196     }
00197     modelviewM.set_translation( frameData.getTranslation( ));
00198 
00199     modelviewM = getHeadTransform() * modelviewM;
00200 
00201     //calculate inverse transposed matrix
00202     eq::Matrix4f modelviewIM;
00203     modelviewM.inverse( modelviewIM );
00204     eq::Matrix3f( modelviewIM ).transpose_to(  modelviewITM  );
00205 }
00206 
00207 
00208 static void _expandPVP( eq::PixelViewport& pvp, 
00209                         const vector< eq::Image* >& images,
00210                         const eq::Vector2i& offset )
00211 {
00212     for( vector< eq::Image* >::const_iterator i = images.begin();
00213          i != images.end(); ++i )
00214     {
00215         const eq::PixelViewport imagePVP = (*i)->getPixelViewport() + offset;
00216         pvp.merge( imagePVP );
00217     }
00218 }
00219 
00220 
00221 void Channel::clearViewport( const eq::PixelViewport &pvp )
00222 {
00223     // clear given area
00224     glScissor(  pvp.x, pvp.y, pvp.w, pvp.h );
00225     glClearColor( _bgColor.r(), _bgColor.g(), _bgColor.b(), 1.0f );
00226     glClear( GL_COLOR_BUFFER_BIT );
00227 
00228     // restore assembly state
00229     const eq::PixelViewport& windowPVP = getWindow()->getPixelViewport();
00230     glScissor( 0, 0, windowPVP.w, windowPVP.h );
00231 }
00232 
00233 void Channel::_orderFrames( eq::FrameVector& frames )
00234 {
00235     eq::Matrix4f        modelviewM;   // modelview matrix
00236     eq::Matrix3f        modelviewITM; // modelview inversed transposed matrix
00237     const FrameData&    frameData = _getFrameData();
00238     const eq::Matrix4f& rotation  = frameData.getRotation();
00239 
00240     if( !frameData.useOrtho( ))
00241         _calcMVandITMV( modelviewM, modelviewITM );
00242 
00243     orderFrames( frames, modelviewM, modelviewITM, rotation, frameData.useOrtho( ));
00244 }
00245 
00246 
00247 void Channel::frameAssemble( const uint32_t frameID )
00248 {
00249     const bool composeOnly = (_drawRange == eq::Range::ALL);
00250 
00251     _startAssemble();
00252 
00253     const eq::FrameVector& frames = getInputFrames();
00254     eq::PixelViewport  coveredPVP;
00255     eq::FrameVector    dbFrames;
00256     eq::Zoom           zoom( eq::Zoom::NONE );
00257 
00258     // Make sure all frames are ready and gather some information on them
00259     for( eq::FrameVector::const_iterator i = frames.begin();
00260          i != frames.end(); ++i )
00261     {
00262         eq::Frame* frame = *i;
00263         {
00264             eq::ChannelStatistics stat(eq::Statistic::CHANNEL_WAIT_FRAME, this);
00265             frame->waitReady( );
00266         }
00267         const eq::Range& curRange = frame->getRange();
00268         if( curRange == eq::Range::ALL ) // 2D frame, assemble directly
00269             eq::Compositor::assembleFrame( frame, this );
00270         else
00271         {
00272             dbFrames.push_back( frame );
00273             zoom = frame->getZoom();
00274             _expandPVP( coveredPVP, frame->getImages(), frame->getOffset() );
00275         }
00276     }
00277     coveredPVP.intersect( getPixelViewport( ));
00278 
00279     if( dbFrames.empty( ))
00280     {
00281         resetAssemblyState();
00282         return;
00283     }
00284 
00285     // calculate correct frames sequence
00286     if( !composeOnly && coveredPVP.hasArea( ))
00287     {
00288         _frame.clear();
00289         _frame.setRange( _drawRange );
00290         dbFrames.push_back( &_frame );
00291     }
00292 
00293     _orderFrames( dbFrames );
00294 
00295     // check if current frame is in proper position, read back if not
00296     if( !composeOnly )
00297     {
00298         if( _bgColor == eq::Vector3f::ZERO && dbFrames.front() == &_frame )
00299             dbFrames.erase( dbFrames.begin( ));
00300         else if( coveredPVP.hasArea())
00301         {
00302             eq::Window::ObjectManager* glObjects = getObjectManager();
00303 
00304             _frame.setOffset( eq::Vector2i( 0, 0 ));
00305             _frame.setZoom( zoom );
00306             _frame.setPixelViewport( coveredPVP );
00307             _frame.startReadback( glObjects );
00308             clearViewport( coveredPVP );
00309             _frame.syncReadback();
00310 
00311             // offset for assembly
00312             _frame.setOffset( eq::Vector2i( coveredPVP.x, coveredPVP.y ));
00313         }
00314     }
00315 
00316     // blend DB frames in order
00317     eq::Compositor::assembleFramesSorted( dbFrames, this, 0, true /*blendAlpha*/ );
00318     resetAssemblyState();
00319 
00320     // Update range
00321     _drawRange = getRange();
00322 }
00323 
00324 void Channel::_startAssemble()
00325 {
00326     applyBuffer();
00327     applyViewport();
00328     setupAssemblyState();
00329 }   
00330 
00331 void Channel::frameReadback( const uint32_t frameID )
00332 {
00333     // Drop depth buffer flag from all output frames
00334     const eq::FrameVector& frames = getOutputFrames();
00335     for( eq::FrameVector::const_iterator i = frames.begin(); 
00336          i != frames.end(); ++i )
00337     {
00338         (*i)->disableBuffer( eq::Frame::BUFFER_DEPTH );
00339     }
00340 
00341     eq::Channel::frameReadback( frameID );
00342 }
00343 
00344 void Channel::frameViewFinish( const uint32_t frameID )
00345 {
00346     _drawHelp();
00347     _drawLogo();
00348 }
00349 
00350 void Channel::_drawLogo( )
00351 {
00352     // Draw the overlay logo
00353     const Window*  window      = static_cast<Window*>( getWindow( ));
00354     GLuint         texture;
00355     eq::Vector2i size;
00356 
00357     window->getLogoTexture( texture, size );
00358     if( !texture )
00359         return;
00360     
00361     glMatrixMode( GL_PROJECTION );
00362     glLoadIdentity();
00363     applyScreenFrustum();
00364     glMatrixMode( GL_MODELVIEW );
00365     glLoadIdentity();
00366 
00367     glDisable( GL_DEPTH_TEST );
00368     glDisable( GL_LIGHTING );
00369     glEnable( GL_BLEND );
00370     glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00371 
00372     glEnable( GL_TEXTURE_RECTANGLE_ARB );
00373     glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture );
00374     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
00375                      GL_LINEAR );
00376     glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, 
00377                      GL_LINEAR );
00378 
00379     glColor3f( 1.0f, 1.0f, 1.0f );
00380     glBegin( GL_TRIANGLE_STRIP ); {
00381         glTexCoord2f( 0.0f, 0.0f );
00382         glVertex3f( 5.0f, 5.0f, 0.0f );
00383 
00384         glTexCoord2f( size.x(), 0.0f );
00385         glVertex3f( size.x() + 5.0f, 5.0f, 0.0f );
00386 
00387         glTexCoord2f( 0.0f, size.y() );
00388         glVertex3f( 5.0f, size.y() + 5.0f, 0.0f );
00389 
00390         glTexCoord2f( size.x(), size.y() );
00391         glVertex3f( size.x() + 5.0f, size.y() + 5.0f, 0.0f );
00392     } glEnd();
00393 
00394     glDisable( GL_TEXTURE_RECTANGLE_ARB );
00395     glDisable( GL_BLEND );
00396 }
00397 
00398 void Channel::_drawHelp()
00399 {
00400     const FrameData& frameData = _getFrameData();
00401     std::string message = frameData.getMessage();
00402 
00403     if( !frameData.showHelp() && message.empty( ))
00404         return;
00405 
00406     EQ_GL_CALL( applyBuffer( ));
00407     EQ_GL_CALL( applyViewport( ));
00408     EQ_GL_CALL( setupAssemblyState( ));
00409 
00410     glDisable( GL_LIGHTING );
00411     glDisable( GL_DEPTH_TEST );
00412 
00413     glColor3f( 1.f, 1.f, 1.f );
00414 
00415     if( frameData.showHelp( ))
00416     {
00417         const eq::Window::Font* font = getWindow()->getSmallFont();
00418         std::string help = EVolve::getHelp();
00419         float y = 340.f;
00420 
00421         for( size_t pos = help.find( '\n' ); pos != std::string::npos;
00422              pos = help.find( '\n' ))
00423         {
00424             glRasterPos3f( 10.f, y, 0.99f );
00425 
00426             font->draw( help.substr( 0, pos ));
00427             help = help.substr( pos + 1 );
00428             y -= 16.f;
00429         }
00430         // last line
00431         glRasterPos3f( 10.f, y, 0.99f );
00432         font->draw( help );
00433     }
00434 
00435     if( !message.empty( ))
00436     {
00437         const eq::Window::Font* font = getWindow()->getMediumFont();
00438 
00439         const eq::Viewport& vp = getViewport();
00440         const eq::PixelViewport& pvp = getPixelViewport();
00441 
00442         const float width = pvp.w / vp.w;
00443         const float xOffset = vp.x * width;
00444 
00445         const float height = pvp.h / vp.h;
00446         const float yOffset = vp.y * height;
00447         const float yMiddle = 0.5f * height;
00448         float y = yMiddle - yOffset;
00449 
00450         for( size_t pos = message.find( '\n' ); pos != std::string::npos;
00451              pos = message.find( '\n' ))
00452         {
00453             glRasterPos3f( 10.f - xOffset, y, 0.99f );
00454             
00455             font->draw( message.substr( 0, pos ));
00456             message = message.substr( pos + 1 );
00457             y -= 22.f;
00458         }
00459         // last line
00460         glRasterPos3f( 10.f - xOffset, y, 0.99f );
00461         font->draw( message );
00462     }
00463 
00464     EQ_GL_CALL( resetAssemblyState( ));
00465 }
00466 
00467 
00468 }
Generated on Sat Feb 6 12:59:44 2010 for Equalizer 0.9.1 by  doxygen 1.6.1