server/canvas.cpp

00001 
00002 /* Copyright (c) 2009, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #include "canvas.h"
00019 
00020 #include "channel.h"
00021 #include "compound.h"
00022 #include "config.h"
00023 #include "layout.h"
00024 #include "log.h"
00025 #include "nameFinder.h"
00026 #include "node.h"
00027 #include "paths.h"
00028 #include "pipe.h"
00029 #include "segment.h"
00030 #include "window.h"
00031 
00032 #include <eq/net/dataIStream.h>
00033 #include <eq/net/dataOStream.h>
00034 
00035 
00036 using namespace eq::base;
00037 
00038 namespace eq
00039 {
00040 namespace server
00041 {
00042 
00043 Canvas::Canvas()
00044         : _config( 0 )
00045         , _activeLayout( 0 )
00046 {}
00047 
00048 Canvas::Canvas( const Canvas& from, Config* config )
00049         : eq::Frustum( from )
00050         , _config( 0 )
00051         , _activeLayout( from._activeLayout )
00052 {
00053     EQASSERT( config );
00054 
00055     for( SegmentVector::const_iterator i = from._segments.begin();
00056          i != from._segments.end(); ++i )
00057     {
00058         addSegment( new Segment( **i, config ));
00059     }
00060 
00061     for( LayoutVector::const_iterator i = from._layouts.begin();
00062          i != from._layouts.end(); ++i )
00063     {
00064         const Layout* layout = *i;
00065         if( layout )
00066         {
00067             const LayoutPath path( layout->getPath( ));
00068             addLayout( config->getLayout( path ));
00069         }
00070         else
00071             addLayout( 0 );
00072     }
00073 
00074     config->addCanvas( this );
00075     EQASSERT( _config );
00076 }
00077 
00078 Canvas::~Canvas()
00079 {
00080     for( SegmentVector::const_iterator i = _segments.begin();
00081          i != _segments.end(); ++i )
00082     {
00083         Segment* segment = *i;
00084         segment->_canvas = 0;
00085         delete segment;
00086     }
00087     _segments.clear();
00088     _layouts.clear();
00089 
00090     if( _config )
00091         _config->removeCanvas( this );
00092 
00093     _config = 0;
00094     _activeLayout = 0;
00095 }
00096 
00097 void Canvas::getInstanceData( net::DataOStream& os )
00098 {
00099     // This function is overwritten from eq::Object, since the class is
00100     // intended to be subclassed on the client side. When serializing a
00101     // server::Canvas, we only transmit the effective bits, not all since that
00102     // potentially includes bits from subclassed eq::Canvases.
00103     const uint64_t dirty = eq::Canvas::DIRTY_CUSTOM - 1;
00104     os << dirty;
00105     serialize( os, dirty );
00106 }
00107 
00108 void Canvas::serialize( net::DataOStream& os, const uint64_t dirtyBits )
00109 {
00110     Frustum::serialize( os, dirtyBits );
00111 
00112     if( dirtyBits & eq::Canvas::DIRTY_LAYOUT )
00113         os << _activeLayout;
00114 
00115     if( dirtyBits & eq::Canvas::DIRTY_CHILDREN )
00116     {
00117         for( SegmentVector::const_iterator i = _segments.begin(); 
00118              i != _segments.end(); ++i )
00119         {
00120             Segment* segment = *i;
00121             EQASSERT( segment->getID() != EQ_ID_INVALID );
00122             os << segment->getID();
00123         }
00124         os << EQ_ID_INVALID;
00125 
00126         for( LayoutVector::const_iterator i = _layouts.begin(); 
00127              i != _layouts.end(); ++i )
00128         {
00129             Layout* layout = *i;
00130             if( layout )
00131             {
00132                 EQASSERT( layout->getID() != EQ_ID_INVALID );
00133                 os << layout->getID();
00134             }
00135             else
00136                 os << EQ_ID_NONE;
00137         }
00138         os << EQ_ID_INVALID;
00139     }
00140 }
00141 
00142 void Canvas::deserialize( net::DataIStream& is, const uint64_t dirtyBits )
00143 {
00144     Frustum::deserialize( is, dirtyBits );
00145 
00146     if( dirtyBits & eq::Canvas::DIRTY_LAYOUT )
00147     {
00148         uint32_t index;
00149         is >> index;
00150         _useLayout( index );
00151     }
00152 }
00153 
00154 Segment* Canvas::getSegment( const SegmentPath& path )
00155 {
00156     EQASSERTINFO( _segments.size() > path.segmentIndex,
00157                   _segments.size() << " <= " << path.segmentIndex );
00158 
00159     if( _segments.size() <= path.segmentIndex )
00160         return 0;
00161 
00162     return _segments[ path.segmentIndex ];
00163 }
00164 
00165 CanvasPath Canvas::getPath() const
00166 {
00167     EQASSERT( _config );
00168 
00169     const CanvasVector& canvases = _config->getCanvases();
00170     CanvasVector::const_iterator i = std::find( canvases.begin(),
00171                                                  canvases.end(), this );
00172     EQASSERT( i != canvases.end( ));
00173 
00174     CanvasPath path;
00175     path.canvasIndex = std::distance( canvases.begin(), i );
00176     return path;
00177 }
00178 
00179 void Canvas::addSegment( Segment* segment )
00180 {
00181     EQASSERT( segment );
00182     EQASSERT( std::find( _segments.begin(), _segments.end(), segment ) == 
00183               _segments.end( ));
00184     
00185     // if segment has no frustum...
00186     if( segment->getCurrentType() == TYPE_NONE )
00187     {
00188         if( getCurrentType() != TYPE_NONE ) // ... and canvas has frustum
00189         {
00190             eq::Wall wall( getWall( ));
00191             const Viewport& viewport( segment->getViewport( ));
00192             wall.apply( viewport );
00193                     
00194             switch( getCurrentType( ))
00195             {
00196                 case Frustum::TYPE_WALL:
00197                     segment->setWall( wall );
00198                     EQLOG( LOG_VIEW ) << "Segment " << segment->getName() 
00199                                       << segment->getWall() << std::endl;
00200                     break;
00201 
00202                 case Frustum::TYPE_PROJECTION:
00203                 {
00204                     Projection projection( getProjection( )); // keep distance
00205                     projection = wall;
00206                     segment->setProjection( projection );
00207                     break;
00208                 }
00209                 default: 
00210                     EQUNIMPLEMENTED;
00211                     break; 
00212             }
00213         }
00214     }
00215 
00216     segment->_canvas = this;
00217     _segments.push_back( segment );
00218 }
00219 
00220 Segment* Canvas::findSegment( const std::string& name )
00221 {
00222     SegmentFinder finder( name );
00223     accept( finder );
00224     return finder.getResult();
00225 }
00226 
00227 void Canvas::addLayout( Layout* layout )
00228 {
00229     EQASSERT( std::find( _layouts.begin(), _layouts.end(), layout ) == 
00230               _layouts.end( ));
00231 
00232     // dest channel creation is done be Config::addCanvas
00233     _layouts.push_back( layout );
00234 }
00235 
00236 void Canvas::_useLayout( const uint32_t index )
00237 {
00238     if( _config && _config->isRunning( ))
00239         _switchLayout( _activeLayout, index );
00240 
00241     _activeLayout = index;
00242 }
00243 
00244 void Canvas::init()
00245 {
00246     _switchLayout( EQ_ID_NONE, _activeLayout );
00247 }
00248 
00249 void Canvas::exit()
00250 {
00251     _switchLayout( _activeLayout, EQ_ID_NONE );
00252 }
00253 
00254 namespace
00255 {
00256 class ActivateVisitor : public ConfigVisitor
00257 {
00258 public:
00259     ActivateVisitor( const ChannelVector& channels ) : _channels( channels ) {}
00260     virtual ~ActivateVisitor() {}
00261 
00262     virtual VisitorResult visit( Compound* compound )
00263         {
00264             Channel* channel = compound->getChannel();
00265             if( !channel )
00266                 return TRAVERSE_CONTINUE;
00267             
00268             for( ChannelVector::iterator i = _channels.begin();
00269                  i != _channels.end(); ++i )
00270             {
00271                 Channel* destChannel = *i;
00272                 if( destChannel != channel ) 
00273                     continue;
00274 
00275                 compound->activate();
00276                 _channels.erase( i );
00277                 break;
00278             }
00279 
00280             return TRAVERSE_PRUNE;
00281         }
00282 
00283     virtual VisitorResult visitPost( Config* config )
00284         { 
00285             if( !_channels.empty( ))
00286                 EQWARN << _channels.size() << " unused destination channels"
00287                        << std::endl;
00288             return TRAVERSE_CONTINUE;
00289         }
00290 
00291 private:
00292     ChannelVector _channels;
00293 };
00294 
00295 class DeactivateVisitor : public ConfigVisitor
00296 {
00297 public:
00298     DeactivateVisitor( ChannelVector& channels )
00299             : _channels( channels ) {}
00300     virtual ~DeactivateVisitor() {}
00301 
00302     virtual VisitorResult visit( Compound* compound )
00303         {
00304             Channel* channel = compound->getChannel();
00305             if( !channel )
00306                 return TRAVERSE_CONTINUE;
00307             
00308             for( ChannelVector::iterator i = _channels.begin();
00309                  i != _channels.end(); ++i )
00310             {
00311                 Channel* destChannel = *i;
00312                 if( destChannel != channel ) 
00313                     continue;
00314 
00315                 compound->deactivate();
00316                 _channels.erase( i );
00317                 break;
00318             }
00319 
00320             return TRAVERSE_PRUNE;
00321         }
00322 
00323     virtual VisitorResult visitPost( Config* config )
00324         { 
00325             if( !_channels.empty( ))
00326                 EQWARN << _channels.size() << " unused destination channels"
00327                        << std::endl;
00328             return TRAVERSE_CONTINUE;
00329         }
00330 
00331 private:
00332     ChannelVector& _channels;
00333 };
00334 }
00335 
00336 void Canvas::_switchLayout( const uint32_t oldIndex, const uint32_t newIndex )
00337 {
00338     EQASSERT( _config );
00339 
00340     const size_t nLayouts = _layouts.size();
00341     const Layout* oldLayout = (oldIndex >= nLayouts) ? 0 :_layouts[oldIndex];
00342     const Layout* newLayout = (newIndex >= nLayouts) ? 0 :_layouts[newIndex];
00343 
00344     for( SegmentVector::const_iterator i = _segments.begin();
00345          i != _segments.end(); ++i )
00346     {
00347         const Segment* segment = *i;        
00348         const ChannelVector& destChannels = segment->getDestinationChannels();
00349 
00350         if( newLayout )
00351         {
00352             // activate channels used by new layout
00353             ChannelVector usedChannels;
00354             for( ChannelVector::const_iterator j = destChannels.begin();
00355                  j != destChannels.end(); ++j )
00356             {
00357                 Channel*       channel       = *j;
00358                 const Layout*  channelLayout = channel->getLayout();
00359                 if( channelLayout == newLayout )
00360                     usedChannels.push_back( channel );
00361             }
00362             
00363             ActivateVisitor activator( usedChannels );
00364             _config->accept( activator );
00365         }
00366 
00367         if( oldLayout )
00368         {
00369             // de-activate channels used by old layout
00370             ChannelVector usedChannels;
00371 
00372             for( ChannelVector::const_iterator j = destChannels.begin();
00373                  j != destChannels.end(); ++j )
00374             {
00375                 Channel*       channel       = *j;
00376                 const Layout*  channelLayout = channel->getLayout();
00377                 if( channelLayout == oldLayout )
00378                     usedChannels.push_back( channel );
00379             }
00380             DeactivateVisitor deactivator( usedChannels );
00381             _config->accept( deactivator );
00382         }
00383     }
00384 }
00385 
00386 namespace
00387 {
00388 template< class C, class V >
00389 VisitorResult _accept( C* canvas, V& visitor )
00390 {
00391     VisitorResult result = visitor.visitPre( canvas );
00392     if( result != TRAVERSE_CONTINUE )
00393         return result;
00394 
00395     const SegmentVector& segments = canvas->getSegments();
00396     for( SegmentVector::const_iterator i = segments.begin(); 
00397          i != segments.end(); ++i )
00398     {
00399         switch( (*i)->accept( visitor ))
00400         {
00401             case TRAVERSE_TERMINATE:
00402                 return TRAVERSE_TERMINATE;
00403 
00404             case TRAVERSE_PRUNE:
00405                 result = TRAVERSE_PRUNE;
00406                 break;
00407                 
00408             case TRAVERSE_CONTINUE:
00409             default:
00410                 break;
00411         }
00412     }
00413 
00414     switch( visitor.visitPost( canvas ))
00415     {
00416         case TRAVERSE_TERMINATE:
00417             return TRAVERSE_TERMINATE;
00418 
00419         case TRAVERSE_PRUNE:
00420             return TRAVERSE_PRUNE;
00421                 
00422         case TRAVERSE_CONTINUE:
00423         default:
00424             break;
00425     }
00426 
00427     return result;
00428 }
00429 }
00430 
00431 VisitorResult Canvas::accept( CanvasVisitor& visitor )
00432 {
00433     return _accept( this, visitor );
00434 }
00435 
00436 VisitorResult Canvas::accept( ConstCanvasVisitor& visitor ) const
00437 {
00438     return _accept( this, visitor );
00439 }
00440 
00441 void Canvas::unmap()
00442 {
00443     net::Session* session = getSession();
00444     EQASSERT( session );
00445     for( SegmentVector::const_iterator i = _segments.begin(); 
00446          i != _segments.end(); ++i )
00447     {
00448         Segment* segment = *i;
00449         EQASSERT( segment->getID() != EQ_ID_INVALID );
00450         
00451         session->unmapObject( segment );
00452     }
00453 
00454     EQASSERT( getID() != EQ_ID_INVALID );
00455     session->unmapObject( this );
00456 }
00457 
00458 std::ostream& operator << ( std::ostream& os, const Canvas* canvas )
00459 {
00460     if( !canvas )
00461         return os;
00462     
00463     os << disableFlush << disableHeader << "canvas" << std::endl;
00464     os << "{" << std::endl << indent; 
00465 
00466     const std::string& name = canvas->getName();
00467     if( !name.empty( ))
00468         os << "name     \"" << name << "\"" << std::endl;
00469 
00470     const LayoutVector& layouts = canvas->getLayouts();
00471     for( LayoutVector::const_iterator i = layouts.begin(); 
00472          i != layouts.end(); ++i )
00473     {
00474         Layout* layout = *i;
00475         if( layout )
00476         {
00477             const Config*      config     = layout->getConfig();
00478             const std::string& layoutName = layout->getName();
00479             if( layoutName.empty() || 
00480                 config->findLayout( layoutName ) != layout )
00481                 os << layout->getPath() << std::endl;
00482             else
00483                 os << "layout   \"" << layout->getName() << "\"" << std::endl;
00484         }
00485         else
00486             os << "layout   OFF" << std::endl;
00487     }
00488 
00489     os << static_cast< const eq::Frustum& >( *canvas );
00490 
00491     const SegmentVector& segments = canvas->getSegments();
00492     for( SegmentVector::const_iterator i = segments.begin(); 
00493          i != segments.end(); ++i )
00494     {
00495         os << *i;
00496     }
00497     os << exdent << "}" << std::endl << enableHeader << enableFlush;
00498     return os;
00499 }
00500 
00501 }
00502 }
Generated on Mon Aug 10 18:58:31 2009 for Equalizer 0.9 by  doxygen 1.5.8