Equalizer 1.0

eqPly/channel.cpp

00001 
00002 /* Copyright (c) 2006-2011, Stefan Eilemann <eile@equalizergraphics.com>
00003  *               2010, Cedric Stalder <cedric.stalder@gmail.com>
00004  *               2007, Tobias Wolf <twolf@access.unizh.ch>
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright notice, this
00010  *   list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright notice,
00012  *   this list of conditions and the following disclaimer in the documentation
00013  *   and/or other materials provided with the distribution.
00014  * - Neither the name of Eyescale Software GmbH nor the names of its
00015  *   contributors may be used to endorse or promote products derived from this
00016  *   software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028  * POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 #include "channel.h"
00032 
00033 #include "initData.h"
00034 #include "config.h"
00035 #include "configEvent.h"
00036 #include "pipe.h"
00037 #include "view.h"
00038 #include "window.h"
00039 #include "vertexBufferState.h"
00040 #include <co/base/bitOperation.h> // function getIndexOfLastBit
00041 
00042 // light parameters
00043 static GLfloat lightPosition[] = {0.0f, 0.0f, 1.0f, 0.0f};
00044 static GLfloat lightAmbient[]  = {0.1f, 0.1f, 0.1f, 1.0f};
00045 static GLfloat lightDiffuse[]  = {0.8f, 0.8f, 0.8f, 1.0f};
00046 static GLfloat lightSpecular[] = {0.8f, 0.8f, 0.8f, 1.0f};
00047 
00048 // material properties
00049 static GLfloat materialAmbient[]  = {0.2f, 0.2f, 0.2f, 1.0f};
00050 static GLfloat materialDiffuse[]  = {0.8f, 0.8f, 0.8f, 1.0f};
00051 static GLfloat materialSpecular[] = {0.5f, 0.5f, 0.5f, 1.0f};
00052 static GLint  materialShininess   = 64;
00053 
00054 #ifndef M_SQRT3_2
00055 #  define M_SQRT3_2  0.86603f  /* sqrt(3)/2 */
00056 #endif
00057 
00058 namespace eqPly
00059 {
00060 
00061 Channel::Channel( eq::Window* parent )
00062         : eq::Channel( parent )
00063         , _model(0)
00064         , _modelID( co::base::UUID::ZERO )
00065         , _frameRestart( 0 )
00066 {
00067 }
00068 
00069 bool Channel::configInit( const eq::uint128_t& initID )
00070 {
00071     if( !eq::Channel::configInit( initID ))
00072         return false;
00073 
00074     setNearFar( 0.1f, 10.0f );
00075     _model = 0;
00076     _modelID = co::base::UUID::ZERO;
00077     return true;
00078 }
00079 
00080 bool Channel::configExit()
00081 {
00082     for( size_t i = 0; i < eq::NUM_EYES; ++i )
00083     {
00084         delete _accum[ i ].buffer;
00085         _accum[ i ].buffer = 0;
00086     }
00087 
00088     return eq::Channel::configExit();
00089 }
00090 
00091 void Channel::frameClear( const eq::uint128_t& frameID )
00092 {
00093     if( stopRendering( ))
00094         return;
00095 
00096     _initJitter();
00097     const FrameData& frameData = _getFrameData();
00098     const int32_t eyeIndex = co::base::getIndexOfLastBit( getEye() );
00099     if( _isDone() && !_accum[ eyeIndex ].transfer )
00100         return;
00101 
00102     applyBuffer();
00103     applyViewport();
00104 
00105     const eq::View* view = getView();
00106     if( view && frameData.getCurrentViewID() == view->getID( ))
00107         glClearColor( .4f, .4f, .4f, 1.0f );
00108 #ifndef NDEBUG
00109     else if( getenv( "EQ_TAINT_CHANNELS" ))
00110     {
00111         const eq::Vector3ub color = getUniqueColor();
00112         glClearColor( color.r()/255.0f,
00113                       color.g()/255.0f,
00114                       color.b()/255.0f, 1.0f );
00115     }
00116 #endif // NDEBUG
00117     else
00118         glClearColor( 0.f, 0.f, 0.f, 1.0f );
00119 
00120     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
00121 }
00122 
00123 void Channel::frameDraw( const eq::uint128_t& frameID )
00124 {
00125     if( stopRendering( ))
00126         return;
00127 
00128     _initJitter();
00129     if( _isDone( ))
00130         return;
00131 
00132     const Model* model = _getModel();
00133     if( model )
00134         _updateNearFar( model->getBoundingSphere( ));
00135 
00136     // Setup OpenGL state
00137     eq::Channel::frameDraw( frameID );
00138 
00139     glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );
00140     glLightfv( GL_LIGHT0, GL_AMBIENT,  lightAmbient  );
00141     glLightfv( GL_LIGHT0, GL_DIFFUSE,  lightDiffuse  );
00142     glLightfv( GL_LIGHT0, GL_SPECULAR, lightSpecular );
00143 
00144     glMaterialfv( GL_FRONT, GL_AMBIENT,   materialAmbient );
00145     glMaterialfv( GL_FRONT, GL_DIFFUSE,   materialDiffuse );
00146     glMaterialfv( GL_FRONT, GL_SPECULAR,  materialSpecular );
00147     glMateriali(  GL_FRONT, GL_SHININESS, materialShininess );
00148 
00149     const FrameData& frameData = _getFrameData();
00150     glPolygonMode( GL_FRONT_AND_BACK, 
00151                    frameData.useWireframe() ? GL_LINE : GL_FILL );
00152 
00153     const eq::Vector3f& position = frameData.getCameraPosition();
00154 
00155     glMultMatrixf( frameData.getCameraRotation().array );
00156     glTranslatef( position.x(), position.y(), position.z() );
00157     glMultMatrixf( frameData.getModelRotation().array );
00158 
00159     if( frameData.getColorMode() == COLOR_DEMO )
00160     {
00161         const eq::Vector3ub color = getUniqueColor();
00162         glColor3ub( color.r(), color.g(), color.b() );
00163     }
00164     else
00165         glColor3f( .75f, .75f, .75f );
00166 
00167     if( model )
00168         _drawModel( model );
00169     else
00170     {
00171         glNormal3f( 0.f, -1.f, 0.f );
00172         glBegin( GL_TRIANGLE_STRIP );
00173             glVertex3f(  .25f, 0.f,  .25f );
00174             glVertex3f( -.25f, 0.f,  .25f );
00175             glVertex3f(  .25f, 0.f, -.25f );
00176             glVertex3f( -.25f, 0.f, -.25f );
00177         glEnd();
00178     }
00179 
00180     Accum& accum = _accum[ co::base::getIndexOfLastBit( getEye()) ];
00181     accum.stepsDone = EQ_MAX( accum.stepsDone, 
00182                               getSubPixel().size * getPeriod( ));
00183     accum.transfer = true;
00184 }
00185 
00186 void Channel::frameAssemble( const eq::uint128_t& frameID )
00187 {
00188     if( stopRendering( ))
00189         return;
00190 
00191     if( _isDone( ))
00192         return;
00193 
00194     Accum& accum = _accum[ co::base::getIndexOfLastBit( getEye()) ];
00195 
00196     if( getPixelViewport() != _currentPVP )
00197     {
00198         accum.transfer = true;
00199 
00200         if( accum.buffer && !accum.buffer->usesFBO( ))
00201         {
00202             EQWARN << "Current viewport different from view viewport, ";
00203             EQWARN << "idle anti-aliasing not implemented." << std::endl;
00204             accum.step = 0;
00205         }
00206 
00207         eq::Channel::frameAssemble( frameID );
00208         return;
00209     }
00210     // else
00211     
00212     bool subPixelALL = true;
00213     const eq::Frames& frames = getInputFrames();
00214 
00215     for( eq::Frames::const_iterator i = frames.begin(); i != frames.end(); ++i )
00216     {
00217         eq::Frame* frame = *i;
00218         const eq::SubPixel& curSubPixel = frame->getSubPixel();
00219 
00220         if( curSubPixel != eq::SubPixel::ALL )
00221             subPixelALL = false;
00222 
00223         accum.stepsDone = EQ_MAX( accum.stepsDone, 
00224                                   frame->getSubPixel().size*frame->getPeriod());
00225     }
00226 
00227     accum.transfer = subPixelALL;
00228 
00229     applyBuffer();
00230     applyViewport();
00231     setupAssemblyState();
00232 
00233     eq::Compositor::assembleFrames( getInputFrames(), this, accum.buffer );
00234 
00235     resetAssemblyState();
00236 }
00237 
00238 void Channel::frameReadback( const eq::uint128_t& frameID )
00239 {
00240     if( stopRendering( ))
00241         return;
00242 
00243     if( _isDone( ))
00244         return;
00245 
00246     // OPT: Drop alpha channel from all frames during network transport
00247     const FrameData& frameData = _getFrameData();
00248     const eq::Frames& frames = getOutputFrames();
00249     for( eq::Frames::const_iterator i = frames.begin(); i != frames.end(); ++i )
00250     {
00251         eq::Frame* frame = *i;
00252         frame->setAlphaUsage( false );
00253         
00254         if( frameData.isIdle( ))
00255             frame->setQuality( eq::Frame::BUFFER_COLOR, 1.f );
00256         else
00257             frame->setQuality( eq::Frame::BUFFER_COLOR, frameData.getQuality());
00258     }
00259 
00260     eq::Channel::frameReadback( frameID );
00261 }
00262 
00263 void Channel::frameStart( const eq::uint128_t& frameID,
00264                           const uint32_t frameNumber )
00265 {
00266     if( stopRendering( ))
00267         return;
00268 
00269     for( size_t i = 0; i < eq::NUM_EYES; ++i )
00270         _accum[ i ].stepsDone = 0;
00271 
00272     eq::Channel::frameStart( frameID, frameNumber );
00273 }
00274 
00275 void Channel::frameViewStart( const eq::uint128_t& frameID )
00276 {
00277     if( stopRendering( ))
00278         return;
00279 
00280     _currentPVP = getPixelViewport();
00281     _initJitter();
00282     eq::Channel::frameViewStart( frameID );
00283 }
00284 
00285 void Channel::frameFinish( const eq::uint128_t& frameID,
00286                            const uint32_t frameNumber )
00287 {
00288     if( stopRendering( ))
00289         return;
00290 
00291     for( size_t i = 0; i < eq::NUM_EYES; ++i )
00292     {
00293         Accum& accum = _accum[ i ];
00294         if( accum.step > 0 )
00295         {
00296             if( static_cast< int32_t >( accum.stepsDone ) > accum.step )
00297                 accum.step = 0;
00298             else
00299                 accum.step -= accum.stepsDone;
00300         }
00301     }
00302 
00303     eq::Channel::frameFinish( frameID, frameNumber );
00304 }
00305 
00306 void Channel::frameViewFinish( const eq::uint128_t& frameID )
00307 {
00308     if( stopRendering( ))
00309         return;
00310 
00311     applyBuffer();
00312 
00313     const FrameData& frameData = _getFrameData();
00314     Accum& accum = _accum[ co::base::getIndexOfLastBit( getEye()) ];
00315 
00316     if( accum.buffer )
00317     {
00318         const eq::PixelViewport& pvp = getPixelViewport();
00319         const bool isResized = accum.buffer->resize( pvp.w, pvp.h );
00320 
00321         if( isResized )
00322         {
00323             const View* view = static_cast< const View* >( getView( ));
00324             accum.buffer->clear();
00325             accum.step = view->getIdleSteps();
00326             accum.stepsDone = 0;
00327         }
00328         else if( frameData.isIdle( ))
00329         {
00330             setupAssemblyState();
00331 
00332             if( !_isDone() && accum.transfer )
00333                 accum.buffer->accum();
00334             accum.buffer->display();
00335 
00336             resetAssemblyState();
00337         }
00338     }
00339 
00340     applyViewport();
00341     _drawOverlay();
00342     _drawHelp();
00343 
00344     if( frameData.useStatistics())
00345         drawStatistics();
00346 
00347     ConfigEvent event;
00348     event.data.originator = getID();
00349     event.data.type = ConfigEvent::IDLE_AA_LEFT;
00350 
00351     if( frameData.isIdle( ))
00352     {
00353         int32_t maxSteps = 0;
00354         for( size_t i = 0; i < eq::NUM_EYES; ++i )
00355             maxSteps = EQ_MAX( maxSteps, _accum[i].step );
00356 
00357         event.steps = maxSteps;
00358     }
00359     else
00360     {
00361         const View* view = static_cast< const View* >( getView( ));
00362         if( view )
00363             event.steps = view->getIdleSteps();
00364         else
00365             event.steps = 0;
00366     }
00367 
00368     // if _jitterStep == 0 and no user redraw event happened, the app will exit
00369     // FSAA idle mode and block on the next redraw event.
00370     eq::Config* config = getConfig();
00371     config->sendEvent( event );
00372 }
00373 
00374 bool Channel::useOrtho() const
00375 {
00376     const FrameData& frameData = _getFrameData();
00377     return frameData.useOrtho();
00378 }
00379 
00380 const FrameData& Channel::_getFrameData() const
00381 {
00382     const Pipe* pipe = static_cast<const Pipe*>( getPipe( ));
00383     return pipe->getFrameData();
00384 }
00385 
00386 bool Channel::_isDone() const
00387 {
00388     const FrameData& frameData = _getFrameData();
00389     if( !frameData.isIdle( ))
00390         return false;
00391 
00392     const eq::SubPixel& subpixel = getSubPixel();
00393     const Accum& accum = _accum[ co::base::getIndexOfLastBit( getEye()) ];
00394     return static_cast< int32_t >( subpixel.index ) >= accum.step;
00395 }
00396 
00397 void Channel::_initJitter()
00398 {
00399     if( !_initAccum( ))
00400         return;
00401 
00402     const FrameData& frameData = _getFrameData();
00403     if( frameData.isIdle( ))
00404         return;
00405 
00406     const View* view = static_cast< const View* >( getView( ));
00407     if( !view )
00408         return;
00409 
00410     const uint32_t totalSteps = view->getIdleSteps();
00411 
00412     if( totalSteps == 0 )
00413         return;
00414 
00415     // ready for the next FSAA
00416     Accum& accum = _accum[ co::base::getIndexOfLastBit( getEye()) ];
00417 
00418     if( accum.buffer )
00419         accum.buffer->clear();
00420     accum.step = totalSteps;
00421 }
00422 
00423 bool Channel::_initAccum()
00424 {
00425     View* view = static_cast< View* >( getNativeView( ));
00426     if( !view ) // Only alloc accum for dest
00427         return true;
00428 
00429     const eq::Eye eye = getEye();
00430     Accum& accum = _accum[ co::base::getIndexOfLastBit( eye ) ];
00431 
00432     if( accum.buffer ) // already done
00433         return true;
00434 
00435     if( accum.step == -1 ) // accum init failed last time
00436         return false;
00437 
00438     // Check unsupported cases
00439     if( !eq::util::Accum::usesFBO( glewGetContext( )))
00440     {
00441         for( size_t i = 0; i < eq::NUM_EYES; ++i )
00442         {
00443             if( _accum[ i ].buffer )
00444             {
00445                 EQWARN << "glAccum-based accumulation does not support "
00446                        << "stereo, disabling idle anti-aliasing."
00447                        << std::endl;
00448                 for( size_t j = 0; j < eq::NUM_EYES; ++j )
00449                 {
00450                     delete _accum[ j ].buffer;
00451                     _accum[ j ].buffer = 0;
00452                     _accum[ j ].step = -1;
00453                 }
00454 
00455                 view->setIdleSteps( 0 );
00456                 return false;
00457             }
00458         }
00459     }
00460 
00461     // set up accumulation buffer
00462     accum.buffer = new eq::util::Accum( glewGetContext( ));
00463     const eq::PixelViewport& pvp = getPixelViewport();
00464     EQASSERT( pvp.isValid( ));
00465 
00466     if( !accum.buffer->init( pvp, getWindow()->getColorFormat( )) ||
00467         accum.buffer->getMaxSteps() < 256 )
00468     {
00469         EQWARN <<"Accumulation buffer initialization failed, "
00470                << "idle AA not available." << std::endl;
00471         delete accum.buffer;
00472         accum.buffer = 0;
00473         accum.step = -1;
00474         return false;
00475     }
00476 
00477     // else
00478     EQVERB << "Initialized "
00479            << (accum.buffer->usesFBO() ? "FBO accum" : "glAccum")
00480            << " buffer for " << getName() << " " << getEye() 
00481            << std::endl;
00482 
00483     view->setIdleSteps( accum.buffer ? 256 : 0 );
00484     return true;
00485 }
00486 
00487 bool Channel::stopRendering() const
00488 { 
00489     return getPipe()->getCurrentFrame() < _frameRestart; 
00490 }
00491 
00492 eq::Vector2f Channel::getJitter() const
00493 {
00494     const FrameData& frameData = _getFrameData();
00495     const Accum& accum = _accum[ co::base::getIndexOfLastBit( getEye()) ];
00496 
00497     if( !frameData.isIdle() || accum.step <= 0 )
00498         return eq::Channel::getJitter();
00499 
00500     const View* view = static_cast< const View* >( getView( ));
00501     if( !view || view->getIdleSteps() != 256 )
00502         return eq::Vector2f::ZERO;
00503 
00504     eq::Vector2i jitterStep = _getJitterStep();
00505     if( jitterStep == eq::Vector2i::ZERO )
00506         return eq::Vector2f::ZERO;
00507 
00508     const eq::PixelViewport& pvp = getPixelViewport();
00509     const float pvp_w = float( pvp.w );
00510     const float pvp_h = float( pvp.h );
00511     const float frustum_w = float(( getFrustum().get_width( )));
00512     const float frustum_h = float(( getFrustum().get_height( )));
00513 
00514     const float pixel_w = frustum_w / pvp_w;
00515     const float pixel_h = frustum_h / pvp_h;
00516 
00517     const float sampleSize = 16.f; // sqrt( 256 )
00518     const float subpixel_w = pixel_w / sampleSize;
00519     const float subpixel_h = pixel_h / sampleSize;
00520 
00521     // Sample value randomly computed within the subpixel
00522     co::base::RNG rng;
00523     float value_i = rng.get< float >() * subpixel_w
00524                     + float( jitterStep.x( )) * subpixel_w;
00525 
00526     float value_j = rng.get< float >() * subpixel_h
00527                     + float( jitterStep.y( )) * subpixel_h;
00528 
00529     const eq::Pixel& pixel = getPixel();
00530     value_i /= float( pixel.w );
00531     value_j /= float( pixel.h );
00532 
00533     return eq::Vector2f( value_i, value_j );
00534 }
00535 
00536 namespace
00537 {
00538 static const uint32_t _primes[100] = {
00539     739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
00540     839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
00541     947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033,
00542     1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109,
00543     1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213,
00544     1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
00545     1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399,
00546     1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451 };
00547 }
00548 
00549 eq::Vector2i Channel::_getJitterStep() const
00550 {
00551     const eq::SubPixel& subPixel = getSubPixel();
00552     const uint32_t channelID = subPixel.index;
00553     const View* view = static_cast< const View* >( getView( ));
00554     if( !view )
00555         return eq::Vector2i::ZERO;
00556 
00557     const uint32_t totalSteps = view->getIdleSteps();
00558     if( totalSteps != 256 )
00559         return eq::Vector2i::ZERO;
00560 
00561     const Accum& accum = _accum[ co::base::getIndexOfLastBit( getEye()) ];
00562     const uint32_t subset = totalSteps / getSubPixel().size;
00563     const uint32_t idx = 
00564         ( accum.step * _primes[ channelID ] ) % subset + ( channelID * subset );
00565 
00566     const uint32_t sampleSize = 16;
00567     const int dx = idx % sampleSize;
00568     const int dy = idx / sampleSize;
00569 
00570     return eq::Vector2i( dx, dy );
00571 }
00572 
00573 const Model* Channel::_getModel()
00574 {
00575     Config*     config = static_cast< Config* >( getConfig( ));
00576     const View* view   = static_cast< const View* >( getView( ));
00577     const FrameData& frameData = _getFrameData();
00578     EQASSERT( !view || dynamic_cast< const View* >( getView( )));
00579 
00580     eq::uint128_t id = view ? view->getModelID() : frameData.getModelID();
00581     if( id == co::base::UUID::ZERO )
00582         id = frameData.getModelID();
00583     if( id != _modelID )
00584     {
00585         _model = config->getModel( id );
00586         _modelID = id;
00587     }
00588 
00589     return _model;
00590 }
00591 
00592 void Channel::_drawModel( const Model* model )
00593 {
00594     Window*            window    = static_cast< Window* >( getWindow( ));
00595     VertexBufferState& state     = window->getState();
00596     const FrameData&   frameData = _getFrameData();
00597     const eq::Range&   range     = getRange();
00598     eq::FrustumCullerf culler;
00599 
00600     if( frameData.getColorMode() == COLOR_MODEL && model->hasColors( ))
00601         state.setColors( true );
00602     else
00603         state.setColors( false );
00604     state.setChannel( this );
00605 
00606     _initFrustum( culler, model->getBoundingSphere( ));
00607 
00608     const eq::Pipe* pipe = getPipe();
00609     const GLuint program = state.getProgram( pipe );
00610     if( program != VertexBufferState::INVALID )
00611         glUseProgram( program );
00612     
00613     model->beginRendering( state );
00614     
00615 #ifndef NDEBUG
00616     size_t verticesRendered = 0;
00617     size_t verticesOverlap  = 0;
00618 #endif
00619 
00620     // start with root node
00621     std::vector< const mesh::VertexBufferBase* > candidates;
00622     candidates.push_back( model );
00623 
00624     while( !candidates.empty() )
00625     {
00626         if( stopRendering( ))
00627             return;
00628 
00629         const mesh::VertexBufferBase* treeNode = candidates.back();
00630         candidates.pop_back();
00631             
00632         // completely out of range check
00633         if( treeNode->getRange()[0] >= range.end || 
00634             treeNode->getRange()[1] < range.start )
00635             continue;
00636             
00637         // bounding sphere view frustum culling
00638         const vmml::Visibility visibility =
00639             culler.test_sphere( treeNode->getBoundingSphere( ));
00640 
00641         switch( visibility )
00642         {
00643             case vmml::VISIBILITY_FULL:
00644                 // if fully visible and fully in range, render it
00645                 if( range == eq::Range::ALL || 
00646                     ( treeNode->getRange()[0] >= range.start && 
00647                       treeNode->getRange()[1] < range.end ))
00648                 {
00649                     treeNode->render( state );
00650                     //treeNode->renderBoundingSphere( state );
00651 #ifndef NDEBUG
00652                     verticesRendered += treeNode->getNumberOfVertices();
00653 #endif
00654                     break;
00655                 }
00656                 // partial range, fall through to partial visibility
00657 
00658             case vmml::VISIBILITY_PARTIAL:
00659             {
00660                 const mesh::VertexBufferBase* left  = treeNode->getLeft();
00661                 const mesh::VertexBufferBase* right = treeNode->getRight();
00662             
00663                 if( !left && !right )
00664                 {
00665                     if( treeNode->getRange()[0] >= range.start )
00666                     {
00667                         treeNode->render( state );
00668                         //treeNode->renderBoundingSphere( state );
00669 #ifndef NDEBUG
00670                         verticesRendered += treeNode->getNumberOfVertices();
00671                         if( visibility == vmml::VISIBILITY_PARTIAL )
00672                             verticesOverlap  += treeNode->getNumberOfVertices();
00673 #endif
00674                     }
00675                     // else drop, to be drawn by 'previous' channel
00676                 }
00677                 else
00678                 {
00679                     if( left )
00680                         candidates.push_back( left );
00681                     if( right )
00682                         candidates.push_back( right );
00683                 }
00684                 break;
00685             }
00686             case vmml::VISIBILITY_NONE:
00687                 // do nothing
00688                 break;
00689         }
00690     }
00691     
00692     model->endRendering( state );
00693     state.setChannel( 0 );
00694 
00695     if( program != VertexBufferState::INVALID )
00696         glUseProgram( 0 );
00697 
00698 #ifndef NDEBUG
00699     const size_t verticesTotal = model->getNumberOfVertices();
00700     EQLOG( LOG_CULL ) 
00701         << getName() << " rendered " << verticesRendered * 100 / verticesTotal
00702         << "% of model, overlap <= " << verticesOverlap * 100 / verticesTotal
00703         << "%" << std::endl;
00704 #endif    
00705 }
00706 
00707 void Channel::_drawOverlay()
00708 {
00709     // Draw the overlay logo
00710     const Window* window = static_cast<Window*>( getWindow( ));
00711     const eq::util::Texture* texture = window->getLogoTexture();
00712     if( !texture )
00713         return;
00714 
00715     glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
00716     glMatrixMode( GL_PROJECTION );
00717     glLoadIdentity();
00718     applyScreenFrustum();
00719     glMatrixMode( GL_MODELVIEW );
00720     glLoadIdentity();
00721 
00722     glDisable( GL_DEPTH_TEST );
00723     glDisable( GL_LIGHTING );
00724     glColor3f( 1.0f, 1.0f, 1.0f );
00725 
00726 #if 1
00727     // border
00728     const eq::PixelViewport& pvp = getPixelViewport();
00729     const eq::Viewport& vp = getViewport();
00730     const float w = pvp.w / vp.w - .5f;
00731     const float h = pvp.h / vp.h - .5f;
00732 
00733     glBegin( GL_LINE_LOOP );
00734     {
00735         glVertex3f( .5f, .5f, 0.f );
00736         glVertex3f(   w, .5f, 0.f );
00737         glVertex3f(   w,   h, 0.f );
00738         glVertex3f( .5f,   h, 0.f );
00739     } 
00740     glEnd();
00741 #endif
00742 
00743     // logo
00744     glEnable( GL_BLEND );
00745     glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00746     const GLenum target = texture->getTarget();
00747     glEnable( target );
00748     texture->bind();
00749     glTexParameteri( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00750     glTexParameteri( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00751     
00752     const float tWidth = float( texture->getWidth( ) );
00753     const float tHeight = float( texture->getHeight( ) );
00754 
00755     const float width = target == GL_TEXTURE_2D ? 1.0f : tWidth;
00756     const float height = target == GL_TEXTURE_2D ? 1.0f : tHeight;
00757 
00758     glBegin( GL_QUADS ); {
00759         glTexCoord2f( 0, 0 );
00760         glVertex3f( 5.0f, 5.0f, 0.0f );
00761 
00762         glTexCoord2f( width, 0 );
00763         glVertex3f( tWidth + 5.0f, 5.0f, 0.0f );
00764 
00765         glTexCoord2f( width, height );
00766         glVertex3f( tWidth + 5.0f, tHeight + 5.0f, 0.0f );
00767 
00768         glTexCoord2f( 0, height );
00769         glVertex3f( 5.0f, tHeight + 5.0f, 0.0f );
00770 
00771     } glEnd();
00772 
00773     glDisable( target );
00774     glDisable( GL_BLEND );
00775     glEnable( GL_LIGHTING );
00776     glEnable( GL_DEPTH_TEST );
00777 }
00778 
00779 void Channel::_drawHelp()
00780 {
00781     const FrameData& frameData = _getFrameData();
00782     std::string message = frameData.getMessage();
00783 
00784     if( !frameData.showHelp() && message.empty( ))
00785         return;
00786 
00787     applyBuffer();
00788     applyViewport();
00789     setupAssemblyState();
00790 
00791     glDisable( GL_LIGHTING );
00792     glDisable( GL_DEPTH_TEST );
00793 
00794     glColor3f( 1.f, 1.f, 1.f );
00795 
00796     if( frameData.showHelp( ))
00797     {
00798         const eq::Window::Font* font = getWindow()->getSmallFont();
00799         std::string help = EqPly::getHelp();
00800         float y = 340.f;
00801 
00802         for( size_t pos = help.find( '\n' ); pos != std::string::npos;
00803              pos = help.find( '\n' ))
00804         {
00805             glRasterPos3f( 10.f, y, 0.99f );
00806             
00807             font->draw( help.substr( 0, pos ));
00808             help = help.substr( pos + 1 );
00809             y -= 16.f;
00810         }
00811         // last line
00812         glRasterPos3f( 10.f, y, 0.99f );
00813         font->draw( help );
00814     }
00815 
00816     if( !message.empty( ))
00817     {
00818         const eq::Window::Font* font = getWindow()->getMediumFont();
00819 
00820         const eq::Viewport& vp = getViewport();
00821         const eq::PixelViewport& pvp = getPixelViewport();
00822 
00823         const float width = pvp.w / vp.w;
00824         const float xOffset = vp.x * width;
00825 
00826         const float height = pvp.h / vp.h;
00827         const float yOffset = vp.y * height;
00828         const float yMiddle = 0.5f * height;
00829         float y = yMiddle - yOffset;
00830 
00831         for( size_t pos = message.find( '\n' ); pos != std::string::npos;
00832              pos = message.find( '\n' ))
00833         {
00834             glRasterPos3f( 10.f - xOffset, y, 0.99f );
00835             
00836             font->draw( message.substr( 0, pos ));
00837             message = message.substr( pos + 1 );
00838             y -= 22.f;
00839         }
00840         // last line
00841         glRasterPos3f( 10.f - xOffset, y, 0.99f );
00842         font->draw( message );
00843     }
00844 
00845     resetAssemblyState();
00846 }
00847 
00848 void Channel::_updateNearFar( const mesh::BoundingSphere& boundingSphere )
00849 {
00850     // compute dynamic near/far plane of whole model
00851     const FrameData& frameData = _getFrameData();
00852 
00853     const eq::Matrix4f& rotation     = frameData.getCameraRotation();
00854     const eq::Matrix4f headTransform = getHeadTransform() * rotation;
00855 
00856     eq::Matrix4f modelInv;
00857     compute_inverse( headTransform, modelInv );
00858 
00859     const eq::Vector3f zero  = modelInv * eq::Vector3f::ZERO;
00860     eq::Vector3f       front = modelInv * eq::Vector3f( 0.0f, 0.0f, -1.0f );
00861 
00862     front -= zero;
00863     front.normalize();
00864     front *= boundingSphere.w();
00865 
00866     const eq::Vector3f center =  
00867         frameData.getCameraPosition().get_sub_vector< 3 >() -
00868         boundingSphere.get_sub_vector< 3 >();
00869     const eq::Vector3f nearPoint  = headTransform * ( center - front );
00870     const eq::Vector3f farPoint   = headTransform * ( center + front );
00871 
00872     if( useOrtho( ))
00873     {
00874         EQASSERTINFO( fabs( farPoint.z() - nearPoint.z() ) > 
00875                       std::numeric_limits< float >::epsilon(),
00876                       nearPoint << " == " << farPoint );
00877         setNearFar( -nearPoint.z(), -farPoint.z() );
00878     }
00879     else
00880     {
00881         // estimate minimal value of near plane based on frustum size
00882         const eq::Frustumf& frustum = getFrustum();
00883         const float width  = fabs( frustum.right() - frustum.left() );
00884         const float height = fabs( frustum.top() - frustum.bottom() );
00885         const float size   = EQ_MIN( width, height );
00886         const float minNear = frustum.near_plane() / size * .001f;
00887 
00888         const float zNear = EQ_MAX( minNear, -nearPoint.z() );
00889         const float zFar  = EQ_MAX( zNear * 2.f, -farPoint.z() );
00890 
00891         setNearFar( zNear, zFar );
00892     }
00893 }
00894 
00895 void Channel::_initFrustum( eq::FrustumCullerf& culler,
00896                             const mesh::BoundingSphere& boundingSphere )
00897 {
00898     // setup frustum cull helper
00899     const FrameData& frameData = _getFrameData();
00900     const eq::Matrix4f& rotation = frameData.getCameraRotation();
00901     const eq::Matrix4f& modelRotation = frameData.getModelRotation();
00902     eq::Matrix4f position = eq::Matrix4f::IDENTITY;
00903     position.set_translation( frameData.getCameraPosition());
00904 
00905     const eq::Matrix4f& xfm = getHeadTransform();
00906     const eq::Matrix4f modelView = xfm * rotation * position * modelRotation;
00907 
00908     const eq::Frustumf& frustum = getFrustum();
00909     const eq::Matrix4f projection = useOrtho() ? frustum.compute_ortho_matrix():
00910                                                  frustum.compute_matrix();
00911     culler.setup( projection * modelView );
00912 }
00913 }
Generated on Sun May 8 2011 19:11:05 for Equalizer 1.0 by  doxygen 1.7.3