examples/eqPly/channel.cpp

00001 
00002 /* Copyright (c) 2006-2010, 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 "configEvent.h"
00024 #include "pipe.h"
00025 #include "view.h"
00026 #include "window.h"
00027 #include "vertexBufferState.h"
00028 
00029 // light parameters
00030 static GLfloat lightPosition[] = {0.0f, 0.0f, 1.0f, 0.0f};
00031 static GLfloat lightAmbient[]  = {0.1f, 0.1f, 0.1f, 1.0f};
00032 static GLfloat lightDiffuse[]  = {0.8f, 0.8f, 0.8f, 1.0f};
00033 static GLfloat lightSpecular[] = {0.8f, 0.8f, 0.8f, 1.0f};
00034 
00035 // material properties
00036 static GLfloat materialAmbient[]  = {0.2f, 0.2f, 0.2f, 1.0f};
00037 static GLfloat materialDiffuse[]  = {0.8f, 0.8f, 0.8f, 1.0f};
00038 static GLfloat materialSpecular[] = {0.5f, 0.5f, 0.5f, 1.0f};
00039 static GLint  materialShininess   = 64;
00040 
00041 #ifndef M_SQRT3_2
00042 #  define M_SQRT3_2  0.86603f  /* sqrt(3)/2 */
00043 #endif
00044 
00045 namespace eqPly
00046 {
00047 
00048 Channel::Channel( eq::Window* parent )
00049         : eq::Channel( parent )
00050         , _model(0)
00051         , _modelID( EQ_ID_INVALID )
00052 {
00053 }
00054 
00055 bool Channel::configInit( const uint32_t initID )
00056 {
00057     EQINFO << getID() << ": " << getName() << std::endl;
00058     if( !eq::Channel::configInit( initID ))
00059         return false;
00060 
00061     setNearFar( 0.1f, 10.0f );
00062     _model = 0;
00063     _modelID = EQ_ID_INVALID;
00064     return true;
00065 }
00066 
00067 bool Channel::configExit()
00068 {
00069     for( size_t i = 0; i < eq::EYE_ALL; ++i )
00070     {
00071         delete _accum[ i ].buffer;
00072         _accum[ i ].buffer = 0;
00073     }
00074 
00075     return true;
00076 }
00077 
00078 void Channel::frameClear( const uint32_t frameID )
00079 {
00080     _initJitter();
00081     const FrameData& frameData = _getFrameData();
00082     if( _isDone() && !_accum[ getEye() ].transfer )
00083         return;
00084 
00085     applyBuffer();
00086     applyViewport();
00087 
00088     const eq::View*  view      = getView();
00089     if( view && frameData.getCurrentViewID() == view->getID( ))
00090         glClearColor( .4f, .4f, .4f, 1.0f );
00091 #ifndef NDEBUG
00092     else if( getenv( "EQ_TAINT_CHANNELS" ))
00093     {
00094         const eq::Vector3ub color = getUniqueColor();
00095         glClearColor( color.r()/255.0f,
00096                       color.g()/255.0f,
00097                       color.b()/255.0f, 1.0f );
00098     }
00099 #endif // NDEBUG
00100     else
00101         glClearColor( 0.f, 0.f, 0.f, 1.0f );
00102 
00103     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
00104 }
00105 
00106 void Channel::frameDraw( const uint32_t frameID )
00107 {
00108     _initJitter();
00109     if( _isDone( ))
00110         return;
00111 
00112     const Model* model = _getModel();
00113     if( model )
00114         _updateNearFar( model->getBoundingSphere( ));
00115 
00116     // Setup OpenGL state
00117     eq::Channel::frameDraw( frameID );
00118 
00119     glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );
00120     glLightfv( GL_LIGHT0, GL_AMBIENT,  lightAmbient  );
00121     glLightfv( GL_LIGHT0, GL_DIFFUSE,  lightDiffuse  );
00122     glLightfv( GL_LIGHT0, GL_SPECULAR, lightSpecular );
00123 
00124     glMaterialfv( GL_FRONT, GL_AMBIENT,   materialAmbient );
00125     glMaterialfv( GL_FRONT, GL_DIFFUSE,   materialDiffuse );
00126     glMaterialfv( GL_FRONT, GL_SPECULAR,  materialSpecular );
00127     glMateriali(  GL_FRONT, GL_SHININESS, materialShininess );
00128 
00129     const FrameData& frameData = _getFrameData();
00130     glPolygonMode( GL_FRONT_AND_BACK, 
00131                    frameData.useWireframe() ? GL_LINE : GL_FILL );
00132 
00133     const eq::Vector3f& translation = frameData.getCameraTranslation();
00134 
00135     glMultMatrixf( frameData.getCameraRotation().array );
00136     glTranslatef( translation.x(), translation.y(), translation.z() );
00137     glMultMatrixf( frameData.getModelRotation().array );
00138 
00139     if( frameData.getColorMode() == COLOR_DEMO )
00140     {
00141         const eq::Vector3ub color = getUniqueColor();
00142         glColor3ub( color.r(), color.g(), color.b() );
00143     }
00144     else
00145         glColor3f( .75f, .75f, .75f );
00146 
00147     if( model )
00148     {
00149         _drawModel( model );
00150     }
00151     else
00152     {
00153         glNormal3f( 0.f, -1.f, 0.f );
00154         glBegin( GL_TRIANGLE_STRIP );
00155         glVertex3f(  .25f, 0.f,  .25f );
00156         glVertex3f( -.25f, 0.f,  .25f );
00157         glVertex3f(  .25f, 0.f, -.25f );
00158         glVertex3f( -.25f, 0.f, -.25f );
00159         glEnd();
00160     }
00161 
00162     Accum& accum = _accum[ getEye() ];
00163     accum.stepsDone = EQ_MAX( accum.stepsDone, 
00164                               getSubPixel().size * getPeriod( ));
00165     accum.transfer = true;
00166 }
00167 
00168 void Channel::frameAssemble( const uint32_t frameID )
00169 {
00170     if( _isDone( ))
00171         return;
00172 
00173     Accum& accum = _accum[ getEye() ];
00174 
00175     if( getPixelViewport() != _currentPVP )
00176     {
00177         accum.transfer = true;
00178 
00179         if( accum.buffer && !accum.buffer->usesFBO( ))
00180         {
00181             EQWARN << "Current viewport different from view viewport, ";
00182             EQWARN << "idle anti-aliasing not implemented." << std::endl;
00183             accum.step = 0;
00184         }
00185 
00186         eq::Channel::frameAssemble( frameID );
00187         return;
00188     }
00189     // else
00190     
00191     bool subPixelALL = true;
00192     const eq::FrameVector& frames = getInputFrames();
00193 
00194     for( eq::FrameVector::const_iterator i = frames.begin();
00195          i != frames.end(); ++i )
00196     {
00197         eq::Frame* frame = *i;
00198         const eq::SubPixel& curSubPixel = frame->getSubPixel();
00199 
00200         if( curSubPixel != eq::SubPixel::ALL )
00201             subPixelALL = false;
00202 
00203         accum.stepsDone = EQ_MAX( accum.stepsDone, 
00204                                   frame->getSubPixel().size*frame->getPeriod());
00205     }
00206 
00207     accum.transfer = subPixelALL;
00208 
00209     applyBuffer();
00210     applyViewport();
00211     setupAssemblyState();
00212 
00213     eq::Compositor::assembleFrames( getInputFrames(), this, accum.buffer );
00214 
00215     resetAssemblyState();
00216 }
00217 
00218 void Channel::frameReadback( const uint32_t frameID )
00219 {
00220     if( _isDone( ))
00221         return;
00222 
00223     // OPT: Drop alpha channel from all frames during network transport
00224     const eq::FrameVector& frames = getOutputFrames();
00225     for( eq::FrameVector::const_iterator i = frames.begin(); 
00226          i != frames.end(); ++i )
00227     {
00228         (*i)->setAlphaUsage( false );
00229     }
00230 
00231     eq::Channel::frameReadback( frameID );
00232 }
00233 
00234 void Channel::frameStart( const uint32_t frameID, const uint32_t frameNumber )
00235 {
00236     for( size_t i = 0; i < eq::EYE_ALL; ++i )
00237         _accum[ i ].stepsDone = 0;
00238 
00239     eq::Channel::frameStart( frameID, frameNumber );
00240 }
00241 
00242 void Channel::frameViewStart( const uint32_t frameID )
00243 {
00244     _currentPVP = getPixelViewport();
00245     _initJitter();
00246     eq::Channel::frameViewStart( frameID );
00247 }
00248 
00249 void Channel::frameFinish( const uint32_t frameID,
00250                            const uint32_t frameNumber )
00251 {
00252     for( size_t i = 0; i < eq::EYE_ALL; ++i )
00253     {
00254         Accum& accum = _accum[ i ];
00255         if( accum.step > 0 )
00256         {
00257             if( static_cast< int32_t >( accum.stepsDone ) > accum.step )
00258                 accum.step = 0;
00259             else
00260                 accum.step -= accum.stepsDone;
00261         }
00262     }
00263 
00264     eq::Channel::frameFinish( frameID, frameNumber );
00265 }
00266 
00267 void Channel::frameViewFinish( const uint32_t frameID )
00268 {
00269     applyBuffer();
00270 
00271     const FrameData& frameData = _getFrameData();
00272     Accum& accum = _accum[ getEye() ];
00273 
00274     if( accum.buffer )
00275     {
00276         const eq::PixelViewport& pvp = getPixelViewport();
00277         const bool isResized = accum.buffer->resize( pvp.w, pvp.h );
00278 
00279         if( isResized )
00280         {
00281             const View* view = static_cast< const View* >( getView( ));
00282             accum.buffer->clear();
00283             accum.step = view->getIdleSteps();
00284             accum.stepsDone = 0;
00285         }
00286         else if( frameData.isIdle( ))
00287         {
00288             setupAssemblyState();
00289 
00290             if( !_isDone() && accum.transfer )
00291                 accum.buffer->accum();
00292             accum.buffer->display();
00293 
00294             resetAssemblyState();
00295         }
00296     }
00297 
00298     applyViewport();
00299     _drawOverlay();
00300     _drawHelp();
00301 
00302     if( frameData.useStatistics())
00303         drawStatistics();
00304 
00305     ConfigEvent event;
00306     event.data.originator = getID();
00307     event.data.type = ConfigEvent::IDLE_AA_LEFT;
00308 
00309     const bool isIdle = frameData.isIdle();
00310 
00311     if( isIdle )
00312     {
00313         int32_t maxSteps = 0;
00314         for( size_t i = 0; i < eq::EYE_ALL; ++i )
00315             maxSteps = EQ_MAX( maxSteps, _accum[i].step );
00316 
00317         event.steps = maxSteps;
00318     }
00319     else
00320     {
00321         const View* view = static_cast< const View* >( getView( ));
00322         if( view )
00323             event.steps = view->getIdleSteps();
00324         else
00325             event.steps = 0;
00326     }
00327 
00328     // if _jitterStep == 0 and no user redraw event happened, the app will exit
00329     // FSAA idle mode and block on the next redraw event.
00330     eq::Config* config = getConfig();
00331     config->sendEvent( event );
00332 }
00333 
00334 void Channel::applyFrustum() const
00335 {
00336     const FrameData& frameData = _getFrameData();
00337     const eq::Vector2f jitter = _getJitter();
00338 
00339     if( frameData.useOrtho( ))
00340     {
00341         eq::Frustumf ortho = getOrtho();
00342         ortho.apply_jitter( jitter );
00343 
00344         glOrtho( ortho.left(), ortho.right(),
00345                  ortho.bottom(), ortho.top(),
00346                  ortho.near_plane(), ortho.far_plane( ));
00347     }
00348     else
00349     {
00350         eq::Frustumf frustum = getFrustum();
00351         frustum.apply_jitter( jitter );
00352 
00353         glFrustum( frustum.left(), frustum.right(),
00354                    frustum.bottom(), frustum.top(),
00355                    frustum.near_plane(), frustum.far_plane( ));
00356     }
00357 }
00358 
00359 const FrameData& Channel::_getFrameData() const
00360 {
00361     const Pipe* pipe = static_cast<const Pipe*>( getPipe( ));
00362     return pipe->getFrameData();
00363 }
00364 
00365 bool Channel::_isDone() const
00366 {
00367     const FrameData& frameData = _getFrameData();
00368     if( !frameData.isIdle( ))
00369         return false;
00370 
00371     const eq::SubPixel& subpixel = getSubPixel();
00372     const Accum& accum = _accum[ getEye() ];
00373     return static_cast< int32_t >( subpixel.index ) >= accum.step;
00374 }
00375 
00376 void Channel::_initJitter()
00377 {
00378     if( !_initAccum( ))
00379         return;
00380 
00381     const FrameData& frameData = _getFrameData();
00382     if( frameData.isIdle( ))
00383         return;
00384 
00385     const View* view = static_cast< const View* >( getView( ));
00386     const uint32_t totalSteps = view->getIdleSteps();
00387 
00388     if( totalSteps == 0 )
00389         return;
00390 
00391     // ready for the next FSAA
00392     Accum& accum = _accum[ getEye() ];
00393 
00394     if( accum.buffer )
00395         accum.buffer->clear();
00396     accum.step = totalSteps;
00397 }
00398 
00399 bool Channel::_initAccum()
00400 {
00401     if( !getNativeView( )) // Only alloc accum for dest
00402         return true;
00403 
00404     const eq::Eye eye = getEye();
00405     Accum& accum = _accum[ eye ];
00406 
00407     if( accum.buffer ) // already done
00408         return true;
00409 
00410     if( accum.step == -1 ) // accum init failed last time
00411         return false;
00412 
00413     // Check unsupported cases
00414     if( !eq::util::Accum::usesFBO( glewGetContext( )))
00415     {
00416         for( size_t i = 0; i < eq::EYE_ALL; ++i )
00417         {
00418             if( _accum[ i ].buffer )
00419             {
00420                 EQWARN << "glAccum-based accumulation does not support "
00421                        << "stereo, disabling idle anti-aliasing."
00422                        << std::endl;
00423                 for( size_t j = 0; j < eq::EYE_ALL; ++j )
00424                 {
00425                     delete _accum[ j ].buffer;
00426                     _accum[ j ].buffer = 0;
00427                     _accum[ j ].step = -1;
00428                 }
00429 
00430                 ConfigEvent event;
00431                 event.data.type = ConfigEvent::IDLE_AA_TOTAL;
00432                 event.data.originator = getNativeView()->getID();
00433                 event.steps = 0;
00434 
00435                 eq::Config* config = getConfig();
00436                 config->sendEvent( event );
00437                 return false;
00438             }
00439         }
00440     }
00441 
00442     // set up accumulation buffer
00443     accum.buffer = new eq::util::Accum( glewGetContext( ));
00444     const eq::PixelViewport& pvp = getPixelViewport();
00445     EQASSERT( pvp.isValid( ));
00446 
00447     if( !accum.buffer->init( pvp, getWindow()->getColorFormat( )) ||
00448         accum.buffer->getMaxSteps() < 256 )
00449     {
00450         EQWARN <<"Accumulation buffer initialization failed, "
00451                << "idle AA not available." << std::endl;
00452         delete accum.buffer;
00453         accum.buffer = 0;
00454         accum.step = -1;
00455         return false;
00456     }
00457 
00458     // else
00459     EQINFO << "Initialized "
00460            << (accum.buffer->usesFBO() ? "FBO accum" : "glAccum")
00461            << " buffer for " << getName() << " " << getEye() 
00462            << std::endl;
00463 
00464     ConfigEvent event;
00465     event.data.type = ConfigEvent::IDLE_AA_TOTAL;
00466     event.data.originator = getNativeView()->getID();
00467     event.steps = accum.buffer ? 256 : 0;
00468 
00469     eq::Config* config = getConfig();
00470     config->sendEvent( event );
00471     return true;
00472 }
00473 
00474 eq::Vector2f Channel::_getJitter() const
00475 {
00476     const FrameData& frameData = _getFrameData();
00477     const Accum& accum = _accum[ getEye() ];
00478 
00479     if( !frameData.isIdle() || accum.step <= 0 )
00480         return eq::Channel::getJitter();
00481 
00482     const View* view = static_cast< const View* >( getView( ));
00483     if( !view || view->getIdleSteps() != 256 )
00484         return eq::Vector2f::ZERO;
00485 
00486     eq::Vector2i jitterStep = _getJitterStep();
00487     if( jitterStep == eq::Vector2i::ZERO )
00488         return eq::Vector2f::ZERO;
00489 
00490     const eq::PixelViewport& pvp = getPixelViewport();
00491     const float pvp_w = static_cast<float>( pvp.w );
00492     const float pvp_h = static_cast<float>( pvp.h );
00493     const float frustum_w = static_cast<float>(( getFrustum().get_width( )));
00494     const float frustum_h = static_cast<float>(( getFrustum().get_height( )));
00495 
00496     const float pixel_w = frustum_w / pvp_w;
00497     const float pixel_h = frustum_h / pvp_h;
00498 
00499     const float sampleSize = 16.f; // sqrt( 256 )
00500     const float subpixel_w = pixel_w / sampleSize;
00501     const float subpixel_h = pixel_h / sampleSize;
00502 
00503     // Sample value randomly computed within the subpixel
00504     eq::base::RNG rng;
00505     float value_i = rng.get< float >() * subpixel_w
00506                     + static_cast<float>( jitterStep.x( )) * subpixel_w;
00507 
00508     float value_j = rng.get< float >() * subpixel_h
00509                     + static_cast<float>( jitterStep.y( )) * subpixel_h;
00510 
00511     const eq::Pixel& pixel = getPixel();
00512     value_i /= static_cast<float>( pixel.w );
00513     value_j /= static_cast<float>( pixel.h );
00514 
00515     return eq::Vector2f( value_i, value_j );
00516 }
00517 
00518 eq::Vector2i Channel::_getJitterStep() const
00519 {
00520     const eq::SubPixel& subPixel = getSubPixel();
00521     uint32_t channelID = subPixel.index;
00522     const View* view = static_cast< const View* >( getView( ));
00523     if( !view )
00524         return eq::Vector2i::ZERO;
00525 
00526     const uint32_t totalSteps = view->getIdleSteps();
00527     if( totalSteps != 256 )
00528         return eq::Vector2i::ZERO;
00529 
00530     const Accum& accum = _accum[ getEye() ];
00531     const uint32_t subset = totalSteps / getSubPixel().size;
00532     const uint32_t idx = 
00533         ( accum.step * primeNumberTable[ channelID ] ) % subset +
00534         ( channelID * subset );
00535 
00536     const uint32_t sampleSize = 16;
00537     const int dx = idx % sampleSize;
00538     const int dy = idx / sampleSize;
00539 
00540     return eq::Vector2i( dx, dy );
00541 }
00542 
00543 const Model* Channel::_getModel()
00544 {
00545     Config*     config = static_cast< Config* >( getConfig( ));
00546     const View* view   = static_cast< const View* >( getView( ));
00547     const FrameData& frameData = _getFrameData();
00548     EQASSERT( !view || dynamic_cast< const View* >( getView( )));
00549 
00550     const uint32_t id = view ? view->getModelID() : frameData.getModelID();
00551     if( id != _modelID )
00552     {
00553         _model = config->getModel( id );
00554         _modelID = id;
00555     }
00556 
00557     return _model;
00558 }
00559 
00560 void Channel::_drawModel( const Model* model )
00561 {
00562     Window*            window    = static_cast<Window*>( getWindow() );
00563     VertexBufferState& state     = window->getState();
00564     const FrameData&   frameData = _getFrameData();
00565     const eq::Range&   range     = getRange();
00566     eq::FrustumCullerf culler;
00567 
00568     if( frameData.getColorMode() == COLOR_MODEL && model->hasColors( ))
00569         state.setColors( true );
00570     else
00571         state.setColors( false );
00572 
00573     _initFrustum( culler, model->getBoundingSphere( ));
00574 
00575     const eq::Pipe* pipe = getPipe();
00576     const GLuint program = state.getProgram( pipe );
00577     if( program != VertexBufferState::INVALID )
00578         glUseProgram( program );
00579     
00580     model->beginRendering( state );
00581     
00582     // start with root node
00583     std::vector< const mesh::VertexBufferBase* > candidates;
00584     candidates.push_back( model );
00585 
00586 #ifndef NDEBUG
00587     size_t verticesRendered = 0;
00588     size_t verticesOverlap  = 0;
00589 #endif
00590 
00591     while( !candidates.empty() )
00592     {
00593         const mesh::VertexBufferBase* treeNode = candidates.back();
00594         candidates.pop_back();
00595             
00596         // completely out of range check
00597         if( treeNode->getRange()[0] >= range.end || 
00598             treeNode->getRange()[1] < range.start )
00599             continue;
00600             
00601         // bounding sphere view frustum culling
00602         const vmml::Visibility visibility =
00603             culler.test_sphere( treeNode->getBoundingSphere( ));
00604 
00605         switch( visibility )
00606         {
00607             case vmml::VISIBILITY_FULL:
00608                 // if fully visible and fully in range, render it
00609                 if( range == eq::Range::ALL || 
00610                     ( treeNode->getRange()[0] >= range.start && 
00611                       treeNode->getRange()[1] < range.end ))
00612                 {
00613                     treeNode->render( state );
00614                     //treeNode->renderBoundingSphere( state );
00615 #ifndef NDEBUG
00616                     verticesRendered += treeNode->getNumberOfVertices();
00617 #endif
00618                     break;
00619                 }
00620                 // partial range, fall through to partial visibility
00621 
00622             case vmml::VISIBILITY_PARTIAL:
00623             {
00624                 const mesh::VertexBufferBase* left  = treeNode->getLeft();
00625                 const mesh::VertexBufferBase* right = treeNode->getRight();
00626             
00627                 if( !left && !right )
00628                 {
00629                     if( treeNode->getRange()[0] >= range.start )
00630                     {
00631                         treeNode->render( state );
00632                         //treeNode->renderBoundingSphere( state );
00633 #ifndef NDEBUG
00634                         verticesRendered += treeNode->getNumberOfVertices();
00635                         if( visibility == vmml::VISIBILITY_PARTIAL )
00636                             verticesOverlap  += treeNode->getNumberOfVertices();
00637 #endif
00638                     }
00639                     // else drop, to be drawn by 'previous' channel
00640                 }
00641                 else
00642                 {
00643                     if( left )
00644                         candidates.push_back( left );
00645                     if( right )
00646                         candidates.push_back( right );
00647                 }
00648                 break;
00649             }
00650             case vmml::VISIBILITY_NONE:
00651                 // do nothing
00652                 break;
00653         }
00654     }
00655     
00656     model->endRendering( state );
00657     
00658     if( program != VertexBufferState::INVALID )
00659         glUseProgram( 0 );
00660 
00661 #ifndef NDEBUG
00662     const size_t verticesTotal = model->getNumberOfVertices();
00663     EQLOG( LOG_CULL ) 
00664         << getName() << " rendered " << verticesRendered * 100 / verticesTotal
00665         << "% of model, overlap <= " << verticesOverlap * 100 / verticesTotal
00666         << "%" << std::endl;
00667 #endif    
00668 }
00669 
00670 void Channel::_drawOverlay()
00671 {
00672     // Draw the overlay logo
00673     const Window* window = static_cast<Window*>( getWindow( ));
00674     GLuint texture;
00675     eq::Vector2i  size;
00676         
00677     window->getLogoTexture( texture, size );
00678         
00679     glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
00680     glMatrixMode( GL_PROJECTION );
00681     glLoadIdentity();
00682     applyScreenFrustum();
00683     glMatrixMode( GL_MODELVIEW );
00684     glLoadIdentity();
00685     
00686     glDisable( GL_DEPTH_TEST );
00687     glDisable( GL_LIGHTING );
00688     glColor3f( 1.0f, 1.0f, 1.0f );
00689 
00690 #if 1
00691     // border
00692     const eq::PixelViewport& pvp = getPixelViewport();
00693     const eq::Viewport& vp = getViewport();
00694     const float w = pvp.w / vp.w - .5f;
00695     const float h = pvp.h / vp.h - .5f;
00696 
00697     glBegin( GL_LINE_LOOP );
00698     {
00699         glVertex3f( .5f, .5f, 0.f );
00700         glVertex3f(   w, .5f, 0.f );
00701         glVertex3f(   w,   h, 0.f );
00702         glVertex3f( .5f,   h, 0.f );
00703     } 
00704     glEnd();
00705 #endif
00706 
00707     // logo
00708     if( texture )
00709     {
00710         glEnable( GL_BLEND );
00711         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00712         
00713         glEnable( GL_TEXTURE_RECTANGLE_ARB );
00714         glBindTexture( GL_TEXTURE_RECTANGLE_ARB, texture );
00715         glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
00716                          GL_LINEAR );
00717         glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, 
00718                          GL_LINEAR );
00719     
00720         glBegin( GL_TRIANGLE_STRIP ); {
00721             glTexCoord2f( 0.0f, 0.0f );
00722             glVertex3f( 5.0f, 5.0f, 0.0f );
00723             
00724             glTexCoord2f( size.x(), 0.0f );
00725             glVertex3f( size.x() + 5.0f, 5.0f, 0.0f );
00726             
00727             glTexCoord2f( 0.0f, size.y() );
00728             glVertex3f( 5.0f, size.y() + 5.0f, 0.0f );
00729             
00730             glTexCoord2f( size.x(), size.y() );
00731             glVertex3f( size.x() + 5.0f, size.y() + 5.0f, 0.0f );
00732         } glEnd();
00733     
00734         glDisable( GL_TEXTURE_RECTANGLE_ARB );
00735         glDisable( GL_BLEND );
00736     }
00737     glEnable( GL_LIGHTING );
00738     glEnable( GL_DEPTH_TEST );
00739 }
00740 
00741 void Channel::_drawHelp()
00742 {
00743     const FrameData& frameData = _getFrameData();
00744     std::string message = frameData.getMessage();
00745 
00746     if( !frameData.showHelp() && message.empty( ))
00747         return;
00748 
00749     applyBuffer();
00750     applyViewport();
00751     setupAssemblyState();
00752 
00753     glDisable( GL_LIGHTING );
00754     glDisable( GL_DEPTH_TEST );
00755 
00756     glColor3f( 1.f, 1.f, 1.f );
00757 
00758     if( frameData.showHelp( ))
00759     {
00760         const eq::Window::Font* font = getWindow()->getSmallFont();
00761         std::string help = EqPly::getHelp();
00762         float y = 340.f;
00763 
00764         for( size_t pos = help.find( '\n' ); pos != std::string::npos;
00765              pos = help.find( '\n' ))
00766         {
00767             glRasterPos3f( 10.f, y, 0.99f );
00768             
00769             font->draw( help.substr( 0, pos ));
00770             help = help.substr( pos + 1 );
00771             y -= 16.f;
00772         }
00773         // last line
00774         glRasterPos3f( 10.f, y, 0.99f );
00775         font->draw( help );
00776     }
00777 
00778     if( !message.empty( ))
00779     {
00780         const eq::Window::Font* font = getWindow()->getMediumFont();
00781 
00782         const eq::Viewport& vp = getViewport();
00783         const eq::PixelViewport& pvp = getPixelViewport();
00784 
00785         const float width = pvp.w / vp.w;
00786         const float xOffset = vp.x * width;
00787 
00788         const float height = pvp.h / vp.h;
00789         const float yOffset = vp.y * height;
00790         const float yMiddle = 0.5f * height;
00791         float y = yMiddle - yOffset;
00792 
00793         for( size_t pos = message.find( '\n' ); pos != std::string::npos;
00794              pos = message.find( '\n' ))
00795         {
00796             glRasterPos3f( 10.f - xOffset, y, 0.99f );
00797             
00798             font->draw( message.substr( 0, pos ));
00799             message = message.substr( pos + 1 );
00800             y -= 22.f;
00801         }
00802         // last line
00803         glRasterPos3f( 10.f - xOffset, y, 0.99f );
00804         font->draw( message );
00805     }
00806 
00807     resetAssemblyState();
00808 }
00809 
00810 void Channel::_updateNearFar( const mesh::BoundingSphere& boundingSphere )
00811 {
00812     // compute dynamic near/far plane of whole model
00813     const FrameData& frameData = _getFrameData();
00814     const bool ortho = frameData.useOrtho();
00815 
00816     const eq::Matrix4f& rotation     = frameData.getCameraRotation();
00817     const eq::Matrix4f headTransform = getHeadTransform() * rotation;
00818 
00819     eq::Matrix4f modelInv;
00820     compute_inverse( headTransform, modelInv );
00821 
00822     const eq::Vector3f zero  = modelInv * eq::Vector3f::ZERO;
00823     eq::Vector3f       front = modelInv * eq::Vector3f( 0.0f, 0.0f, -1.0f );
00824 
00825     front -= zero;
00826     front.normalize();
00827     front *= boundingSphere.w();
00828 
00829     const eq::Vector3f center = boundingSphere.get_sub_vector< 3 >() + 
00830                         frameData.getCameraTranslation( ).get_sub_vector< 3 >();
00831     const eq::Vector3f nearPoint  = headTransform * ( center - front );
00832     const eq::Vector3f farPoint   = headTransform * ( center + front );
00833 
00834     if( ortho )
00835     {
00836         EQASSERT( fabs( farPoint.z() - nearPoint.z() ) > 
00837                   std::numeric_limits< float >::epsilon( ));
00838         setNearFar( -nearPoint.z(), -farPoint.z() );
00839     }
00840     else
00841     {
00842         // estimate minimal value of near plane based on frustum size
00843         const eq::Frustumf& frustum = getFrustum();
00844         const float width  = fabs( frustum.right() - frustum.left() );
00845         const float height = fabs( frustum.top() - frustum.bottom() );
00846         const float size   = EQ_MIN( width, height );
00847         const float minNear = frustum.near_plane() / size * .001f;
00848 
00849         const float zNear = EQ_MAX( minNear, -nearPoint.z() );
00850         const float zFar  = EQ_MAX( zNear * 2.f, -farPoint.z() );
00851 
00852         setNearFar( zNear, zFar );
00853     }
00854 }
00855 
00856 void Channel::_initFrustum( eq::FrustumCullerf& culler,
00857                             const mesh::BoundingSphere& boundingSphere )
00858 {
00859     // setup frustum cull helper
00860     const FrameData& frameData = _getFrameData();
00861     const eq::Matrix4f& rotation     = frameData.getCameraRotation();
00862     const eq::Matrix4f& modelRotation = frameData.getModelRotation();
00863           eq::Matrix4f  translation   = eq::Matrix4f::IDENTITY;
00864     translation.set_translation( frameData.getCameraTranslation());
00865 
00866     const eq::Matrix4f modelView = 
00867         getHeadTransform() * rotation * translation * modelRotation;
00868 
00869     const bool ortho = frameData.useOrtho();
00870     const eq::Frustumf& frustum      = ortho ? getOrtho() : getFrustum();
00871     const eq::Matrix4f  projection   = ortho ? frustum.compute_ortho_matrix() :
00872                                                frustum.compute_matrix();
00873     culler.setup( projection * modelView );
00874 }
00875 }
Generated on Sat Feb 6 12:59:44 2010 for Equalizer 0.9.1 by  doxygen 1.6.1