Equalizer
1.4.1
|
00001 00002 /* Copyright (c) 2006-2012, 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 00041 // light parameters 00042 static GLfloat lightPosition[] = {0.0f, 0.0f, 1.0f, 0.0f}; 00043 static GLfloat lightAmbient[] = {0.1f, 0.1f, 0.1f, 1.0f}; 00044 static GLfloat lightDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f}; 00045 static GLfloat lightSpecular[] = {0.8f, 0.8f, 0.8f, 1.0f}; 00046 00047 // material properties 00048 static GLfloat materialAmbient[] = {0.2f, 0.2f, 0.2f, 1.0f}; 00049 static GLfloat materialDiffuse[] = {0.8f, 0.8f, 0.8f, 1.0f}; 00050 static GLfloat materialSpecular[] = {0.5f, 0.5f, 0.5f, 1.0f}; 00051 static GLint materialShininess = 64; 00052 00053 #ifndef M_SQRT3_2 00054 # define M_SQRT3_2 0.86603f /* sqrt(3)/2 */ 00055 #endif 00056 00057 namespace eqPly 00058 { 00059 00060 Channel::Channel( eq::Window* parent ) 00061 : eq::Channel( parent ) 00062 , _model(0) 00063 , _modelID( lunchbox::UUID::ZERO ) 00064 , _frameRestart( 0 ) 00065 { 00066 } 00067 00068 bool Channel::configInit( const eq::uint128_t& initID ) 00069 { 00070 if( !eq::Channel::configInit( initID )) 00071 return false; 00072 00073 setNearFar( 0.1f, 10.0f ); 00074 _model = 0; 00075 _modelID = lunchbox::UUID::ZERO; 00076 return true; 00077 } 00078 00079 bool Channel::configExit() 00080 { 00081 for( size_t i = 0; i < eq::NUM_EYES; ++i ) 00082 { 00083 delete _accum[ i ].buffer; 00084 _accum[ i ].buffer = 0; 00085 } 00086 00087 return eq::Channel::configExit(); 00088 } 00089 00090 void Channel::frameClear( const eq::uint128_t& frameID ) 00091 { 00092 if( stopRendering( )) 00093 return; 00094 00095 _initJitter(); 00096 resetRegions(); 00097 00098 const FrameData& frameData = _getFrameData(); 00099 const int32_t eyeIndex = lunchbox::getIndexOfLastBit( getEye() ); 00100 if( _isDone() && !_accum[ eyeIndex ].transfer ) 00101 return; 00102 00103 applyBuffer(); 00104 applyViewport(); 00105 00106 const eq::View* view = getView(); 00107 if( view && frameData.getCurrentViewID() == view->getID( )) 00108 glClearColor( 1.f, 1.f, 1.f, 1.f ); 00109 #ifndef NDEBUG 00110 else if( getenv( "EQ_TAINT_CHANNELS" )) 00111 { 00112 const eq::Vector3ub color = getUniqueColor(); 00113 glClearColor( color.r()/255.0f, 00114 color.g()/255.0f, 00115 color.b()/255.0f, 1.0f ); 00116 } 00117 #endif // NDEBUG 00118 else 00119 glClearColor( 0.f, 0.f, 0.f, 1.0f ); 00120 00121 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 00122 } 00123 00124 void Channel::frameDraw( const eq::uint128_t& frameID ) 00125 { 00126 if( stopRendering( )) 00127 return; 00128 00129 _initJitter(); 00130 if( _isDone( )) 00131 return; 00132 00133 Window* window = static_cast< Window* >( getWindow( )); 00134 VertexBufferState& state = window->getState(); 00135 const Model* oldModel = _model; 00136 const Model* model = _getModel(); 00137 00138 if( oldModel != model ) 00139 state.setFrustumCulling( false ); // create all display lists/VBOs 00140 00141 if( model ) 00142 _updateNearFar( model->getBoundingSphere( )); 00143 00144 eq::Channel::frameDraw( frameID ); // Setup OpenGL state 00145 00146 glLightfv( GL_LIGHT0, GL_POSITION, lightPosition ); 00147 glLightfv( GL_LIGHT0, GL_AMBIENT, lightAmbient ); 00148 glLightfv( GL_LIGHT0, GL_DIFFUSE, lightDiffuse ); 00149 glLightfv( GL_LIGHT0, GL_SPECULAR, lightSpecular ); 00150 00151 glMaterialfv( GL_FRONT, GL_AMBIENT, materialAmbient ); 00152 glMaterialfv( GL_FRONT, GL_DIFFUSE, materialDiffuse ); 00153 glMaterialfv( GL_FRONT, GL_SPECULAR, materialSpecular ); 00154 glMateriali( GL_FRONT, GL_SHININESS, materialShininess ); 00155 00156 const FrameData& frameData = _getFrameData(); 00157 glPolygonMode( GL_FRONT_AND_BACK, 00158 frameData.useWireframe() ? GL_LINE : GL_FILL ); 00159 00160 const eq::Vector3f& position = frameData.getCameraPosition(); 00161 00162 glMultMatrixf( frameData.getCameraRotation().array ); 00163 glTranslatef( position.x(), position.y(), position.z() ); 00164 glMultMatrixf( frameData.getModelRotation().array ); 00165 00166 if( frameData.getColorMode() == COLOR_DEMO ) 00167 { 00168 const eq::Vector3ub color = getUniqueColor(); 00169 glColor3ub( color.r(), color.g(), color.b() ); 00170 } 00171 else 00172 glColor3f( .75f, .75f, .75f ); 00173 00174 if( model ) 00175 _drawModel( model ); 00176 else 00177 { 00178 glNormal3f( 0.f, -1.f, 0.f ); 00179 glBegin( GL_TRIANGLE_STRIP ); 00180 glVertex3f( .25f, 0.f, .25f ); 00181 glVertex3f( -.25f, 0.f, .25f ); 00182 glVertex3f( .25f, 0.f, -.25f ); 00183 glVertex3f( -.25f, 0.f, -.25f ); 00184 glEnd(); 00185 } 00186 00187 state.setFrustumCulling( true ); 00188 Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ]; 00189 accum.stepsDone = LB_MAX( accum.stepsDone, 00190 getSubPixel().size * getPeriod( )); 00191 accum.transfer = true; 00192 } 00193 00194 void Channel::frameAssemble( const eq::uint128_t& frameID ) 00195 { 00196 if( stopRendering( )) 00197 return; 00198 00199 if( _isDone( )) 00200 return; 00201 00202 Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ]; 00203 00204 if( getPixelViewport() != _currentPVP ) 00205 { 00206 accum.transfer = true; 00207 00208 if( accum.buffer && !accum.buffer->usesFBO( )) 00209 { 00210 LBWARN << "Current viewport different from view viewport, " 00211 << "idle anti-aliasing not implemented." << std::endl; 00212 accum.step = 0; 00213 } 00214 00215 eq::Channel::frameAssemble( frameID ); 00216 return; 00217 } 00218 // else 00219 00220 accum.transfer = true; 00221 const eq::Frames& frames = getInputFrames(); 00222 00223 for( eq::Frames::const_iterator i = frames.begin(); i != frames.end(); ++i ) 00224 { 00225 eq::Frame* frame = *i; 00226 const eq::SubPixel& curSubPixel = frame->getSubPixel(); 00227 00228 if( curSubPixel != eq::SubPixel::ALL ) 00229 accum.transfer = false; 00230 00231 accum.stepsDone = LB_MAX( accum.stepsDone, frame->getSubPixel().size * 00232 frame->getPeriod( )); 00233 } 00234 00235 applyBuffer(); 00236 applyViewport(); 00237 setupAssemblyState(); 00238 00239 try 00240 { 00241 eq::Compositor::assembleFrames( getInputFrames(), this, accum.buffer ); 00242 } 00243 catch( const co::Exception& e ) 00244 { 00245 LBWARN << e.what() << std::endl; 00246 } 00247 00248 resetAssemblyState(); 00249 } 00250 00251 void Channel::frameReadback( const eq::uint128_t& frameID ) 00252 { 00253 if( stopRendering() || _isDone( )) 00254 return; 00255 00256 const FrameData& frameData = _getFrameData(); 00257 const eq::Frames& frames = getOutputFrames(); 00258 for( eq::FramesCIter i = frames.begin(); i != frames.end(); ++i ) 00259 { 00260 eq::Frame* frame = *i; 00261 // OPT: Drop alpha channel from all frames during network transport 00262 frame->setAlphaUsage( false ); 00263 00264 if( frameData.isIdle( )) 00265 frame->setQuality( eq::Frame::BUFFER_COLOR, 1.f ); 00266 else 00267 frame->setQuality( eq::Frame::BUFFER_COLOR, frameData.getQuality()); 00268 00269 if( frameData.useCompression( )) 00270 frame->useCompressor( eq::Frame::BUFFER_COLOR, EQ_COMPRESSOR_AUTO ); 00271 else 00272 frame->useCompressor( eq::Frame::BUFFER_COLOR, EQ_COMPRESSOR_NONE ); 00273 } 00274 00275 eq::Channel::frameReadback( frameID ); 00276 } 00277 00278 void Channel::frameStart( const eq::uint128_t& frameID, 00279 const uint32_t frameNumber ) 00280 { 00281 if( stopRendering( )) 00282 return; 00283 00284 for( size_t i = 0; i < eq::NUM_EYES; ++i ) 00285 _accum[ i ].stepsDone = 0; 00286 00287 eq::Channel::frameStart( frameID, frameNumber ); 00288 } 00289 00290 void Channel::frameViewStart( const eq::uint128_t& frameID ) 00291 { 00292 if( stopRendering( )) 00293 return; 00294 00295 _currentPVP = getPixelViewport(); 00296 _initJitter(); 00297 eq::Channel::frameViewStart( frameID ); 00298 } 00299 00300 void Channel::frameFinish( const eq::uint128_t& frameID, 00301 const uint32_t frameNumber ) 00302 { 00303 if( stopRendering( )) 00304 return; 00305 00306 for( size_t i = 0; i < eq::NUM_EYES; ++i ) 00307 { 00308 Accum& accum = _accum[ i ]; 00309 if( accum.step > 0 ) 00310 { 00311 if( int32_t( accum.stepsDone ) > accum.step ) 00312 accum.step = 0; 00313 else 00314 accum.step -= accum.stepsDone; 00315 } 00316 } 00317 00318 eq::Channel::frameFinish( frameID, frameNumber ); 00319 } 00320 00321 void Channel::frameViewFinish( const eq::uint128_t& frameID ) 00322 { 00323 if( stopRendering( )) 00324 return; 00325 00326 applyBuffer(); 00327 00328 const FrameData& frameData = _getFrameData(); 00329 Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ]; 00330 00331 if( accum.buffer ) 00332 { 00333 const eq::PixelViewport& pvp = getPixelViewport(); 00334 const bool isResized = accum.buffer->resize( pvp.w, pvp.h ); 00335 00336 if( isResized ) 00337 { 00338 const View* view = static_cast< const View* >( getView( )); 00339 accum.buffer->clear(); 00340 accum.step = view->getIdleSteps(); 00341 accum.stepsDone = 0; 00342 } 00343 else if( frameData.isIdle( )) 00344 { 00345 setupAssemblyState(); 00346 00347 if( !_isDone() && accum.transfer ) 00348 accum.buffer->accum(); 00349 accum.buffer->display(); 00350 00351 resetAssemblyState(); 00352 } 00353 } 00354 00355 applyViewport(); 00356 _drawOverlay(); 00357 _drawHelp(); 00358 00359 if( frameData.useStatistics()) 00360 drawStatistics(); 00361 00362 ConfigEvent event; 00363 event.data.originator = getID(); 00364 event.data.type = ConfigEvent::IDLE_AA_LEFT; 00365 00366 if( frameData.isIdle( )) 00367 { 00368 event.steps = 0; 00369 for( size_t i = 0; i < eq::NUM_EYES; ++i ) 00370 event.steps = LB_MAX( event.steps, _accum[i].step ); 00371 } 00372 else 00373 { 00374 const View* view = static_cast< const View* >( getView( )); 00375 event.steps = view ? view->getIdleSteps() : 0; 00376 } 00377 00378 // if _jitterStep == 0 and no user redraw event happened, the app will exit 00379 // FSAA idle mode and block on the next redraw event. 00380 eq::Config* config = getConfig(); 00381 config->sendEvent( event ); 00382 } 00383 00384 bool Channel::useOrtho() const 00385 { 00386 const FrameData& frameData = _getFrameData(); 00387 return frameData.useOrtho(); 00388 } 00389 00390 const FrameData& Channel::_getFrameData() const 00391 { 00392 const Pipe* pipe = static_cast<const Pipe*>( getPipe( )); 00393 return pipe->getFrameData(); 00394 } 00395 00396 bool Channel::_isDone() const 00397 { 00398 const FrameData& frameData = _getFrameData(); 00399 if( !frameData.isIdle( )) 00400 return false; 00401 00402 const eq::SubPixel& subpixel = getSubPixel(); 00403 const Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ]; 00404 return int32_t( subpixel.index ) >= accum.step; 00405 } 00406 00407 void Channel::_initJitter() 00408 { 00409 if( !_initAccum( )) 00410 return; 00411 00412 const FrameData& frameData = _getFrameData(); 00413 if( frameData.isIdle( )) 00414 return; 00415 00416 const View* view = static_cast< const View* >( getView( )); 00417 if( !view ) 00418 return; 00419 00420 const int32_t idleSteps = view->getIdleSteps(); 00421 if( idleSteps == 0 ) 00422 return; 00423 00424 // ready for the next FSAA 00425 Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ]; 00426 if( accum.buffer ) 00427 accum.buffer->clear(); 00428 accum.step = idleSteps; 00429 } 00430 00431 bool Channel::_initAccum() 00432 { 00433 View* view = static_cast< View* >( getNativeView( )); 00434 if( !view ) // Only alloc accum for dest 00435 return true; 00436 00437 const eq::Eye eye = getEye(); 00438 Accum& accum = _accum[ lunchbox::getIndexOfLastBit( eye ) ]; 00439 00440 if( accum.buffer ) // already done 00441 return true; 00442 00443 if( accum.step == -1 ) // accum init failed last time 00444 return false; 00445 00446 // Check unsupported cases 00447 if( !eq::util::Accum::usesFBO( glewGetContext( ))) 00448 { 00449 for( size_t i = 0; i < eq::NUM_EYES; ++i ) 00450 { 00451 if( _accum[ i ].buffer ) 00452 { 00453 LBWARN << "glAccum-based accumulation does not support " 00454 << "stereo, disabling idle anti-aliasing." 00455 << std::endl; 00456 for( size_t j = 0; j < eq::NUM_EYES; ++j ) 00457 { 00458 delete _accum[ j ].buffer; 00459 _accum[ j ].buffer = 0; 00460 _accum[ j ].step = -1; 00461 } 00462 00463 view->setIdleSteps( 0 ); 00464 return false; 00465 } 00466 } 00467 } 00468 00469 // set up accumulation buffer 00470 accum.buffer = new eq::util::Accum( glewGetContext( )); 00471 const eq::PixelViewport& pvp = getPixelViewport(); 00472 LBASSERT( pvp.isValid( )); 00473 00474 if( !accum.buffer->init( pvp, getWindow()->getColorFormat( )) || 00475 accum.buffer->getMaxSteps() < 256 ) 00476 { 00477 LBWARN <<"Accumulation buffer initialization failed, " 00478 << "idle AA not available." << std::endl; 00479 delete accum.buffer; 00480 accum.buffer = 0; 00481 accum.step = -1; 00482 return false; 00483 } 00484 00485 // else 00486 LBVERB << "Initialized " 00487 << (accum.buffer->usesFBO() ? "FBO accum" : "glAccum") 00488 << " buffer for " << getName() << " " << getEye() 00489 << std::endl; 00490 00491 view->setIdleSteps( accum.buffer ? 256 : 0 ); 00492 return true; 00493 } 00494 00495 bool Channel::stopRendering() const 00496 { 00497 return getPipe()->getCurrentFrame() < _frameRestart; 00498 } 00499 00500 eq::Vector2f Channel::getJitter() const 00501 { 00502 const FrameData& frameData = _getFrameData(); 00503 const Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ]; 00504 00505 if( !frameData.isIdle() || accum.step <= 0 ) 00506 return eq::Channel::getJitter(); 00507 00508 const View* view = static_cast< const View* >( getView( )); 00509 if( !view || view->getIdleSteps() != 256 ) 00510 return eq::Vector2f::ZERO; 00511 00512 const eq::Vector2i jitterStep = _getJitterStep(); 00513 if( jitterStep == eq::Vector2i::ZERO ) 00514 return eq::Vector2f::ZERO; 00515 00516 const eq::PixelViewport& pvp = getPixelViewport(); 00517 const float pvp_w = float( pvp.w ); 00518 const float pvp_h = float( pvp.h ); 00519 const float frustum_w = float(( getFrustum().get_width( ))); 00520 const float frustum_h = float(( getFrustum().get_height( ))); 00521 00522 const float pixel_w = frustum_w / pvp_w; 00523 const float pixel_h = frustum_h / pvp_h; 00524 00525 const float sampleSize = 16.f; // sqrt( 256 ) 00526 const float subpixel_w = pixel_w / sampleSize; 00527 const float subpixel_h = pixel_h / sampleSize; 00528 00529 // Sample value randomly computed within the subpixel 00530 lunchbox::RNG rng; 00531 const eq::Pixel& pixel = getPixel(); 00532 00533 const float i = ( rng.get< float >() * subpixel_w + 00534 float( jitterStep.x( )) * subpixel_w ) / float( pixel.w ); 00535 const float j = ( rng.get< float >() * subpixel_h + 00536 float( jitterStep.y( )) * subpixel_h ) / float( pixel.h ); 00537 00538 return eq::Vector2f( i, j ); 00539 } 00540 00541 static const uint32_t _primes[100] = { 00542 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 00543 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 00544 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 00545 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 00546 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 00547 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 00548 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 00549 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451 }; 00550 00551 eq::Vector2i Channel::_getJitterStep() const 00552 { 00553 const eq::SubPixel& subPixel = getSubPixel(); 00554 const uint32_t channelID = subPixel.index; 00555 const View* view = static_cast< const View* >( getView( )); 00556 if( !view ) 00557 return eq::Vector2i::ZERO; 00558 00559 const uint32_t totalSteps = uint32_t( view->getIdleSteps( )); 00560 if( totalSteps != 256 ) 00561 return eq::Vector2i::ZERO; 00562 00563 const Accum& accum = _accum[ lunchbox::getIndexOfLastBit( getEye()) ]; 00564 const uint32_t subset = totalSteps / getSubPixel().size; 00565 const uint32_t index = ( accum.step * _primes[ channelID % 100 ] )%subset + 00566 ( channelID * subset ); 00567 const uint32_t sampleSize = 16; 00568 const int dx = index % sampleSize; 00569 const int dy = index / sampleSize; 00570 00571 return eq::Vector2i( dx, dy ); 00572 } 00573 00574 const Model* Channel::_getModel() 00575 { 00576 Config* config = static_cast< Config* >( getConfig( )); 00577 const View* view = static_cast< const View* >( getView( )); 00578 const FrameData& frameData = _getFrameData(); 00579 LBASSERT( !view || dynamic_cast< const View* >( getView( ))); 00580 00581 eq::uint128_t id = view ? view->getModelID() : frameData.getModelID(); 00582 if( id == lunchbox::UUID::ZERO ) 00583 id = frameData.getModelID(); 00584 if( id != _modelID ) 00585 { 00586 _model = config->getModel( id ); 00587 _modelID = id; 00588 } 00589 00590 return _model; 00591 } 00592 00593 void Channel::_drawModel( const Model* scene ) 00594 { 00595 Window* window = static_cast< Window* >( getWindow( )); 00596 VertexBufferState& state = window->getState(); 00597 const FrameData& frameData = _getFrameData(); 00598 00599 if( frameData.getColorMode() == COLOR_MODEL && scene->hasColors( )) 00600 state.setColors( true ); 00601 else 00602 state.setColors( false ); 00603 state.setChannel( this ); 00604 00605 // Compute cull matrix 00606 const eq::Matrix4f& rotation = frameData.getCameraRotation(); 00607 const eq::Matrix4f& modelRotation = frameData.getModelRotation(); 00608 eq::Matrix4f position = eq::Matrix4f::IDENTITY; 00609 position.set_translation( frameData.getCameraPosition()); 00610 00611 const eq::Frustumf& frustum = getFrustum(); 00612 const eq::Matrix4f projection = useOrtho() ? frustum.compute_ortho_matrix(): 00613 frustum.compute_matrix(); 00614 const eq::Matrix4f& view = getHeadTransform(); 00615 const eq::Matrix4f model = rotation * position * modelRotation; 00616 00617 state.setProjectionModelViewMatrix( projection * view * model ); 00618 state.setRange( &getRange().start); 00619 00620 const eq::Pipe* pipe = getPipe(); 00621 const GLuint program = state.getProgram( pipe ); 00622 if( program != VertexBufferState::INVALID ) 00623 glUseProgram( program ); 00624 00625 scene->cullDraw( state ); 00626 00627 state.setChannel( 0 ); 00628 if( program != VertexBufferState::INVALID ) 00629 glUseProgram( 0 ); 00630 00631 const InitData& initData = 00632 static_cast<Config*>( getConfig( ))->getInitData(); 00633 if( !initData.useROI( )) 00634 { 00635 declareRegion( getPixelViewport( )); 00636 return; 00637 } 00638 00639 #ifndef NDEBUG // region border 00640 const eq::PixelViewport& pvp = getPixelViewport(); 00641 const eq::PixelViewport& region = getRegion(); 00642 00643 glMatrixMode( GL_PROJECTION ); 00644 glLoadIdentity(); 00645 glOrtho( 0.f, pvp.w, 0.f, pvp.h, -1.f, 1.f ); 00646 glMatrixMode( GL_MODELVIEW ); 00647 glLoadIdentity(); 00648 00649 const eq::View* currentView = getView(); 00650 if( frameData.getColorMode() == COLOR_DEMO ) 00651 { 00652 const eq::Vector3ub color = getUniqueColor(); 00653 glColor3ub( color.r(), color.g(), color.b() ); 00654 } 00655 else if( currentView && 00656 frameData.getCurrentViewID() == currentView->getID( )) 00657 { 00658 glColor3f( 0.f, 0.f, 0.f ); 00659 } 00660 else 00661 glColor3f( 1.f, 1.f, 1.f ); 00662 glNormal3f( 0.f, 0.f, 1.f ); 00663 00664 const eq::Vector4f rect( float( region.x ) + .5f, float( region.y ) + .5f, 00665 float( region.getXEnd( )) - .5f, 00666 float( region.getYEnd( )) - .5f ); 00667 glBegin( GL_LINE_LOOP ); { 00668 glVertex3f( rect[0], rect[1], -.99f ); 00669 glVertex3f( rect[2], rect[1], -.99f ); 00670 glVertex3f( rect[2], rect[3], -.99f ); 00671 glVertex3f( rect[0], rect[3], -.99f ); 00672 } glEnd(); 00673 #endif 00674 } 00675 00676 void Channel::_drawOverlay() 00677 { 00678 // Draw the overlay logo 00679 const Window* window = static_cast<Window*>( getWindow( )); 00680 const eq::util::Texture* texture = window->getLogoTexture(); 00681 if( !texture ) 00682 return; 00683 00684 glMatrixMode( GL_PROJECTION ); 00685 glLoadIdentity(); 00686 applyScreenFrustum(); 00687 glMatrixMode( GL_MODELVIEW ); 00688 glLoadIdentity(); 00689 00690 glDisable( GL_DEPTH_TEST ); 00691 glDisable( GL_LIGHTING ); 00692 glColor3f( 1.0f, 1.0f, 1.0f ); 00693 glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); 00694 00695 // logo 00696 glEnable( GL_BLEND ); 00697 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); 00698 const GLenum target = texture->getTarget(); 00699 glEnable( target ); 00700 texture->bind(); 00701 glTexParameteri( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); 00702 glTexParameteri( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); 00703 00704 const float tWidth = float( texture->getWidth( ) ); 00705 const float tHeight = float( texture->getHeight( ) ); 00706 00707 const float width = target == GL_TEXTURE_2D ? 1.0f : tWidth; 00708 const float height = target == GL_TEXTURE_2D ? 1.0f : tHeight; 00709 00710 glBegin( GL_QUADS ); { 00711 glTexCoord2f( 0, 0 ); 00712 glVertex3f( 5.0f, 5.0f, 0.0f ); 00713 00714 glTexCoord2f( width, 0 ); 00715 glVertex3f( tWidth + 5.0f, 5.0f, 0.0f ); 00716 00717 glTexCoord2f( width, height ); 00718 glVertex3f( tWidth + 5.0f, tHeight + 5.0f, 0.0f ); 00719 00720 glTexCoord2f( 0, height ); 00721 glVertex3f( 5.0f, tHeight + 5.0f, 0.0f ); 00722 00723 } glEnd(); 00724 00725 glDisable( target ); 00726 glDisable( GL_BLEND ); 00727 glEnable( GL_LIGHTING ); 00728 glEnable( GL_DEPTH_TEST ); 00729 } 00730 00731 void Channel::_drawHelp() 00732 { 00733 const FrameData& frameData = _getFrameData(); 00734 std::string message = frameData.getMessage(); 00735 00736 if( !frameData.showHelp() && message.empty( )) 00737 return; 00738 00739 applyBuffer(); 00740 applyViewport(); 00741 setupAssemblyState(); 00742 00743 glLogicOp( GL_XOR ); 00744 glEnable( GL_COLOR_LOGIC_OP ); 00745 glDisable( GL_LIGHTING ); 00746 glDisable( GL_DEPTH_TEST ); 00747 00748 glColor3f( 1.f, 1.f, 1.f ); 00749 00750 const eq::PixelViewport& pvp = getPixelViewport(); 00751 const eq::Viewport& vp = getViewport(); 00752 const float height = pvp.h / vp.h; 00753 00754 if( !message.empty( )) 00755 { 00756 const eq::Window::Font* font = getWindow()->getMediumFont(); 00757 00758 const float width = pvp.w / vp.w; 00759 const float xOffset = vp.x * width; 00760 00761 const float yOffset = vp.y * height; 00762 const float yPos = 0.618f * height; 00763 float y = yPos - yOffset; 00764 00765 for( size_t pos = message.find( '\n' ); pos != std::string::npos; 00766 pos = message.find( '\n' )) 00767 { 00768 glRasterPos3f( 10.f - xOffset, y, 0.99f ); 00769 font->draw( message.substr( 0, pos )); 00770 message = message.substr( pos + 1 ); 00771 y -= 22.f; 00772 } 00773 // last line 00774 glRasterPos3f( 10.f - xOffset, y, 0.99f ); 00775 font->draw( message ); 00776 } 00777 00778 glMatrixMode( GL_PROJECTION ); 00779 glLoadIdentity(); 00780 applyScreenFrustum(); 00781 glMatrixMode( GL_MODELVIEW ); 00782 00783 if( frameData.showHelp( )) 00784 { 00785 const eq::Window::Font* font = getWindow()->getSmallFont(); 00786 std::string help = EqPly::getHelp(); 00787 float y = height - 16.f; 00788 00789 for( size_t pos = help.find( '\n' ); pos != std::string::npos; 00790 pos = help.find( '\n' )) 00791 { 00792 glRasterPos3f( 10.f, y, 0.99f ); 00793 00794 font->draw( help.substr( 0, pos )); 00795 help = help.substr( pos + 1 ); 00796 y -= 16.f; 00797 } 00798 // last line 00799 glRasterPos3f( 10.f, y, 0.99f ); 00800 font->draw( help ); 00801 } 00802 00803 resetAssemblyState(); 00804 } 00805 00806 void Channel::_updateNearFar( const mesh::BoundingSphere& boundingSphere ) 00807 { 00808 // compute dynamic near/far plane of whole model 00809 const FrameData& frameData = _getFrameData(); 00810 00811 const eq::Matrix4f& rotation = frameData.getCameraRotation(); 00812 const eq::Matrix4f headTransform = getHeadTransform() * rotation; 00813 00814 eq::Matrix4f modelInv; 00815 compute_inverse( headTransform, modelInv ); 00816 00817 const eq::Vector3f zero = modelInv * eq::Vector3f::ZERO; 00818 eq::Vector3f front = modelInv * eq::Vector3f( 0.0f, 0.0f, -1.0f ); 00819 00820 front -= zero; 00821 front.normalize(); 00822 front *= boundingSphere.w(); 00823 00824 const eq::Vector3f center = 00825 frameData.getCameraPosition().get_sub_vector< 3 >() - 00826 boundingSphere.get_sub_vector< 3 >(); 00827 const eq::Vector3f nearPoint = headTransform * ( center - front ); 00828 const eq::Vector3f farPoint = headTransform * ( center + front ); 00829 00830 if( useOrtho( )) 00831 { 00832 LBASSERTINFO( fabs( farPoint.z() - nearPoint.z() ) > 00833 std::numeric_limits< float >::epsilon(), 00834 nearPoint << " == " << farPoint ); 00835 setNearFar( -nearPoint.z(), -farPoint.z() ); 00836 } 00837 else 00838 { 00839 // estimate minimal value of near plane based on frustum size 00840 const eq::Frustumf& frustum = getFrustum(); 00841 const float width = fabs( frustum.right() - frustum.left() ); 00842 const float height = fabs( frustum.top() - frustum.bottom() ); 00843 const float size = LB_MIN( width, height ); 00844 const float minNear = frustum.near_plane() / size * .001f; 00845 00846 const float zNear = LB_MAX( minNear, -nearPoint.z() ); 00847 const float zFar = LB_MAX( zNear * 2.f, -farPoint.z() ); 00848 00849 setNearFar( zNear, zFar ); 00850 } 00851 } 00852 00853 }