Equalizer 1.0
|
00001 00002 /* Copyright (c) 2006-2011, Stefan Eilemann <eile@equalizergraphics.com> 00003 * 2007-2009, Maxim Makhinya 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 { 00047 eq::FrameData* frameData = new eq::FrameData; 00048 frameData->setBuffers( eq::Frame::BUFFER_COLOR ); 00049 _frame.setData( frameData ); 00050 } 00051 00052 static void checkError( const std::string& msg ) 00053 { 00054 const GLenum error = glGetError(); 00055 if (error != GL_NO_ERROR) 00056 EQERROR << msg << " GL Error: " << error << std::endl; 00057 } 00058 00059 00060 bool Channel::configInit( const eq::uint128_t& initID ) 00061 { 00062 if( !eq::Channel::configInit( initID )) 00063 return false; 00064 00065 setNearFar( 0.001f, 10.0f ); 00066 00067 if( getenv( "EQ_TAINT_CHANNELS" )) 00068 { 00069 _bgColor = getUniqueColor(); 00070 _bgColor /= 255.f; 00071 } 00072 00073 return true; 00074 } 00075 00076 void Channel::frameStart( const eq::uint128_t& frameID, const uint32_t frameNumber ) 00077 { 00078 _drawRange = eq::Range::ALL; 00079 eq::Channel::frameStart( frameID, frameNumber ); 00080 } 00081 00082 void Channel::frameClear( const eq::uint128_t& frameID ) 00083 { 00084 applyBuffer(); 00085 applyViewport(); 00086 00087 if( getRange() == eq::Range::ALL ) 00088 glClearColor( _bgColor.r(), _bgColor.g(), _bgColor.b(), 1.0f ); 00089 else 00090 glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); 00091 00092 glClear( GL_COLOR_BUFFER_BIT ); 00093 } 00094 00095 00096 static void setLights( eq::Matrix4f& invRotationM ) 00097 { 00098 GLfloat lightAmbient[] = {0.05f, 0.05f, 0.05f, 1.0f}; 00099 GLfloat lightDiffuse[] = {0.9f , 0.9f , 0.9f , 1.0f}; 00100 GLfloat lightSpecular[] = {0.8f , 0.8f , 0.8f , 1.0f}; 00101 GLfloat lightPosition[] = {1.0f , 1.0f , 1.0f , 0.0f}; 00102 00103 glLightfv( GL_LIGHT0, GL_AMBIENT, lightAmbient ); 00104 glLightfv( GL_LIGHT0, GL_DIFFUSE, lightDiffuse ); 00105 glLightfv( GL_LIGHT0, GL_SPECULAR, lightSpecular ); 00106 00107 // rotate light in the opposite direction of the model rotation to keep 00108 // light position constant and avoid recalculating normals in the fragment 00109 // shader 00110 glPushMatrix(); 00111 glMultMatrixf( invRotationM.array ); 00112 glLightfv( GL_LIGHT0, GL_POSITION, lightPosition ); 00113 glPopMatrix(); 00114 } 00115 00116 00117 void Channel::frameDraw( const eq::uint128_t& frameID ) 00118 { 00119 // Setup frustum 00120 EQ_GL_CALL( applyBuffer( )); 00121 EQ_GL_CALL( applyViewport( )); 00122 00123 EQ_GL_CALL( glMatrixMode( GL_PROJECTION )); 00124 EQ_GL_CALL( glLoadIdentity( )); 00125 EQ_GL_CALL( applyFrustum( )); 00126 00127 EQ_GL_CALL( glMatrixMode( GL_MODELVIEW )); 00128 EQ_GL_CALL( glLoadIdentity( )); 00129 00130 // Setup lights before applying head transform, so the light will be 00131 // consistent in the cave 00132 const FrameData& frameData = _getFrameData(); 00133 const eq::Matrix4f& rotation = frameData.getRotation(); 00134 const eq::Vector3f& translation = frameData.getTranslation(); 00135 00136 eq::Matrix4f invRotationM; 00137 rotation.inverse( invRotationM ); 00138 setLights( invRotationM ); 00139 00140 EQ_GL_CALL( applyHeadTransform( )); 00141 00142 glTranslatef( translation.x(), translation.y(), translation.z() ); 00143 glMultMatrixf( rotation.array ); 00144 00145 Pipe* pipe = static_cast<Pipe*>( getPipe( )); 00146 Renderer* renderer = pipe->getRenderer(); 00147 EQASSERT( renderer ); 00148 00149 eq::Matrix4f modelviewM; // modelview matrix 00150 eq::Matrix3f modelviewITM; // modelview inversed transposed matrix 00151 _calcMVandITMV( modelviewM, modelviewITM ); 00152 00153 const eq::Range& range = getRange(); 00154 renderer->render( range, modelviewM, modelviewITM, invRotationM ); 00155 00156 checkError( "error during rendering " ); 00157 00158 _drawRange = range; 00159 00160 #ifndef NDEBUG 00161 outlineViewport(); 00162 #endif 00163 } 00164 00165 bool Channel::useOrtho() const 00166 { 00167 const FrameData& frameData = _getFrameData(); 00168 return frameData.useOrtho(); 00169 } 00170 00171 const FrameData& Channel::_getFrameData() const 00172 { 00173 const Pipe* pipe = static_cast< const Pipe* >( getPipe( )); 00174 return pipe->getFrameData(); 00175 } 00176 00177 void Channel::_calcMVandITMV( 00178 eq::Matrix4f& modelviewM, 00179 eq::Matrix3f& modelviewITM ) const 00180 { 00181 const FrameData& frameData = _getFrameData(); 00182 const Pipe* pipe = static_cast< const Pipe* >( getPipe( )); 00183 const Renderer* renderer = pipe->getRenderer(); 00184 00185 if( renderer ) 00186 { 00187 const VolumeScaling& volScaling = renderer->getVolumeScaling(); 00188 00189 eq::Matrix4f scale( eq::Matrix4f::ZERO ); 00190 scale.at(0,0) = volScaling.W; 00191 scale.at(1,1) = volScaling.H; 00192 scale.at(2,2) = volScaling.D; 00193 scale.at(3,3) = 1.f; 00194 00195 modelviewM = scale * frameData.getRotation(); 00196 } 00197 modelviewM.set_translation( frameData.getTranslation( )); 00198 modelviewM = getHeadTransform() * modelviewM; 00199 00200 //calculate inverse transposed matrix 00201 eq::Matrix4f modelviewIM; 00202 modelviewM.inverse( modelviewIM ); 00203 eq::Matrix3f( modelviewIM ).transpose_to( modelviewITM ); 00204 } 00205 00206 00207 static void _expandPVP( eq::PixelViewport& pvp, const eq::Images& images, 00208 const eq::Vector2i& offset ) 00209 { 00210 for( eq::Images::const_iterator i = images.begin(); 00211 i != images.end(); ++i ) 00212 { 00213 const eq::PixelViewport imagePVP = (*i)->getPixelViewport() + offset; 00214 pvp.merge( imagePVP ); 00215 } 00216 } 00217 00218 00219 void Channel::clearViewport( const eq::PixelViewport &pvp ) 00220 { 00221 // clear given area 00222 glScissor( pvp.x, pvp.y, pvp.w, pvp.h ); 00223 glClearColor( _bgColor.r(), _bgColor.g(), _bgColor.b(), 1.0f ); 00224 glClear( GL_COLOR_BUFFER_BIT ); 00225 00226 // restore assembly state 00227 const eq::PixelViewport& windowPVP = getWindow()->getPixelViewport(); 00228 glScissor( 0, 0, windowPVP.w, windowPVP.h ); 00229 } 00230 00231 void Channel::_orderFrames( eq::Frames& frames ) 00232 { 00233 eq::Matrix4f modelviewM; // modelview matrix 00234 eq::Matrix3f modelviewITM; // modelview inversed transposed matrix 00235 const FrameData& frameData = _getFrameData(); 00236 const eq::Matrix4f& rotation = frameData.getRotation(); 00237 00238 if( !useOrtho( )) 00239 _calcMVandITMV( modelviewM, modelviewITM ); 00240 00241 orderFrames( frames, modelviewM, modelviewITM, rotation, useOrtho( )); 00242 } 00243 00244 00245 void Channel::frameAssemble( const eq::uint128_t& frameID ) 00246 { 00247 const bool composeOnly = (_drawRange == eq::Range::ALL); 00248 eq::FrameData* data = _frame.getData(); 00249 00250 _startAssemble(); 00251 00252 const eq::Frames& frames = getInputFrames(); 00253 eq::PixelViewport coveredPVP; 00254 eq::Frames dbFrames; 00255 eq::Zoom zoom( eq::Zoom::NONE ); 00256 00257 // Make sure all frames are ready and gather some information on them 00258 for( eq::Frames::const_iterator i = frames.begin(); 00259 i != frames.end(); ++i ) 00260 { 00261 eq::Frame* frame = *i; 00262 { 00263 eq::ChannelStatistics stat( eq::Statistic::CHANNEL_FRAME_WAIT_READY, 00264 this ); 00265 frame->waitReady( ); 00266 } 00267 const eq::Range& range = frame->getRange(); 00268 if( range == eq::Range::ALL ) // 2D frame, assemble directly 00269 eq::Compositor::assembleFrame( frame, this ); 00270 else 00271 { 00272 dbFrames.push_back( frame ); 00273 zoom = frame->getZoom(); 00274 _expandPVP( coveredPVP, frame->getImages(), frame->getOffset() ); 00275 } 00276 } 00277 coveredPVP.intersect( getPixelViewport( )); 00278 00279 if( dbFrames.empty( )) 00280 { 00281 resetAssemblyState(); 00282 return; 00283 } 00284 00285 // calculate correct frames sequence 00286 if( !composeOnly && coveredPVP.hasArea( )) 00287 { 00288 _frame.clear(); 00289 data->setRange( _drawRange ); 00290 dbFrames.push_back( &_frame ); 00291 } 00292 00293 _orderFrames( dbFrames ); 00294 00295 // check if current frame is in proper position, read back if not 00296 if( !composeOnly ) 00297 { 00298 if( _bgColor == eq::Vector3f::ZERO && dbFrames.front() == &_frame ) 00299 dbFrames.erase( dbFrames.begin( )); 00300 else if( coveredPVP.hasArea()) 00301 { 00302 eq::Window::ObjectManager* glObjects = getObjectManager(); 00303 00304 _frame.setOffset( eq::Vector2i( 0, 0 )); 00305 _frame.setZoom( zoom ); 00306 data->setPixelViewport( coveredPVP ); 00307 _frame.readback( glObjects, getDrawableConfig( )); 00308 clearViewport( coveredPVP ); 00309 00310 // offset for assembly 00311 _frame.setOffset( eq::Vector2i( coveredPVP.x, coveredPVP.y )); 00312 } 00313 } 00314 00315 // blend DB frames in order 00316 eq::Compositor::assembleFramesSorted( dbFrames, this, 0, true /*blendAlpha*/ ); 00317 resetAssemblyState(); 00318 00319 // Update range 00320 _drawRange = getRange(); 00321 } 00322 00323 void Channel::_startAssemble() 00324 { 00325 applyBuffer(); 00326 applyViewport(); 00327 setupAssemblyState(); 00328 } 00329 00330 void Channel::frameReadback( const eq::uint128_t& frameID ) 00331 { 00332 // Drop depth buffer flag from all output frames 00333 const eq::Frames& frames = getOutputFrames(); 00334 const FrameData& frameData = _getFrameData(); 00335 for( eq::Frames::const_iterator i = frames.begin(); 00336 i != frames.end(); ++i ) 00337 { 00338 eq::Frame* frame = *i; 00339 frame->setQuality( eq::Frame::BUFFER_COLOR, frameData.getQuality()); 00340 frame->disableBuffer( eq::Frame::BUFFER_DEPTH ); 00341 } 00342 00343 eq::Channel::frameReadback( frameID ); 00344 } 00345 00346 void Channel::frameViewFinish( const eq::uint128_t& frameID ) 00347 { 00348 _drawHelp(); 00349 _drawLogo(); 00350 } 00351 00352 void Channel::_drawLogo( ) 00353 { 00354 // Draw the overlay logo 00355 const Window* window = static_cast<Window*>( getWindow( )); 00356 const eq::util::Texture* texture = window->getLogoTexture(); 00357 if( !texture ) 00358 return; 00359 00360 glMatrixMode( GL_PROJECTION ); 00361 glLoadIdentity(); 00362 applyScreenFrustum(); 00363 glMatrixMode( GL_MODELVIEW ); 00364 glLoadIdentity(); 00365 00366 glDisable( GL_DEPTH_TEST ); 00367 glDisable( GL_LIGHTING ); 00368 glEnable( GL_BLEND ); 00369 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); 00370 00371 glColor3f( 1.0f, 1.0f, 1.0f ); 00372 const GLenum target = texture->getTarget(); 00373 glEnable( target ); 00374 texture->bind(); 00375 glTexParameteri( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); 00376 glTexParameteri( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); 00377 00378 const float tWidth = float( texture->getWidth( ) ); 00379 const float tHeight = float( texture->getHeight( ) ); 00380 00381 const float width = target == GL_TEXTURE_2D ? 1.0f : tWidth; 00382 const float height = target == GL_TEXTURE_2D ? 1.0f : tHeight; 00383 00384 glBegin( GL_QUADS ); { 00385 glTexCoord2f( 0, 0 ); 00386 glVertex3f( 5.0f, 5.0f, 0.0f ); 00387 00388 glTexCoord2f( width, 0 ); 00389 glVertex3f( tWidth + 5.0f, 5.0f, 0.0f ); 00390 00391 glTexCoord2f( width, height ); 00392 glVertex3f( tWidth + 5.0f, tHeight + 5.0f, 0.0f ); 00393 00394 glTexCoord2f( 0, height ); 00395 glVertex3f( 5.0f, tHeight + 5.0f, 0.0f ); 00396 00397 } glEnd(); 00398 00399 glDisable( target ); 00400 glDisable( GL_BLEND ); 00401 } 00402 00403 void Channel::_drawHelp() 00404 { 00405 const FrameData& frameData = _getFrameData(); 00406 std::string message = frameData.getMessage(); 00407 00408 if( !frameData.showHelp() && message.empty( )) 00409 return; 00410 00411 applyBuffer(); 00412 applyViewport(); 00413 setupAssemblyState(); 00414 00415 glDisable( GL_LIGHTING ); 00416 glDisable( GL_DEPTH_TEST ); 00417 00418 glColor3f( 1.f, 1.f, 1.f ); 00419 00420 if( frameData.showHelp( )) 00421 { 00422 const eq::Window::Font* font = getWindow()->getSmallFont(); 00423 std::string help = EVolve::getHelp(); 00424 float y = 340.f; 00425 00426 for( size_t pos = help.find( '\n' ); pos != std::string::npos; 00427 pos = help.find( '\n' )) 00428 { 00429 glRasterPos3f( 10.f, y, 0.99f ); 00430 00431 font->draw( help.substr( 0, pos )); 00432 help = help.substr( pos + 1 ); 00433 y -= 16.f; 00434 } 00435 // last line 00436 glRasterPos3f( 10.f, y, 0.99f ); 00437 font->draw( help ); 00438 } 00439 00440 if( !message.empty( )) 00441 { 00442 const eq::Window::Font* font = getWindow()->getMediumFont(); 00443 00444 const eq::Viewport& vp = getViewport(); 00445 const eq::PixelViewport& pvp = getPixelViewport(); 00446 00447 const float width = pvp.w / vp.w; 00448 const float xOffset = vp.x * width; 00449 00450 const float height = pvp.h / vp.h; 00451 const float yOffset = vp.y * height; 00452 const float yMiddle = 0.5f * height; 00453 float y = yMiddle - yOffset; 00454 00455 for( size_t pos = message.find( '\n' ); pos != std::string::npos; 00456 pos = message.find( '\n' )) 00457 { 00458 glRasterPos3f( 10.f - xOffset, y, 0.99f ); 00459 00460 font->draw( message.substr( 0, pos )); 00461 message = message.substr( pos + 1 ); 00462 y -= 22.f; 00463 } 00464 // last line 00465 glRasterPos3f( 10.f - xOffset, y, 0.99f ); 00466 font->draw( message ); 00467 } 00468 00469 EQ_GL_CALL( resetAssemblyState( )); 00470 } 00471 00472 00473 }