Equalizer 1.0
|
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 }