Equalizer
1.4.1
|
00001 00002 /* Copyright (c) 2006-2012, Stefan Eilemann <eile@equalizergraphics.com> 00003 * 2007-2011, Maxim Makhinya <maxmah@gmail.com> 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * - Redistributions of source code must retain the above copyright notice, this 00009 * list of conditions and the following disclaimer. 00010 * - Redistributions in binary form must reproduce the above copyright notice, 00011 * this list of conditions and the following disclaimer in the documentation 00012 * and/or other materials provided with the distribution. 00013 * - Neither the name of Eyescale Software GmbH nor the names of its 00014 * contributors may be used to endorse or promote products derived from this 00015 * software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 #include "channel.h" 00031 00032 #include "frameData.h" 00033 #include "initData.h" 00034 #include "node.h" 00035 #include "pipe.h" 00036 #include "window.h" 00037 #include "hlp.h" 00038 #include "framesOrderer.h" 00039 00040 namespace eVolve 00041 { 00042 Channel::Channel( eq::Window* parent ) 00043 : eq::Channel( parent ) 00044 , _bgColor( eq::Vector3f::ZERO ) 00045 , _drawRange( eq::Range::ALL ) 00046 , _taint( getenv( "EQ_TAINT_CHANNELS" )) 00047 { 00048 eq::FrameDataPtr frameData = new eq::FrameData; 00049 frameData->setBuffers( eq::Frame::BUFFER_COLOR ); 00050 _frame.setFrameData( frameData ); 00051 } 00052 00053 static void checkError( const std::string& msg ) 00054 { 00055 const GLenum error = glGetError(); 00056 if (error != GL_NO_ERROR) 00057 LBERROR << msg << " GL Error: " << error << std::endl; 00058 } 00059 00060 00061 bool Channel::configInit( const eq::uint128_t& initID ) 00062 { 00063 if( !eq::Channel::configInit( initID )) 00064 return false; 00065 00066 setNearFar( 0.001f, 10.0f ); 00067 return true; 00068 } 00069 00070 bool Channel::configExit() 00071 { 00072 eq::FrameDataPtr frameData = _frame.getFrameData(); 00073 frameData->resetPlugins(); 00074 00075 return eq::Channel::configExit(); 00076 } 00077 00078 void Channel::frameStart( const eq::uint128_t& frameID, 00079 const uint32_t frameNumber ) 00080 { 00081 _drawRange = eq::Range::ALL; 00082 _bgColor = eq::Vector3f( 0.f, 0.f, 0.f ); 00083 00084 const BackgroundMode bgMode = _getFrameData().getBackgroundMode(); 00085 00086 if( bgMode == BG_WHITE ) 00087 _bgColor = eq::Vector3f( 1.f, 1.f, 1.f ); 00088 else 00089 if( bgMode == BG_COLOR || _taint ) 00090 _bgColor = eq::Vector3f( getUniqueColor( )) / 255.f; 00091 00092 eq::Channel::frameStart( frameID, frameNumber ); 00093 } 00094 00095 void Channel::frameClear( const eq::uint128_t& frameID ) 00096 { 00097 applyBuffer(); 00098 applyViewport(); 00099 00100 _drawRange = getRange(); 00101 if( _drawRange == eq::Range::ALL ) 00102 glClearColor( _bgColor.r(), _bgColor.g(), _bgColor.b(), 1.0f ); 00103 else 00104 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); 00105 00106 glClear( GL_COLOR_BUFFER_BIT ); 00107 } 00108 00109 00110 static void setLights( eq::Matrix4f& invRotationM ) 00111 { 00112 GLfloat lightAmbient[] = {0.05f, 0.05f, 0.05f, 1.0f}; 00113 GLfloat lightDiffuse[] = {0.9f , 0.9f , 0.9f , 1.0f}; 00114 GLfloat lightSpecular[] = {0.8f , 0.8f , 0.8f , 1.0f}; 00115 GLfloat lightPosition[] = {1.0f , 1.0f , 1.0f , 0.0f}; 00116 00117 glLightfv( GL_LIGHT0, GL_AMBIENT, lightAmbient ); 00118 glLightfv( GL_LIGHT0, GL_DIFFUSE, lightDiffuse ); 00119 glLightfv( GL_LIGHT0, GL_SPECULAR, lightSpecular ); 00120 00121 // rotate light in the opposite direction of the model rotation to keep 00122 // light position constant and avoid recalculating normals in the fragment 00123 // shader 00124 glPushMatrix(); 00125 glMultMatrixf( invRotationM.array ); 00126 glLightfv( GL_LIGHT0, GL_POSITION, lightPosition ); 00127 glPopMatrix(); 00128 } 00129 00130 00131 static eq::Vector4f _getTaintColor( const ColorMode colorMode, 00132 const eq::Vector3f& color ) 00133 { 00134 if( colorMode == COLOR_MODEL ) 00135 return eq::Vector4f::ZERO; 00136 00137 eq::Vector4f taintColor( color.r(), color.g(), color.b(), 1.0 ); 00138 const float alpha = ( colorMode == COLOR_HALF_DEMO ) ? 0.5 : 1.0; 00139 00140 taintColor /= 255.f; 00141 taintColor *= alpha; 00142 taintColor.a() = alpha; 00143 return taintColor; 00144 } 00145 00146 void Channel::frameDraw( const eq::uint128_t& frameID ) 00147 { 00148 // Setup frustum 00149 EQ_GL_CALL( applyBuffer( )); 00150 EQ_GL_CALL( applyViewport( )); 00151 00152 EQ_GL_CALL( glMatrixMode( GL_PROJECTION )); 00153 EQ_GL_CALL( glLoadIdentity( )); 00154 EQ_GL_CALL( applyFrustum( )); 00155 00156 EQ_GL_CALL( glMatrixMode( GL_MODELVIEW )); 00157 EQ_GL_CALL( glLoadIdentity( )); 00158 00159 // Setup lights before applying head transform, so the light will be 00160 // consistent in the cave 00161 const FrameData& frameData = _getFrameData(); 00162 const eq::Matrix4f& rotation = frameData.getRotation(); 00163 const eq::Vector3f& translation = frameData.getTranslation(); 00164 00165 eq::Matrix4f invRotationM; 00166 rotation.inverse( invRotationM ); 00167 setLights( invRotationM ); 00168 00169 EQ_GL_CALL( applyHeadTransform( )); 00170 00171 glTranslatef( translation.x(), translation.y(), translation.z() ); 00172 glMultMatrixf( rotation.array ); 00173 00174 Pipe* pipe = static_cast<Pipe*>( getPipe( )); 00175 Renderer* renderer = pipe->getRenderer(); 00176 LBASSERT( renderer ); 00177 00178 eq::Matrix4f modelviewM; // modelview matrix 00179 eq::Matrix3f modelviewITM; // modelview inversed transposed matrix 00180 _calcMVandITMV( modelviewM, modelviewITM ); 00181 00182 // set fancy data colors 00183 const eq::Vector4f taintColor = _getTaintColor( frameData.getColorMode(), 00184 getUniqueColor( )); 00185 const int normalsQuality = _getFrameData().getNormalsQuality(); 00186 00187 const eq::Range& range = getRange(); 00188 renderer->render( range, modelviewM, modelviewITM, invRotationM, 00189 taintColor, normalsQuality ); 00190 checkError( "error during rendering " ); 00191 00192 _drawRange = range; 00193 00194 #ifndef NDEBUG 00195 outlineViewport(); 00196 #endif 00197 } 00198 00199 bool Channel::useOrtho() const 00200 { 00201 const FrameData& frameData = _getFrameData(); 00202 return frameData.useOrtho(); 00203 } 00204 00205 const FrameData& Channel::_getFrameData() const 00206 { 00207 const Pipe* pipe = static_cast< const Pipe* >( getPipe( )); 00208 return pipe->getFrameData(); 00209 } 00210 00211 void Channel::_calcMVandITMV( 00212 eq::Matrix4f& modelviewM, 00213 eq::Matrix3f& modelviewITM ) const 00214 { 00215 const FrameData& frameData = _getFrameData(); 00216 const Pipe* pipe = static_cast< const Pipe* >( getPipe( )); 00217 const Renderer* renderer = pipe->getRenderer(); 00218 00219 if( renderer ) 00220 { 00221 const VolumeScaling& volScaling = renderer->getVolumeScaling(); 00222 00223 eq::Matrix4f scale( eq::Matrix4f::ZERO ); 00224 scale.at(0,0) = volScaling.W; 00225 scale.at(1,1) = volScaling.H; 00226 scale.at(2,2) = volScaling.D; 00227 scale.at(3,3) = 1.f; 00228 00229 modelviewM = scale * frameData.getRotation(); 00230 } 00231 modelviewM.set_translation( frameData.getTranslation( )); 00232 modelviewM = getHeadTransform() * modelviewM; 00233 00234 //calculate inverse transposed matrix 00235 eq::Matrix4f modelviewIM; 00236 modelviewM.inverse( modelviewIM ); 00237 eq::Matrix3f( modelviewIM ).transpose_to( modelviewITM ); 00238 } 00239 00240 00241 static void _expandPVP( eq::PixelViewport& pvp, const eq::Images& images, 00242 const eq::Vector2i& offset ) 00243 { 00244 for( eq::Images::const_iterator i = images.begin(); 00245 i != images.end(); ++i ) 00246 { 00247 const eq::PixelViewport imagePVP = (*i)->getPixelViewport() + offset; 00248 pvp.merge( imagePVP ); 00249 } 00250 } 00251 00252 00253 void Channel::clearViewport( const eq::PixelViewport &pvp ) 00254 { 00255 // clear given area 00256 glScissor( pvp.x, pvp.y, pvp.w, pvp.h ); 00257 00258 if( _drawRange == eq::Range::ALL ) 00259 glClearColor( _bgColor.r(), _bgColor.g(), _bgColor.b(), 1.0f ); 00260 else 00261 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); 00262 00263 glClear( GL_COLOR_BUFFER_BIT ); 00264 00265 // restore assembly state 00266 const eq::PixelViewport& windowPVP = getWindow()->getPixelViewport(); 00267 glScissor( 0, 0, windowPVP.w, windowPVP.h ); 00268 } 00269 00270 void Channel::_orderFrames( eq::Frames& frames ) 00271 { 00272 eq::Matrix4f modelviewM; // modelview matrix 00273 eq::Matrix3f modelviewITM; // modelview inversed transposed matrix 00274 const FrameData& frameData = _getFrameData(); 00275 const eq::Matrix4f& rotation = frameData.getRotation(); 00276 00277 if( !useOrtho( )) 00278 _calcMVandITMV( modelviewM, modelviewITM ); 00279 00280 orderFrames( frames, modelviewM, modelviewITM, rotation, useOrtho( )); 00281 } 00282 00283 00284 void Channel::frameAssemble( const eq::uint128_t& frameID ) 00285 { 00286 const bool composeOnly = (_drawRange == eq::Range::ALL); 00287 00288 _startAssemble(); 00289 00290 const eq::Frames& frames = getInputFrames(); 00291 eq::PixelViewport coveredPVP; 00292 eq::Frames dbFrames; 00293 eq::Zoom zoom( eq::Zoom::NONE ); 00294 00295 // Make sure all frames are ready and gather some information on them 00296 for( eq::Frames::const_iterator i = frames.begin(); 00297 i != frames.end(); ++i ) 00298 { 00299 eq::Frame* frame = *i; 00300 { 00301 eq::ChannelStatistics stat( eq::Statistic::CHANNEL_FRAME_WAIT_READY, 00302 this ); 00303 frame->waitReady( ); 00304 } 00305 const eq::Range& range = frame->getRange(); 00306 if( range == eq::Range::ALL ) // 2D frame, assemble directly 00307 eq::Compositor::assembleFrame( frame, this ); 00308 else 00309 { 00310 dbFrames.push_back( frame ); 00311 zoom = frame->getZoom(); 00312 _expandPVP( coveredPVP, frame->getImages(), frame->getOffset() ); 00313 } 00314 } 00315 coveredPVP.intersect( getPixelViewport( )); 00316 00317 if( dbFrames.empty( )) 00318 { 00319 resetAssemblyState(); 00320 return; 00321 } 00322 00323 // calculate correct frames sequence 00324 eq::FrameDataPtr data = _frame.getFrameData(); 00325 if( !composeOnly && coveredPVP.hasArea( )) 00326 { 00327 _frame.clear(); 00328 data->setRange( _drawRange ); 00329 dbFrames.push_back( &_frame ); 00330 } 00331 00332 _orderFrames( dbFrames ); 00333 00334 // Update range 00335 eq::Range newRange( 1.f, 0.f ); 00336 for( size_t i = 0; i < dbFrames.size(); ++i ) 00337 { 00338 const eq::Range range = dbFrames[i]->getRange(); 00339 if( newRange.start > range.start ) newRange.start = range.start; 00340 if( newRange.end < range.end ) newRange.end = range.end; 00341 } 00342 _drawRange = newRange; 00343 00344 // check if current frame is in proper position, read back if not 00345 if( !composeOnly ) 00346 { 00347 if( _bgColor == eq::Vector3f::ZERO && dbFrames.front() == &_frame ) 00348 dbFrames.erase( dbFrames.begin( )); 00349 else if( coveredPVP.hasArea()) 00350 { 00351 eq::Window::ObjectManager* glObjects = getObjectManager(); 00352 00353 _frame.setOffset( eq::Vector2i( 0, 0 )); 00354 _frame.setZoom( zoom ); 00355 data->setPixelViewport( coveredPVP ); 00356 _frame.readback( glObjects, getDrawableConfig(), getRegions( )); 00357 clearViewport( coveredPVP ); 00358 00359 // offset for assembly 00360 _frame.setOffset( eq::Vector2i( coveredPVP.x, coveredPVP.y )); 00361 } 00362 } 00363 00364 // blend DB frames in order 00365 try 00366 { 00367 eq::Compositor::assembleFramesSorted( dbFrames, this, 0, 00368 true /*blendAlpha*/ ); 00369 } 00370 catch( const co::Exception& e ) 00371 { 00372 LBWARN << e.what() << std::endl; 00373 } 00374 00375 resetAssemblyState(); 00376 } 00377 00378 void Channel::_startAssemble() 00379 { 00380 applyBuffer(); 00381 applyViewport(); 00382 setupAssemblyState(); 00383 } 00384 00385 void Channel::frameReadback( const eq::uint128_t& frameID ) 00386 { 00387 // Drop depth buffer flag from all output frames 00388 const eq::Frames& frames = getOutputFrames(); 00389 const FrameData& frameData = _getFrameData(); 00390 for( eq::FramesCIter i = frames.begin(); i != frames.end(); ++i ) 00391 { 00392 eq::Frame* frame = *i; 00393 frame->setQuality( eq::Frame::BUFFER_COLOR, frameData.getQuality()); 00394 frame->disableBuffer( eq::Frame::BUFFER_DEPTH ); 00395 frame->getFrameData()->setRange( _drawRange ); 00396 } 00397 00398 eq::Channel::frameReadback( frameID ); 00399 } 00400 00401 void Channel::frameViewFinish( const eq::uint128_t& frameID ) 00402 { 00403 _drawHelp(); 00404 _drawLogo(); 00405 } 00406 00407 void Channel::_drawLogo( ) 00408 { 00409 // Draw the overlay logo 00410 const Window* window = static_cast<Window*>( getWindow( )); 00411 const eq::util::Texture* texture = window->getLogoTexture(); 00412 if( !texture ) 00413 return; 00414 00415 glMatrixMode( GL_PROJECTION ); 00416 glLoadIdentity(); 00417 applyScreenFrustum(); 00418 glMatrixMode( GL_MODELVIEW ); 00419 glLoadIdentity(); 00420 00421 glDisable( GL_DEPTH_TEST ); 00422 glDisable( GL_LIGHTING ); 00423 glEnable( GL_BLEND ); 00424 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); 00425 00426 glColor3f( 1.0f, 1.0f, 1.0f ); 00427 const GLenum target = texture->getTarget(); 00428 glEnable( target ); 00429 texture->bind(); 00430 glTexParameteri( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); 00431 glTexParameteri( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); 00432 00433 const float tWidth = float( texture->getWidth( ) ); 00434 const float tHeight = float( texture->getHeight( ) ); 00435 00436 const float width = target == GL_TEXTURE_2D ? 1.0f : tWidth; 00437 const float height = target == GL_TEXTURE_2D ? 1.0f : tHeight; 00438 00439 glBegin( GL_QUADS ); { 00440 glTexCoord2f( 0, 0 ); 00441 glVertex3f( 5.0f, 5.0f, 0.0f ); 00442 00443 glTexCoord2f( width, 0 ); 00444 glVertex3f( tWidth + 5.0f, 5.0f, 0.0f ); 00445 00446 glTexCoord2f( width, height ); 00447 glVertex3f( tWidth + 5.0f, tHeight + 5.0f, 0.0f ); 00448 00449 glTexCoord2f( 0, height ); 00450 glVertex3f( 5.0f, tHeight + 5.0f, 0.0f ); 00451 00452 } glEnd(); 00453 00454 glDisable( target ); 00455 glDisable( GL_BLEND ); 00456 } 00457 00458 void Channel::_drawHelp() 00459 { 00460 const FrameData& frameData = _getFrameData(); 00461 std::string message = frameData.getMessage(); 00462 00463 if( !frameData.showHelp() && message.empty( )) 00464 return; 00465 00466 applyBuffer(); 00467 applyViewport(); 00468 setupAssemblyState(); 00469 00470 glDisable( GL_LIGHTING ); 00471 glDisable( GL_DEPTH_TEST ); 00472 00473 glColor3f( 1.f, 1.f, 1.f ); 00474 00475 if( frameData.showHelp( )) 00476 { 00477 const eq::Window::Font* font = getWindow()->getSmallFont(); 00478 std::string help = EVolve::getHelp(); 00479 float y = 340.f; 00480 00481 for( size_t pos = help.find( '\n' ); pos != std::string::npos; 00482 pos = help.find( '\n' )) 00483 { 00484 glRasterPos3f( 10.f, y, 0.99f ); 00485 00486 font->draw( help.substr( 0, pos )); 00487 help = help.substr( pos + 1 ); 00488 y -= 16.f; 00489 } 00490 // last line 00491 glRasterPos3f( 10.f, y, 0.99f ); 00492 font->draw( help ); 00493 } 00494 00495 if( !message.empty( )) 00496 { 00497 const eq::Window::Font* font = getWindow()->getMediumFont(); 00498 00499 const eq::Viewport& vp = getViewport(); 00500 const eq::PixelViewport& pvp = getPixelViewport(); 00501 00502 const float width = pvp.w / vp.w; 00503 const float xOffset = vp.x * width; 00504 00505 const float height = pvp.h / vp.h; 00506 const float yOffset = vp.y * height; 00507 const float yMiddle = 0.5f * height; 00508 float y = yMiddle - yOffset; 00509 00510 for( size_t pos = message.find( '\n' ); pos != std::string::npos; 00511 pos = message.find( '\n' )) 00512 { 00513 glRasterPos3f( 10.f - xOffset, y, 0.99f ); 00514 00515 font->draw( message.substr( 0, pos )); 00516 message = message.substr( pos + 1 ); 00517 y -= 22.f; 00518 } 00519 // last line 00520 glRasterPos3f( 10.f - xOffset, y, 0.99f ); 00521 font->draw( message ); 00522 } 00523 00524 EQ_GL_CALL( resetAssemblyState( )); 00525 } 00526 }