server/canvas.cpp

00001 
00002 /* Copyright (c) 2009-2010, 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                 break;
00277             }
00278 
00279             return TRAVERSE_PRUNE;
00280         }
00281 
00282 private:
00283     ChannelVector _channels;
00284 };
00285 
00286 class DeactivateVisitor : public ConfigVisitor
00287 {
00288 public:
00289     DeactivateVisitor( ChannelVector& channels )
00290             : _channels( channels ) {}
00291     virtual ~DeactivateVisitor() {}
00292 
00293     virtual VisitorResult visit( Compound* compound )
00294         {
00295             Channel* channel = compound->getChannel();
00296             if( !channel )
00297                 return TRAVERSE_CONTINUE;
00298             
00299             for( ChannelVector::iterator i = _channels.begin();
00300                  i != _channels.end(); ++i )
00301             {
00302                 Channel* destChannel = *i;
00303                 if( destChannel != channel ) 
00304                     continue;
00305 
00306                 compound->deactivate();
00307                 break;
00308             }
00309 
00310             return TRAVERSE_PRUNE;
00311         }
00312 
00313 private:
00314     ChannelVector& _channels;
00315 };
00316 }
00317 
00318 void Canvas::_switchLayout( const uint32_t oldIndex, const uint32_t newIndex )
00319 {
00320     EQASSERT( _config );
00321     if( oldIndex == newIndex )
00322         return;
00323 
00324     const size_t nLayouts = _layouts.size();
00325     const Layout* oldLayout = (oldIndex >= nLayouts) ? 0 :_layouts[oldIndex];
00326     const Layout* newLayout = (newIndex >= nLayouts) ? 0 :_layouts[newIndex];
00327 
00328     for( SegmentVector::const_iterator i = _segments.begin();
00329          i != _segments.end(); ++i )
00330     {
00331         const Segment* segment = *i;        
00332         const ChannelVector& destChannels = segment->getDestinationChannels();
00333 
00334         if( newLayout )
00335         {
00336             // activate channels used by new layout
00337             ChannelVector usedChannels;
00338             for( ChannelVector::const_iterator j = destChannels.begin();
00339                  j != destChannels.end(); ++j )
00340             {
00341                 Channel*       channel       = *j;
00342                 const Layout*  channelLayout = channel->getLayout();
00343                 if( channelLayout == newLayout )
00344                     usedChannels.push_back( channel );
00345             }
00346             
00347             ActivateVisitor activator( usedChannels );
00348             _config->accept( activator );
00349         }
00350 
00351         if( oldLayout )
00352         {
00353             // de-activate channels used by old layout
00354             ChannelVector usedChannels;
00355 
00356             for( ChannelVector::const_iterator j = destChannels.begin();
00357                  j != destChannels.end(); ++j )
00358             {
00359                 Channel*       channel       = *j;
00360                 const Layout*  channelLayout = channel->getLayout();
00361                 if( channelLayout == oldLayout )
00362                     usedChannels.push_back( channel );
00363             }
00364             DeactivateVisitor deactivator( usedChannels );
00365             _config->accept( deactivator );
00366         }
00367     }
00368 }
00369 
00370 namespace
00371 {
00372 template< class C >
00373 VisitorResult _accept( C* canvas, CanvasVisitor& visitor )
00374 {
00375     VisitorResult result = visitor.visitPre( canvas );
00376     if( result != TRAVERSE_CONTINUE )
00377         return result;
00378 
00379     const SegmentVector& segments = canvas->getSegments();
00380     for( SegmentVector::const_iterator i = segments.begin(); 
00381          i != segments.end(); ++i )
00382     {
00383         switch( (*i)->accept( visitor ))
00384         {
00385             case TRAVERSE_TERMINATE:
00386                 return TRAVERSE_TERMINATE;
00387 
00388             case TRAVERSE_PRUNE:
00389                 result = TRAVERSE_PRUNE;
00390                 break;
00391                 
00392             case TRAVERSE_CONTINUE:
00393             default:
00394                 break;
00395         }
00396     }
00397 
00398     switch( visitor.visitPost( canvas ))
00399     {
00400         case TRAVERSE_TERMINATE:
00401             return TRAVERSE_TERMINATE;
00402 
00403         case TRAVERSE_PRUNE:
00404             return TRAVERSE_PRUNE;
00405                 
00406         case TRAVERSE_CONTINUE:
00407         default:
00408             break;
00409     }
00410 
00411     return result;
00412 }
00413 }
00414 
00415 VisitorResult Canvas::accept( CanvasVisitor& visitor )
00416 {
00417     return _accept( this, visitor );
00418 }
00419 
00420 VisitorResult Canvas::accept( CanvasVisitor& visitor ) const
00421 {
00422     return _accept( this, visitor );
00423 }
00424 
00425 void Canvas::unmap()
00426 {
00427     net::Session* session = getSession();
00428     EQASSERT( session );
00429     for( SegmentVector::const_iterator i = _segments.begin(); 
00430          i != _segments.end(); ++i )
00431     {
00432         Segment* segment = *i;
00433         EQASSERT( segment->getID() != EQ_ID_INVALID );
00434         
00435         session->unmapObject( segment );
00436     }
00437 
00438     EQASSERT( getID() != EQ_ID_INVALID );
00439     session->unmapObject( this );
00440 }
00441 
00442 std::ostream& operator << ( std::ostream& os, const Canvas* canvas )
00443 {
00444     if( !canvas )
00445         return os;
00446     
00447     os << disableFlush << disableHeader << "canvas" << std::endl;
00448     os << "{" << std::endl << indent; 
00449 
00450     const std::string& name = canvas->getName();
00451     if( !name.empty( ))
00452         os << "name     \"" << name << "\"" << std::endl;
00453 
00454     const LayoutVector& layouts = canvas->getLayouts();
00455     for( LayoutVector::const_iterator i = layouts.begin(); 
00456          i != layouts.end(); ++i )
00457     {
00458         Layout* layout = *i;
00459         if( layout )
00460         {
00461             const Config*      config     = layout->getConfig();
00462             const std::string& layoutName = layout->getName();
00463             if( layoutName.empty() || 
00464                 config->findLayout( layoutName ) != layout )
00465                 os << layout->getPath() << std::endl;
00466             else
00467                 os << "layout   \"" << layout->getName() << "\"" << std::endl;
00468         }
00469         else
00470             os << "layout   OFF" << std::endl;
00471     }
00472 
00473     os << static_cast< const eq::Frustum& >( *canvas );
00474 
00475     const SegmentVector& segments = canvas->getSegments();
00476     for( SegmentVector::const_iterator i = segments.begin(); 
00477          i != segments.end(); ++i )
00478     {
00479         os << *i;
00480     }
00481     os << exdent << "}" << std::endl << enableHeader << enableFlush;
00482     return os;
00483 }
00484 
00485 }
00486 }
Generated on Sat Feb 6 12:59:42 2010 for Equalizer 0.9.1 by  doxygen 1.6.1