bool DotNodeGadget::drop( const DragDropEvent &event ) { if( dotNode()->inPlug<Plug>() ) { // We've already got our plugs set up - StandardNodeGadget // behaviour will take care of everything. return false; } Plug *plug = runTimeCast<Plug>( event.data.get() ); if( !plug ) { return false; } Gaffer::UndoScope undoEnabler( node()->ancestor<ScriptNode>() ); dotNode()->setup( plug ); if( plug->direction() == Plug::In ) { plug->setInput( dotNode()->outPlug<Plug>() ); } else { dotNode()->inPlug<Plug>()->setInput( plug ); } return true; }
void Plug::removeOutputs() { for( OutputContainer::iterator it = m_outputs.begin(); it!=m_outputs.end(); ) { Plug *p = *it++; p->setInput( 0 ); } }
void BoxIO::insert( Box *box ) { // Must take a copy of children because adding a child // would invalidate our PlugIterator. GraphComponent::ChildContainer children = box->children(); for( PlugIterator it( children ); !it.done(); ++it ) { Plug *plug = it->get(); if( plug->direction() == Plug::In ) { std::vector<Plug *> outputsNeedingBoxIn; const Plug::OutputContainer &outputs = plug->outputs(); for( Plug::OutputContainer::const_iterator oIt = outputs.begin(), oeIt = outputs.end(); oIt != oeIt; ++oIt ) { if( hasNodule( *oIt ) && !runTimeCast<BoxIO>( (*oIt)->node() ) ) { outputsNeedingBoxIn.push_back( *oIt ); } } if( outputsNeedingBoxIn.empty() ) { continue; } BoxInPtr boxIn = new BoxIn; boxIn->namePlug()->setValue( plug->getName() ); boxIn->setup( plug ); box->addChild( boxIn ); boxIn->inPlugInternal()->setInput( plug ); for( std::vector<Plug *>::const_iterator oIt = outputsNeedingBoxIn.begin(), oeIt = outputsNeedingBoxIn.end(); oIt != oeIt; ++oIt ) { (*oIt)->setInput( boxIn->plug() ); } } else { // Output plug Plug *input = plug->getInput(); if( !input || !hasNodule( input ) || runTimeCast<BoxIO>( input->node() ) ) { continue; } BoxOutPtr boxOut = new BoxOut; boxOut->namePlug()->setValue( plug->getName() ); boxOut->setup( plug ); box->addChild( boxOut ); boxOut->plug()->setInput( input ); plug->setInput( boxOut->outPlugInternal() ); } } }
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 CompoundNumericPlug<T>::ungang() { for( size_t i = 1, e = children().size(); i < e; ++i ) { Plug *child = getChild( i ); if( const Plug *input = child->getInput<Plug>() ) { if( input->parent<Plug>() == this ) { child->setInput( 0 ); } } } }
ArnoldMeshLight::ArnoldMeshLight( const std::string &name ) : GafferScene::FilteredSceneProcessor( name, IECore::PathMatcher::NoMatch ) { // ArnoldAttributesNode. This hides the objects from the majority // of ray types, since we don't want to add the poor sampling of the // object on top of the nice sampling of the light. The only visibility // option we don't turn off is camera visibility - instead we promote // so the user can decide whether or not the mesh should be visible in // the render. ArnoldAttributesPtr attributes = new ArnoldAttributes( "__attributes" ); attributes->inPlug()->setInput( inPlug() ); attributes->filterPlug()->setInput( filterPlug() ); for( CompoundDataPlug::MemberPlugIterator it( attributes->attributesPlug() ); !it.done(); ++it ) { if( boost::ends_with( (*it)->getName().string(), "Visibility" ) && (*it)->getName() != "cameraVisibility" ) { (*it)->enabledPlug()->setValue( true ); (*it)->valuePlug<BoolPlug>()->setValue( false ); } } addChild( attributes ); Plug *internalCameraVisibilityPlug = attributes->attributesPlug()->getChild<Plug>( "cameraVisibility" ); PlugPtr cameraVisibilityPlug = internalCameraVisibilityPlug->createCounterpart( "cameraVisibility", Plug::In ); addChild( cameraVisibilityPlug ); internalCameraVisibilityPlug->setInput( cameraVisibilityPlug ); // Shader node. This loads the Arnold mesh_light shader. ArnoldShaderPtr shader = new ArnoldShader( "__shader" ); shader->loadShader( "mesh_light" ); addChild( shader ); PlugPtr parametersPlug = shader->parametersPlug()->createCounterpart( "parameters", Plug::In ); addChild( parametersPlug ); for( PlugIterator srcIt( parametersPlug.get() ), dstIt( shader->parametersPlug() ); !srcIt.done(); ++srcIt, ++dstIt ) { (*dstIt)->setInput( *srcIt ); // We don't need the parameters to be dynamic, because we create the // plugs in our constructor when calling `loadShader()`. (*srcIt)->setFlags( Plug::Dynamic, false ); } // ShaderAssignment node. This assigns the mesh_light shader // to the objects chosen by the filter. ShaderAssignmentPtr shaderAssignment = new ShaderAssignment( "__shaderAssignment" ); shaderAssignment->inPlug()->setInput( attributes->outPlug() ); shaderAssignment->filterPlug()->setInput( filterPlug() ); shaderAssignment->shaderPlug()->setInput( shader->outPlug() ); addChild( shaderAssignment ); // Set node. This adds the objects into the __lights set, // so they will be output correctly to the renderer. SetPtr set = new Set( "__set" ); set->inPlug()->setInput( shaderAssignment->outPlug() ); set->filterPlug()->setInput( filterPlug() ); set->namePlug()->setValue( "__lights" ); set->modePlug()->setValue( Set::Add ); addChild( set ); // Default lights Set node. BoolPlugPtr defaultLightPlug = new BoolPlug( "defaultLight", Plug::In, true ); addChild( defaultLightPlug ); SetPtr defaultLightsSet = new Set( "__defaultLightsSet" ); defaultLightsSet->inPlug()->setInput( set->outPlug() ); defaultLightsSet->filterPlug()->setInput( filterPlug() ); defaultLightsSet->enabledPlug()->setInput( defaultLightPlug.get() ); defaultLightsSet->namePlug()->setValue( "defaultLights" ); defaultLightsSet->modePlug()->setValue( Set::Add ); addChild( defaultLightsSet ); // Switch for enabling/disabling SwitchPtr enabledSwitch = new Switch( "__switch" ); enabledSwitch->setup( inPlug() ); enabledSwitch->inPlugs()->getChild<ScenePlug>( 0 )->setInput( inPlug() ); enabledSwitch->inPlugs()->getChild<ScenePlug>( 1 )->setInput( defaultLightsSet->outPlug() ); enabledSwitch->indexPlug()->setValue( 1 ); enabledSwitch->enabledPlug()->setInput( enabledPlug() ); addChild( enabledSwitch ); outPlug()->setInput( enabledSwitch->outPlug() ); // We don't need to serialise the connection because we make // it upon construction. /// \todo Can we just do this in the SceneProcessor base class? outPlug()->setFlags( Plug::Serialisable, false ); }
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--; } }
void Reference::load( const std::string &fileName ) { ScriptNode *script = scriptNode(); if( !script ) { throw IECore::Exception( "Reference::load called without ScriptNode" ); } // if we're doing a reload, then we want to maintain any values and // connections that our external plugs might have. but we also need to // get those existing plugs out of the way during the load, so that the // incoming plugs don't get renamed. std::map<std::string, Plug *> previousPlugs; for( PlugIterator it( this ); it != it.end(); ++it ) { Plug *plug = it->get(); if( isReferencePlug( plug ) ) { previousPlugs[plug->getName()] = plug; plug->setName( "__tmp__" + plug->getName().string() ); } } for( PlugIterator it( userPlug() ); it != it.end(); ++it ) { Plug *plug = it->get(); previousPlugs[plug->relativeName( this )] = plug; plug->setName( "__tmp__" + plug->getName().string() ); } // if we're doing a reload, then we also need to delete all our child // nodes to make way for the incoming nodes. int i = (int)(children().size()) - 1; while( i >= 0 ) { if( Node *node = getChild<Node>( i ) ) { removeChild( node ); } i--; } // load the reference. we use continueOnError=true to get everything possible // loaded, but if any errors do occur we throw an exception at the end of this // function. this means that the caller is still notified of errors via the // exception mechanism, but we leave ourselves in the best state possible for // the case where ScriptNode::load( continueOnError = true ) will ignore the // exception that we throw. const bool errors = script->executeFile( fileName, this, /* continueOnError = */ true ); fileNamePlug()->setValue( fileName ); // transfer connections and values from the old plugs onto the corresponding new ones. for( std::map<std::string, Plug *>::const_iterator it = previousPlugs.begin(), eIt = previousPlugs.end(); it != eIt; ++it ) { Plug *oldPlug = it->second; Plug *newPlug = descendant<Plug>( it->first ); if( newPlug ) { try { if( newPlug->direction() == Plug::In && oldPlug->direction() == Plug::In ) { if( Plug *oldInput = oldPlug->getInput<Plug>() ) { newPlug->setInput( oldInput ); } else { ValuePlug *oldValuePlug = runTimeCast<ValuePlug>( oldPlug ); ValuePlug *newValuePlug = runTimeCast<ValuePlug>( newPlug ); if( oldValuePlug && newValuePlug ) { newValuePlug->setFrom( oldValuePlug ); } } } else if( newPlug->direction() == Plug::Out && oldPlug->direction() == Plug::Out ) { for( Plug::OutputContainer::const_iterator oIt = oldPlug->outputs().begin(), oeIt = oldPlug->outputs().end(); oIt != oeIt; ) { Plug *outputPlug = *oIt; ++oIt; // increment now because the setInput() call invalidates our iterator. outputPlug->setInput( newPlug ); } } } catch( const std::exception &e ) { msg( Msg::Warning, boost::str( boost::format( "Loading \"%s\" onto \"%s\"" ) % fileName % getName().c_str() ), e.what() ); } } // remove the old plug now we're done with it. oldPlug->parent<GraphComponent>()->removeChild( oldPlug ); } // make the loaded plugs non-dynamic, because we don't want them // to be serialised in the script the reference is in - the whole // point is that they are referenced. for( RecursivePlugIterator it( this ); it != it.end(); ++it ) { if( isReferencePlug( it->get() ) ) { (*it)->setFlags( Plug::Dynamic, false ); } } if( errors ) { throw Exception( boost::str( boost::format( "Error loading reference \"%s\"" ) % fileName ) ); } }
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; }
void Box::unpromotePlug( Plug *promotedDescendantPlug ) { if( !plugIsPromoted( promotedDescendantPlug ) ) { if( promotedDescendantPlug ) { throw IECore::Exception( boost::str( boost::format( "Cannot unpromote plug \"%s\" as it has not been promoted." ) % promotedDescendantPlug->fullName() ) ); } else { throw IECore::Exception( "Cannot unpromote null plug" ); } } Plug *externalPlug = NULL; if( promotedDescendantPlug->direction() == Plug::In ) { externalPlug = promotedDescendantPlug->getInput<Plug>(); promotedDescendantPlug->setInput( NULL ); } else { for( Plug::OutputContainer::const_iterator it = promotedDescendantPlug->outputs().begin(), eIt = promotedDescendantPlug->outputs().end(); it != eIt; ++it ) { if( (*it)->node() == this ) { externalPlug = *it; break; } } assert( externalPlug ); // should be true because we checked plugIsPromoted() externalPlug->setInput( NULL ); } // remove the top level external plug , but only if // all the children are unused too in the case of a compound plug. bool remove = true; Plug *plugToRemove = externalPlug; while( plugToRemove->parent<Plug>() && plugToRemove->parent<Plug>() != userPlug() ) { plugToRemove = plugToRemove->parent<Plug>(); for( PlugIterator it( plugToRemove ); it != it.end(); ++it ) { if( ( (*it)->direction() == Plug::In && (*it)->outputs().size() ) || ( (*it)->direction() == Plug::Out && (*it)->getInput<Plug>() ) ) { remove = false; break; } } } if( remove ) { plugToRemove->parent<GraphComponent>()->removeChild( plugToRemove ); } }