void ImageView::insertConverter( Gaffer::NodePtr converter ) { PlugPtr converterInput = converter->getChild<Plug>( "in" ); if( !converterInput ) { throw IECore::Exception( "Converter has no Plug named \"in\"" ); } ImagePlugPtr converterOutput = converter->getChild<ImagePlug>( "out" ); if( !converterOutput ) { throw IECore::Exception( "Converter has no ImagePlug named \"out\"" ); } PlugPtr newInput = converterInput->createCounterpart( "in", Plug::In ); setChild( "in", newInput ); NodePtr preprocessor = getPreprocessor<Node>(); Plug::OutputContainer outputsToRestore = preprocessor->getChild<ImagePlug>( "in" )->outputs(); PlugPtr newPreprocessorInput = converterInput->createCounterpart( "in", Plug::In ); preprocessor->setChild( "in", newPreprocessorInput ); newPreprocessorInput->setInput( newInput ); preprocessor->setChild( "__converter", converter ); converterInput->setInput( newPreprocessorInput ); for( Plug::OutputContainer::const_iterator it = outputsToRestore.begin(), eIt = outputsToRestore.end(); it != eIt; ++it ) { (*it)->setInput( converterOutput ); } }
void ScriptNode::deleteNodes( Node *parent, const Set *filter, bool reconnect ) { parent = parent ? parent : this; // because children are stored as a vector, it's // much more efficient to delete those at the end before // those at the beginning. int i = (int)(parent->children().size()) - 1; while( i >= 0 ) { Node *node = parent->getChild<Node>( i ); if( node && ( !filter || filter->contains( node ) ) ) { // reconnect the inputs and outputs as though the node was disabled DependencyNode *dependencyNode = IECore::runTimeCast<DependencyNode>( node ); if( reconnect && dependencyNode ) { for( OutputPlugIterator it( node ); it != it.end(); ++it ) { Plug *inPlug = dependencyNode->correspondingInput( it->get() ); if ( !inPlug ) { continue; } Plug *srcPlug = inPlug->getInput<Plug>(); if ( !srcPlug ) { continue; } // record this plug's current outputs, and reconnect them. This is a copy of (*it)->outputs() rather // than a reference, as reconnection can modify (*it)->outputs()... Plug::OutputContainer outputs = (*it)->outputs(); for ( Plug::OutputContainer::const_iterator oIt = outputs.begin(); oIt != outputs.end(); ) { Plug *dstPlug = *oIt; if ( dstPlug && dstPlug->acceptsInput( srcPlug ) && this->isAncestorOf( dstPlug ) ) { oIt++; dstPlug->setInput( srcPlug ); } else { oIt++; } } } } parent->removeChild( node ); } i--; } }
void ScriptNode::deleteNodes( Node *parent, const Set *filter, bool reconnect ) { parent = parent ? parent : this; // because children are stored as a vector, it's // much more efficient to delete those at the end before // those at the beginning. int i = (int)(parent->children().size()) - 1; while( i >= 0 ) { Node *node = parent->getChild<Node>( i ); if( node && ( !filter || filter->contains( node ) ) ) { // reconnect the inputs and outputs as though the node was disabled DependencyNode *dependencyNode = IECore::runTimeCast<DependencyNode>( node ); if( reconnect && dependencyNode ) { for( RecursiveOutputPlugIterator it( node ); !it.done(); ++it ) { Plug *inPlug = nullptr; try { inPlug = dependencyNode->correspondingInput( it->get() ); } catch( const std::exception &e ) { msg( IECore::Msg::Warning, boost::str( boost::format( "correspondingInput error while deleting - cannot reconnect \"%s\"" ) % it->get()->fullName() ), e.what() ); } if ( !inPlug ) { continue; } Plug *srcPlug = inPlug->getInput(); if ( !srcPlug ) { continue; } // record this plug's current outputs, and reconnect them. This is a copy of (*it)->outputs() rather // than a reference, as reconnection can modify (*it)->outputs()... Plug::OutputContainer outputs = (*it)->outputs(); for ( Plug::OutputContainer::const_iterator oIt = outputs.begin(); oIt != outputs.end(); ++oIt ) { Plug *dstPlug = *oIt; if ( dstPlug && dstPlug->acceptsInput( srcPlug ) && this->isAncestorOf( dstPlug ) ) { dstPlug->setInput( srcPlug ); } } } } parent->removeChild( node ); } i--; } }
BoxPtr Box::create( Node *parent, const Set *childNodes ) { BoxPtr result = new Box; parent->addChild( result ); // it's pretty natural to call this function passing childNodes == ScriptNode::selection(). // unfortunately nodes will be removed from the selection as we reparent // them, so we have to make a copy of childNodes so our iteration isn't befuddled by // the changing contents. we can use this opportunity to weed out anything in childNodes // which isn't a direct child of parent though. StandardSetPtr verifiedChildNodes = new StandardSet(); for( NodeIterator nodeIt( parent ); nodeIt != nodeIt.end(); nodeIt++ ) { if( childNodes->contains( nodeIt->get() ) ) { verifiedChildNodes->add( *nodeIt ); } } // when a node we're putting in the box has connections to // a node remaining outside, we need to reroute the connection // via an intermediate plug on the box. this mapping maps input // plugs (be they internal or external) to intermediate input plugs. typedef std::pair<const Plug *, Plug *> PlugPair; typedef std::map<const Plug *, Plug *> PlugMap; PlugMap plugMap; for( size_t i = 0, e = verifiedChildNodes->size(); i < e; i++ ) { Node *childNode = static_cast<Node *>( verifiedChildNodes->member( i ) ); // reroute any connections to external nodes for( RecursivePlugIterator plugIt( childNode ); plugIt != plugIt.end(); plugIt++ ) { Plug *plug = plugIt->get(); if( plug->direction() == Plug::In ) { Plug *input = plug->getInput<Plug>(); if( input && !verifiedChildNodes->contains( input->node() ) ) { PlugMap::const_iterator mapIt = plugMap.find( input ); if( mapIt == plugMap.end() ) { PlugPtr intermediateInput = plug->createCounterpart( result->promotedCounterpartName( plug ), Plug::In ); // we want intermediate inputs to appear on the same side of the node as the // equivalent internal plug, so we copy the relevant metadata over. copyMetadata( plug, intermediateInput.get() ); intermediateInput->setFlags( Plug::Dynamic, true ); result->addChild( intermediateInput ); intermediateInput->setInput( input ); mapIt = plugMap.insert( PlugPair( input, intermediateInput.get() ) ).first; } plug->setInput( mapIt->second ); plugIt.prune(); } } else { // take a copy of the outputs, because we might be modifying the // original as we iterate. Plug::OutputContainer outputs = plug->outputs(); if( !outputs.empty() ) { typedef Plug::OutputContainer::const_iterator OutputIterator; for( OutputIterator oIt = outputs.begin(), eIt = outputs.end(); oIt != eIt; oIt++ ) { Plug *output = *oIt; const Node *outputNode = output->node(); if( outputNode->parent<Node>() == parent && !verifiedChildNodes->contains( outputNode ) ) { PlugMap::const_iterator mapIt = plugMap.find( plug ); if( mapIt == plugMap.end() ) { PlugPtr intermediateOutput = plug->createCounterpart( result->promotedCounterpartName( plug ), Plug::Out ); copyMetadata( plug, intermediateOutput.get() ); intermediateOutput->setFlags( Plug::Dynamic, true ); result->addChild( intermediateOutput ); intermediateOutput->setInput( plug ); mapIt = plugMap.insert( PlugPair( plug, intermediateOutput.get() ) ).first; } output->setInput( mapIt->second ); } } plugIt.prune(); } } } // reparent the child under the Box. it's important that we do this after adding the intermediate // input plugs, so that when they are serialised and reloaded, the inputs to the box are set before // the inputs to the nodes inside the box - see GafferSceneTest.ShaderAssignmentTest.testAssignShaderFromOutsideBox // for a test case highlighting this necessity. result->addChild( childNode ); } return result; }