examples/eqPly/channel.cpp

00001 
00002 /* Copyright (c) 2006-2009, Stefan Eilemann <eile@equalizergraphics.com> 
00003    Copyright (c) 2007, Tobias Wolf <twolf@access.unizh.ch>
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 "initData.h"
00022 #include "config.h"
00023 #include "pipe.h"
00024 #include "view.h"
00025 #include "window.h"
00026 #include "vertexBufferState.h"
00027 
00028 // light parameters
00029 static GLfloat lightPosition[] = {0.0f, 0.0f, 1.0f, 0.0f};
00030 static GLfloat lightAmbient[]  = {0.1f, 0.1f, 0.1f, 1.0f};
00031 static GLfloat lightDiffuse[]  = {0.8f, 0.8f, 0.8f, 1.0f};
00032 static GLfloat lightSpecular[] = {0.8f, 0.8f, 0.8f, 1.0f};
00033 
00034 // material properties
00035 static GLfloat materialAmbient[]  = {0.2f, 0.2f, 0.2f, 1.0f};
00036 static GLfloat materialDiffuse[]  = {0.8f, 0.8f, 0.8f, 1.0f};
00037 static GLfloat materialSpecular[] = {0.5f, 0.5f, 0.5f, 1.0f};
00038 static GLint  materialShininess   = 64;
00039 
00040 #ifndef M_SQRT3_2
00041 #  define M_SQRT3_2  0.86603f  /* sqrt(3)/2 */
00042 #endif
00043 
00044 namespace eqPly
00045 {
00046 bool Channel::configInit( const uint32_t initID )
00047 {
00048     if( !eq::Channel::configInit( initID ))
00049         return false;
00050 
00051     setNearFar( 0.1f, 10.0f );
00052     return true;
00053 }
00054 
00055 void Channel::frameClear( const uint32_t frameID )
00056 {
00057     EQ_GL_CALL( applyBuffer( ));
00058     EQ_GL_CALL( applyViewport( ));
00059 
00060     const eq::View*  view      = getView();
00061     const FrameData& frameData = _getFrameData();
00062     if( view && frameData.getCurrentViewID() == view->getID( ))
00063         glClearColor( .4f, .4f, .4f, 1.0f );
00064 #ifndef NDEBUG
00065     else if( getenv( "EQ_TAINT_CHANNELS" ))
00066     {
00067         const eq::Vector3ub color = getUniqueColor();
00068         glClearColor( color.r()/255.0f, color.g()/255.0f, color.b()/255.0f, 1.0f );
00069     }
00070 #endif // NDEBUG
00071     else
00072         glClearColor( 0.f, 0.f, 0.f, 1.0f );
00073 
00074     EQ_GL_CALL( glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ));
00075 }
00076 
00077 void Channel::frameDraw( const uint32_t frameID )
00078 {
00079     const Model* model = _getModel();
00080     if( model )
00081         _updateNearFar( model->getBoundingSphere( ));
00082 
00083     // Setup OpenGL state
00084     eq::Channel::frameDraw( frameID );
00085 
00086     glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );
00087     glLightfv( GL_LIGHT0, GL_AMBIENT,  lightAmbient  );
00088     glLightfv( GL_LIGHT0, GL_DIFFUSE,  lightDiffuse  );
00089     glLightfv( GL_LIGHT0, GL_SPECULAR, lightSpecular );
00090 
00091     glMaterialfv( GL_FRONT, GL_AMBIENT,   materialAmbient );
00092     glMaterialfv( GL_FRONT, GL_DIFFUSE,   materialDiffuse );
00093     glMaterialfv( GL_FRONT, GL_SPECULAR,  materialSpecular );
00094     glMateriali(  GL_FRONT, GL_SHININESS, materialShininess );
00095 
00096     const FrameData& frameData = _getFrameData();
00097     glPolygonMode( GL_FRONT_AND_BACK, 
00098                    frameData.useWireframe() ? GL_LINE : GL_FILL );
00099 
00100     const eq::Vector3f& translation = frameData.getCameraTranslation();
00101 
00102     glMultMatrixf( frameData.getCameraRotation().array );
00103     glTranslatef( translation.x(), translation.y(), translation.z() );
00104     glMultMatrixf( frameData.getModelRotation().array );
00105 
00106     if( frameData.getColorMode() == COLOR_DEMO )
00107     {
00108         const eq::Vector3ub color = getUniqueColor();
00109         glColor3ub( color.r(), color.g(), color.b() );
00110     }
00111     else
00112         glColor3f( .75f, .75f, .75f );
00113 
00114     if( model )
00115     {
00116         _drawModel( model );
00117     }
00118     else
00119     {
00120         glNormal3f( 0.f, -1.f, 0.f );
00121         glBegin( GL_TRIANGLE_STRIP );
00122         glVertex3f(  .25f, 0.f,  .25f );
00123         glVertex3f( -.25f, 0.f,  .25f );
00124         glVertex3f(  .25f, 0.f, -.25f );
00125         glVertex3f( -.25f, 0.f, -.25f );
00126         glEnd();
00127     }
00128 }
00129 
00130 void Channel::frameReadback( const uint32_t frameID )
00131 {
00132     // OPT: Drop alpha channel from all frames during network transport
00133     const eq::FrameVector& frames = getOutputFrames();
00134     for( eq::FrameVector::const_iterator i = frames.begin(); 
00135          i != frames.end(); ++i )
00136     {
00137         (*i)->setAlphaUsage( false );
00138     }
00139 
00140     eq::Channel::frameReadback( frameID );
00141 }
00142 
00143 const FrameData& Channel::_getFrameData() const
00144 {
00145     const Pipe* pipe = static_cast<const Pipe*>( getPipe( ));
00146     return pipe->getFrameData();
00147 }
00148 
00149 void Channel::applyFrustum() const
00150 {
00151     const FrameData& frameData = _getFrameData();
00152 
00153     if( frameData.useOrtho( ))
00154         eq::Channel::applyOrtho();
00155     else
00156         eq::Channel::applyFrustum();
00157 }
00158 
00159 const Model* Channel::_getModel()
00160 {
00161     Config*     config = static_cast< Config* >( getConfig( ));
00162     const View* view   = static_cast< const View* >( getView( ));
00163     EQASSERT( !view || dynamic_cast< const View* >( getView( )));
00164 
00165     if( view )
00166         return config->getModel( view->getModelID( ));
00167 
00168     const FrameData& frameData = _getFrameData();
00169     return config->getModel( frameData.getModelID( ));
00170 }
00171 
00172 void Channel::_drawModel( const Model* model )
00173 {
00174     Window*            window    = static_cast<Window*>( getWindow() );
00175     VertexBufferState& state     = window->getState();
00176     const FrameData&   frameData = _getFrameData();
00177     const eq::Range&   range     = getRange();
00178     eq::FrustumCullerf culler;
00179 
00180     if( frameData.getColorMode() == COLOR_MODEL && model->hasColors( ))
00181         state.setColors( true );
00182     else
00183         state.setColors( false );
00184 
00185     _initFrustum( culler, model->getBoundingSphere( ));
00186 
00187     const eq::Pipe* pipe = getPipe();
00188     const GLuint program = state.getProgram( pipe );
00189     if( program != VertexBufferState::INVALID )
00190         glUseProgram( program );
00191     
00192     model->beginRendering( state );
00193     
00194     // start with root node
00195     std::vector< const mesh::VertexBufferBase* > candidates;
00196     candidates.push_back( model );
00197 
00198 #ifndef NDEBUG
00199     size_t verticesRendered = 0;
00200     size_t verticesOverlap  = 0;
00201 #endif
00202 
00203     while( !candidates.empty() )
00204     {
00205         const mesh::VertexBufferBase* treeNode = candidates.back();
00206         candidates.pop_back();
00207             
00208         // completely out of range check
00209         if( treeNode->getRange()[0] >= range.end || 
00210             treeNode->getRange()[1] < range.start )
00211             continue;
00212             
00213         // bounding sphere view frustum culling
00214         const vmml::Visibility visibility =
00215             culler.test_sphere( treeNode->getBoundingSphere( ));
00216 
00217         switch( visibility )
00218         {
00219             case vmml::VISIBILITY_FULL:
00220                 // if fully visible and fully in range, render it
00221                 if( range == eq::Range::ALL || 
00222                     ( treeNode->getRange()[0] >= range.start && 
00223                       treeNode->getRange()[1] < range.end ))
00224                 {
00225                     treeNode->render( state );
00226                     //treeNode->renderBoundingSphere( state );
00227 #ifndef NDEBUG
00228                     verticesRendered += treeNode->getNumberOfVertices();
00229 #endif
00230                     break;
00231                 }
00232                 // partial range, fall through to partial visibility
00233 
00234             case vmml::VISIBILITY_PARTIAL:
00235             {
00236                 const mesh::VertexBufferBase* left  = treeNode->getLeft();
00237                 const mesh::VertexBufferBase* right = treeNode->getRight();
00238             
00239                 if( !left && !right )
00240                 {
00241                     if( treeNode->getRange()[0] >= range.start )
00242                     {
00243                         treeNode->render( state );
00244                         //treeNode->renderBoundingSphere( state );
00245 #ifndef NDEBUG
00246                         verticesRendered += treeNode->getNumberOfVertices();
00247                         if( visibility == vmml::VISIBILITY_PARTIAL )
00248                             verticesOverlap  += treeNode->getNumberOfVertices();
00249 #endif
00250                     }
00251                     // else drop, to be drawn by 'previous' channel
00252                 }
00253                 else
00254                 {
00255                     if( left )
00256                         candidates.push_back( left );
00257                     if( right )
00258                         candidates.push_back( right );
00259                 }
00260                 break;
00261             }
00262             case vmml::VISIBILITY_NONE:
00263                 // do nothing
00264                 break;
00265         }
00266     }
00267     
00268     model->endRendering( state );
00269     
00270     if( program != VertexBufferState::INVALID )
00271         glUseProgram( 0 );
00272 
00273 #ifndef NDEBUG
00274     const size_t verticesTotal = model->getNumberOfVertices();
00275     EQLOG( LOG_CULL ) 
00276         << getName() << " rendered " << verticesRendered * 100 / verticesTotal
00277         << "% of model, overlap <= " << verticesOverlap * 100 / verticesTotal
00278         << "%" << std::endl;
00279 #endif    
00280 }
00281 
00282 void Channel::frameViewFinish( const uint32_t frameID )
00283 {
00284     _drawOverlay();
00285     _drawHelp();
00286 }
00287 
00288 void Channel::_drawOverlay()
00289 {
00290     // Draw the overlay logo
00291     const Window* window      = static_cast<Window*>( getWindow( ));
00292     GLuint        texture;
00293     eq::Vector2i  size;
00294         
00295     window->getLogoTexture( texture, size );
00296         
00297     glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
00298     glMatrixMode( GL_PROJECTION );
00299     glLoadIdentity();
00300     applyScreenFrustum();
00301     glMatrixMode( GL_MODELVIEW );
00302     glLoadIdentity();
00303     
00304     glDisable( GL_DEPTH_TEST );
00305     glDisable( GL_LIGHTING );
00306     glColor3f( 1.0f, 1.0f, 1.0f );
00307 
00308 #if 1
00309     // border
00310     const eq::PixelViewport& pvp = getPixelViewport();
00311     const eq::Viewport& vp = getViewport();
00312     const float w = pvp.w / vp.w - .5f;
00313     const float h = pvp.h / vp.h - .5f;
00314 
00315     glBegin( GL_LINE_LOOP );
00316     {
00317         glVertex3f( .5f, .5f, 0.f );
00318         glVertex3f(   w, .5f, 0.f );
00319         glVertex3f(   w,   h, 0.f );
00320         glVertex3f( .5f,   h, 0.f );
00321     } 
00322     glEnd();
00323 #endif
00324 
00325     // logo
00326     if( texture )
00327     {
00328         glEnable( GL_BLEND );
00329         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00330         
00331         glEnable( GL_TEXTURE_RECTANGLE_ARB );
00332         glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture );
00333         glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
00334                          GL_LINEAR );
00335         glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, 
00336                          GL_LINEAR );
00337     
00338         glBegin( GL_TRIANGLE_STRIP ); {
00339             glTexCoord2f( 0.0f, 0.0f );
00340             glVertex3f( 5.0f, 5.0f, 0.0f );
00341             
00342             glTexCoord2f( size.x(), 0.0f );
00343             glVertex3f( size.x() + 5.0f, 5.0f, 0.0f );
00344             
00345             glTexCoord2f( 0.0f, size.y() );
00346             glVertex3f( 5.0f, size.y() + 5.0f, 0.0f );
00347             
00348             glTexCoord2f( size.x(), size.y() );
00349             glVertex3f( size.x() + 5.0f, size.y() + 5.0f, 0.0f );
00350         } glEnd();
00351     
00352         glDisable( GL_TEXTURE_RECTANGLE_ARB );
00353         glDisable( GL_BLEND );
00354     }
00355     glEnable( GL_LIGHTING );
00356     glEnable( GL_DEPTH_TEST );
00357 }
00358 
00359 void Channel::_drawHelp()
00360 {
00361     const FrameData& frameData = _getFrameData();
00362     std::string message = frameData.getMessage();
00363 
00364     if( !frameData.showHelp() && message.empty( ))
00365         return;
00366 
00367     EQ_GL_CALL( applyBuffer( ));
00368     EQ_GL_CALL( applyViewport( ));
00369     EQ_GL_CALL( setupAssemblyState( ));
00370 
00371     glDisable( GL_LIGHTING );
00372     glDisable( GL_DEPTH_TEST );
00373 
00374     glColor3f( 1.f, 1.f, 1.f );
00375 
00376     if( frameData.showHelp( ))
00377     {
00378         const eq::util::BitmapFont& font = getObjectManager()->getDefaultFont();
00379         std::string help = EqPly::getHelp();
00380         float y = 340.f;
00381 
00382         for( size_t pos = help.find( '\n' ); pos != std::string::npos;
00383              pos = help.find( '\n' ))
00384         {
00385             glRasterPos3f( 10.f, y, 0.99f );
00386             
00387             font.draw( help.substr( 0, pos ));
00388             help = help.substr( pos + 1 );
00389             y -= 16.f;
00390         }
00391         // last line
00392         glRasterPos3f( 10.f, y, 0.99f );
00393         font.draw( help );
00394     }
00395 
00396     if( !message.empty( ))
00397     {
00398         const eq::util::BitmapFont& font = getObjectManager()->getMediumFont();
00399 
00400         const eq::Viewport& vp = getViewport();
00401         const eq::PixelViewport& pvp = getPixelViewport();
00402 
00403         const float width = pvp.w / vp.w;
00404         const float xOffset = vp.x * width;
00405 
00406         const float height = pvp.h / vp.h;
00407         const float yOffset = vp.y * height;
00408         const float yMiddle = 0.5f * height;
00409         float y = yMiddle - yOffset;
00410 
00411         for( size_t pos = message.find( '\n' ); pos != std::string::npos;
00412              pos = message.find( '\n' ))
00413         {
00414             glRasterPos3f( 10.f - xOffset, y, 0.99f );
00415             
00416             font.draw( message.substr( 0, pos ));
00417             message = message.substr( pos + 1 );
00418             y -= 22.f;
00419         }
00420         // last line
00421         glRasterPos3f( 10.f - xOffset, y, 0.99f );
00422         font.draw( message );
00423     }
00424 
00425     EQ_GL_CALL( resetAssemblyState( ));
00426 }
00427 
00428 void Channel::_updateNearFar( const mesh::BoundingSphere& boundingSphere )
00429 {
00430     // compute dynamic near/far plane of whole model
00431     const FrameData& frameData = _getFrameData();
00432     const bool ortho = frameData.useOrtho();
00433 
00434     const eq::Matrix4f& rotation     = frameData.getCameraRotation();
00435     const eq::Matrix4f headTransform = getHeadTransform() * rotation;
00436 
00437     eq::Matrix4f modelInv;
00438     compute_inverse( headTransform, modelInv );
00439 
00440     const eq::Vector3f zero  = modelInv * eq::Vector3f::ZERO;
00441     eq::Vector3f       front = modelInv * eq::Vector3f( 0.0f, 0.0f, -1.0f );
00442 
00443     front -= zero;
00444     front.normalize();
00445     front *= boundingSphere.w();
00446 
00447     const eq::Vector3f center = boundingSphere.get_sub_vector< 3 >() + 
00448                         frameData.getCameraTranslation( ).get_sub_vector< 3 >();
00449     const eq::Vector3f nearPoint  = headTransform * ( center - front );
00450     const eq::Vector3f farPoint   = headTransform * ( center + front );
00451 
00452     if( ortho )
00453     {
00454         EQASSERT( fabs( farPoint.z() - nearPoint.z() ) > 
00455                   std::numeric_limits< float >::epsilon( ));
00456         setNearFar( -nearPoint.z(), -farPoint.z() );
00457     }
00458     else
00459     {
00460         // estimate minimal value of near plane based on frustum size
00461         const eq::Frustumf& frustum = getFrustum();
00462         const float width  = fabs( frustum.right() - frustum.left() );
00463         const float height = fabs( frustum.top() - frustum.bottom() );
00464         const float size   = EQ_MIN( width, height );
00465         const float minNear = frustum.near_plane() / size * .001f;
00466 
00467         const float zNear = EQ_MAX( minNear, -nearPoint.z() );
00468         const float zFar  = EQ_MAX( zNear * 2.f, -farPoint.z() );
00469 
00470         setNearFar( zNear, zFar );
00471     }
00472 }
00473 
00474 void Channel::_initFrustum( eq::FrustumCullerf& culler,
00475                             const mesh::BoundingSphere& boundingSphere )
00476 {
00477     // setup frustum cull helper
00478     const FrameData& frameData = _getFrameData();
00479     const eq::Matrix4f& rotation     = frameData.getCameraRotation();
00480     const eq::Matrix4f& modelRotation = frameData.getModelRotation();
00481           eq::Matrix4f  translation   = eq::Matrix4f::IDENTITY;
00482     translation.set_translation( frameData.getCameraTranslation());
00483 
00484     const eq::Matrix4f modelView = 
00485         getHeadTransform() * rotation * translation * modelRotation;
00486 
00487     const bool ortho = frameData.useOrtho();
00488     const eq::Frustumf& frustum      = ortho ? getOrtho() : getFrustum();
00489     const eq::Matrix4f  projection   = ortho ? frustum.compute_ortho_matrix() :
00490                                                frustum.compute_matrix();
00491     culler.setup( projection * modelView );
00492 }
00493 }
Generated on Mon Aug 10 18:58:31 2009 for Equalizer 0.9 by  doxygen 1.5.8