OpenWalnut  1.4.0
WGEGroupNode.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include <iostream>
00026 
00027 #include <osg/ShapeDrawable>
00028 #include <osg/MatrixTransform>
00029 #include <osg/Geode>
00030 
00031 #include "WGEGroupNode.h"
00032 
00033 WGEGroupNode::WGEGroupNode():
00034     osg::MatrixTransform(),
00035     m_childOperationQueueDirty( false ),
00036     m_removeAll( false )
00037 {
00038     setDataVariance( osg::Object::DYNAMIC );
00039 
00040     // setup an update callback
00041     m_nodeUpdater = osg::ref_ptr< SafeUpdaterCallback >( new SafeUpdaterCallback() );
00042     addUpdateCallback( m_nodeUpdater );
00043 
00044     osg::Matrix m;
00045     m.makeIdentity();
00046     setMatrix( m );
00047 }
00048 
00049 WGEGroupNode::~WGEGroupNode()
00050 {
00051     // cleanup
00052 }
00053 
00054 void WGEGroupNode::insert( osg::ref_ptr< osg::Node > node )
00055 {
00056     boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_childOperationQueueLock );
00057     m_childOperationQueue.push( boost::shared_ptr< ChildOperation >( new ChildOperation( INSERT, node ) ) );
00058     m_childOperationQueueDirty = true;
00059     lock.unlock();
00060 }
00061 
00062 void WGEGroupNode::remove( osg::ref_ptr< osg::Node > node )
00063 {
00064     boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_childOperationQueueLock );
00065     m_childOperationQueue.push( boost::shared_ptr< ChildOperation >( new ChildOperation( REMOVE, node ) ) );
00066     m_childOperationQueueDirty = true;
00067     lock.unlock();
00068 }
00069 
00070 void WGEGroupNode::remove_if( boost::shared_ptr< WGEGroupNode::NodePredicate > predicate )
00071 {
00072     boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_childOperationQueueLock );
00073     m_childOperationQueue.push( boost::shared_ptr< ChildOperation >( new ChildOperation( REMOVE_IF, predicate ) ) );
00074     m_childOperationQueueDirty = true;
00075     lock.unlock();
00076 }
00077 
00078 void WGEGroupNode::clear()
00079 {
00080     boost::unique_lock<boost::shared_mutex> lock = boost::unique_lock<boost::shared_mutex>( m_childOperationQueueLock );
00081     m_childOperationQueue.push( boost::shared_ptr< ChildOperation >( new ChildOperation( CLEAR, osg::ref_ptr< osg::Node >() ) ) );
00082     // this encodes the remove all feature
00083     m_childOperationQueueDirty = true;
00084     lock.unlock();
00085 }
00086 
00087 void WGEGroupNode::SafeUpdaterCallback::operator()( osg::Node* node, osg::NodeVisitor* nv )
00088 {
00089     // the node also is a WGEGroupNode
00090     WGEGroupNode* rootNode = static_cast< WGEGroupNode* >( node );
00091 
00092     // write lock the insertion list
00093     boost::unique_lock<boost::shared_mutex> lock;
00094 
00095     // write lock the removal list
00096     if( rootNode->m_childOperationQueueDirty )
00097     {
00098         lock = boost::unique_lock<boost::shared_mutex>( rootNode->m_childOperationQueueLock );
00099         // insert/remove children which requested it
00100         while( !rootNode->m_childOperationQueue.empty() )
00101         {
00102             // remove or insert or remove all?
00103             if( rootNode->m_childOperationQueue.front()->m_operation == INSERT )
00104             {
00105                 // add specified child
00106                 rootNode->addChild( rootNode->m_childOperationQueue.front()->m_item );
00107             }
00108 
00109             if( rootNode->m_childOperationQueue.front()->m_operation == REMOVE )
00110             {
00111                 // remove specified child
00112                 rootNode->removeChild( rootNode->m_childOperationQueue.front()->m_item );
00113             }
00114 
00115             if( rootNode->m_childOperationQueue.front()->m_operation == REMOVE_IF )
00116             {
00117                 // remove children where m_predicate is true
00118                 for( size_t i = 0; i < rootNode->getNumChildren(); )
00119                 {
00120                     if( ( *rootNode->m_childOperationQueue.front()->m_predicate )( rootNode->getChild( i ) ) )
00121                     {
00122                         // remove item but do not increment index
00123                         rootNode->removeChild( i );
00124                     }
00125 
00126                     // this was not removed. Go to next one.
00127                     ++i;
00128                 }
00129             }
00130 
00131             if( rootNode->m_childOperationQueue.front()->m_operation == CLEAR )
00132             {
00133                 // remove all
00134                 rootNode->removeChild( 0, rootNode->getNumChildren() );
00135             }
00136 
00137             // pop item
00138             rootNode->m_childOperationQueue.pop();
00139         }
00140 
00141         rootNode->dirtyBound();
00142 
00143         // all children added/removed -> clear
00144         rootNode->m_childOperationQueueDirty = false;
00145         rootNode->m_removeAll = false;
00146 
00147         lock.unlock();
00148     }
00149 
00150     // forward the call
00151     traverse( node, nv );
00152 }
00153