Plug *Box::promotePlug( Plug *descendantPlug ) { validatePromotability( descendantPlug, /* throwExceptions = */ true ); PlugPtr externalPlug = descendantPlug->createCounterpart( promotedCounterpartName( descendantPlug ), descendantPlug->direction() ); externalPlug->setFlags( Plug::Dynamic, true ); // Flags are not automatically propagated to the children of compound plugs, // so we need to do that ourselves. We don't want to propagate them to the // children of plug types which create the children themselves during // construction though, hence the typeId checks for the base classes // which add no children during construction. I'm not sure this approach is // necessarily the best - the alternative would be to set everything dynamic // unconditionally and then implement Serialiser::childNeedsConstruction() // for types like CompoundNumericPlug that create children in their constructors. const Gaffer::TypeId compoundTypes[] = { PlugTypeId, ValuePlugTypeId, CompoundPlugTypeId, ArrayPlugTypeId }; const Gaffer::TypeId *compoundTypesEnd = compoundTypes + 4; if( find( compoundTypes, compoundTypesEnd, (Gaffer::TypeId)externalPlug->typeId() ) != compoundTypesEnd ) { for( RecursivePlugIterator it( externalPlug.get() ); it != it.end(); ++it ) { (*it)->setFlags( Plug::Dynamic, true ); if( find( compoundTypes, compoundTypesEnd, (Gaffer::TypeId)(*it)->typeId() ) != compoundTypesEnd ) { it.prune(); } } } if( externalPlug->direction() == Plug::In ) { if( ValuePlug *externalValuePlug = IECore::runTimeCast<ValuePlug>( externalPlug.get() ) ) { externalValuePlug->setFrom( static_cast<ValuePlug *>( descendantPlug ) ); } } // Copy over the metadata for nodule position, so the nodule appears in the expected spot. // This must be done before parenting the new plug, as the nodule is created from childAddedSignal(). copyMetadata( descendantPlug, externalPlug.get() ); addChild( externalPlug ); if( externalPlug->direction() == Plug::In ) { descendantPlug->setInput( externalPlug ); } else { externalPlug->setInput( descendantPlug ); } return externalPlug.get(); }
void Plug::setInput( PlugPtr input ) { if( input.get()==m_input ) { return; } if( input && !acceptsInput( input ) ) { std::string what = boost::str( boost::format( "Plug \"%s\" rejects input \"%s\"." ) % fullName() % input->fullName() ); throw IECore::Exception( what ); } if( refCount() ) { // someone is referring to us, so we're definitely fully constructed and we may have a ScriptNode // above us, so we should do things in a way compatible with the undo system. Action::enact( this, boost::bind( &Plug::setInputInternal, PlugPtr( this ), input, true ), boost::bind( &Plug::setInputInternal, PlugPtr( this ), PlugPtr( m_input ), true ) ); } else { // noone is referring to us. we're probably still constructing, and undo is impossible anyway (we // have no ScriptNode ancestor), so we can't make a smart pointer // to ourselves (it will result in double destruction). so we just set the input directly. setInputInternal( input, false ); } }
void ArrayPlug::inputChanged( Gaffer::Plug *plug ) { if( plug->parent<ArrayPlug>() != this ) { return; } if( getInput() ) { // When we ourselves have an input, we don't do any automatic addition or // removal of children, because the Plug base class itself manages // children to maintain the connection. return; } if( const ScriptNode *script = ancestor<ScriptNode>() ) { if( script->currentActionStage() == Action::Undo || script->currentActionStage() == Action::Redo ) { // If we're currently in an undo or redo, we don't // need to do anything, because our previous actions // will be in the undo queue and will be being replayed // for us automatically. return; } } if( plug->getInput() ) { // Connection made. If it's the last plug // then we need to add one more. if( plug == children().back() && children().size() < m_maxSize ) { PlugPtr p = getChild<Plug>( 0 )->createCounterpart( getChild<Plug>( 0 )->getName(), Plug::In ); p->setFlags( Gaffer::Plug::Dynamic, true ); addChild( p ); MetadataAlgo::copyColors( getChild<Plug>( 0 ) , p.get() , /* overwrite = */ false ); } } else { // Connection broken. We need to remove any // unneeded unconnected plugs so that we have // only one unconnected plug at the end. for( size_t i = children().size() - 1; i > m_minSize - 1; --i ) { if( !getChild<Plug>( i )->getInput() && !getChild<Plug>( i - 1 )->getInput() ) { removeChild( getChild<Plug>( i ) ); } else { break; } } } }
ExecutableNode::ExecutableNode( const std::string &name ) : Node( name ) { storeIndexOfNextChild( g_firstPlugIndex ); addChild( new ArrayPlug( "requirements", Plug::In, new RequirementPlug( "requirement0" ) ) ); addChild( new RequirementPlug( "requirement", Plug::Out ) ); PlugPtr dispatcherPlug = new Plug( "dispatcher", Plug::In ); addChild( dispatcherPlug ); Dispatcher::setupPlugs( dispatcherPlug.get() ); }
TaskNode::TaskNode( const std::string &name ) : DependencyNode( name ) { storeIndexOfNextChild( g_firstPlugIndex ); addChild( new ArrayPlug( "preTasks", Plug::In, new TaskPlug( "preTask0" ) ) ); addChild( new ArrayPlug( "postTasks", Plug::In, new TaskPlug( "postTask0" ) ) ); addChild( new TaskPlug( "task", Plug::Out ) ); PlugPtr dispatcherPlug = new Plug( "dispatcher", Plug::In ); addChild( dispatcherPlug ); Dispatcher::setupPlugs( dispatcherPlug.get() ); }
void CompoundPlug::setInput( PlugPtr input ) { if( input.get() == getInput<Plug>() ) { return; } // unfortunately we have to duplicate the check in Plug::setInput() // ourselves as we delay calling Plug::setInput() until we've connected // the children, but need to do the check first. /// \todo I think there's a case for not having CompoundPlug at all, /// and having Plug have all its functionality. if( input && !acceptsInput( input ) ) { std::string what = boost::str( boost::format( "Plug \"%s\" rejects input \"%s\"." ) % fullName() % input->fullName() ); throw IECore::Exception( what ); } { // we use the plugInputChangedConnection to trigger calls to updateInputFromChildInputs() // when child inputs are changed by code elsewhere. it would be counterproductive for // us to call updateInputFromChildInputs() while we ourselves are changing those inputs, // so we temporarily block the connection. BlockedConnection block( m_plugInputChangedConnection ); if( !input ) { for( ChildContainer::const_iterator it = children().begin(); it!=children().end(); it++ ) { IECore::staticPointerCast<Plug>( *it )->setInput( 0 ); } } else { CompoundPlugPtr p = IECore::staticPointerCast<CompoundPlug>( input ); ChildContainer::const_iterator it1, it2; for( it1 = children().begin(), it2 = p->children().begin(); it1!=children().end(); it1++, it2++ ) { IECore::staticPointerCast<Plug>( *it1 )->setInput( IECore::staticPointerCast<Plug>( *it2 ) ); } } } // we connect ourselves last, so that all our child plugs are correctly connected // before we signal our own connection change. ValuePlug::setInput( input ); }
ArrayPlug::ArrayPlug( const std::string &name, Direction direction, PlugPtr element, size_t minSize, size_t maxSize, unsigned flags ) : Plug( name, direction, flags ), m_minSize( std::max( minSize, size_t( 1 ) ) ), m_maxSize( std::max( maxSize, m_minSize ) ) { if( element ) { // If we're dynamic ourselves, then serialisations will include a constructor // for us, but it will have element==None. In this case we make sure the first // element is dynamic, so that it too will have a constructor written out. But // if we're not dynamic, we expect to be passed the element again upon reconstruction, // so we don't need a constructor to be serialised for the element, and therefore // we must set it to be non-dynamic. element->setFlags( Gaffer::Plug::Dynamic, getFlags( Gaffer::Plug::Dynamic ) ); addChild( element ); for( size_t i = 1; i < m_minSize; ++i ) { PlugPtr p = element->createCounterpart( element->getName(), Plug::In ); addChild( p ); MetadataAlgo::copyColors( element.get() , p.get() , /* overwrite = */ false ); } } parentChangedSignal().connect( boost::bind( &ArrayPlug::parentChanged, this ) ); }
static Plug *loadClosureParameter( const OSLQuery::Parameter *parameter, Gaffer::CompoundPlug *parent ) { const string name = plugName( parameter ); Plug *existingPlug = parent->getChild<Plug>( name ); if( existingPlug && existingPlug->typeId() == Plug::staticTypeId() ) { return existingPlug; } PlugPtr plug = new Plug( name, parent->direction(), Plug::Default | Plug::Dynamic ); transferConnectionOrValue( existingPlug, plug.get() ); parent->setChild( name, plug ); return plug; }
void Plug::setInputInternal( PlugPtr input, bool emit ) { if( m_input ) { m_input->m_outputs.remove( this ); } m_input = input.get(); if( m_input ) { m_input->m_outputs.push_back( this ); } if( emit ) { // We must emit inputChanged prior to propagating // dirtiness, because inputChanged slots may be // used to rewire the graph, and we want to emit // plugDirtied only after all the rewiring is done. emitInputChanged(); propagateDirtiness( this ); } }
static void loadCoshaderArrayParameter( Gaffer::CompoundPlug *parametersPlug, const std::string &name, const StringVectorData *defaultValue ) { const size_t minSize = std::max( defaultValue->readable().size(), (size_t)1 ); const size_t maxSize = defaultValue->readable().size() ? defaultValue->readable().size() : Imath::limits<size_t>::max(); PlugPtr existingPlug = parametersPlug->getChild<Plug>( name ); ArrayPlug *existingArrayPlug = runTimeCast<ArrayPlug>( existingPlug.get() ); if( existingArrayPlug && existingArrayPlug->minSize() == minSize && existingArrayPlug->maxSize() == maxSize ) { return; } std::string elementName = name; if( isdigit( *elementName.rbegin() ) ) { elementName += "_0"; } else { elementName += "0"; } ArrayPlugPtr plug = new ArrayPlug( name, Plug::In, new Plug( elementName ), minSize, maxSize, Plug::Default | Plug::Dynamic ); parametersPlug->setChild( name, plug ); if( existingPlug ) { for( size_t i = 0, e = std::min( existingPlug->children().size(), maxSize ); i < e; ++i ) { if( i < plug->children().size() ) { plug->getChild<Plug>( i )->setInput( existingPlug->getChild<Plug>( i )->getInput<Plug>() ); } else { plug->addChild( existingPlug->getChild<Plug>( i ) ); } } } }
void ValuePlug::setInput( PlugPtr input ) { if( input.get() == getInput<Plug>() ) { return; } // set value back to what it was before // we received a connection. we do that // before calling Plug::setInput, so that // we've got our new state set correctly before // the dirty signal is emitted. we don't emit // in the setValueInternal call, because we don't // want to double up on the signals that the Plug // is emitting for us in Plug::setInput(). if( !input ) { setValueInternal( m_staticValue, false ); } Plug::setInput( input ); }
void Plug::setInputInternal( PlugPtr input, bool emit ) { if( m_input ) { m_input->m_outputs.remove( this ); } m_input = input.get(); if( m_input ) { m_input->m_outputs.push_back( this ); } if( emit ) { Node *n = node(); if( n ) { n->plugInputChangedSignal()( this ); } emitDirtiness(); propagateDirtiness(); } }
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 ); }
Gaffer::Plug *ParameterHandler::setupPlug( const AtParamEntry *parameter, Gaffer::GraphComponent *plugParent, Gaffer::Plug::Direction direction ) { std::string name = AiParamGetName( parameter ); PlugPtr plug = 0; switch( AiParamGetType( parameter ) ) { case AI_TYPE_FLOAT : plug = new FloatPlug( name, direction, AiParamGetDefault( parameter )->FLT ); break; case AI_TYPE_INT : plug = new IntPlug( name, direction, AiParamGetDefault( parameter )->INT ); break; case AI_TYPE_BOOLEAN : plug = new BoolPlug( name, direction, AiParamGetDefault( parameter )->BOOL ); break; case AI_TYPE_RGB : plug = new Color3fPlug( name, direction, Color3f( AiParamGetDefault( parameter )->RGB.r, AiParamGetDefault( parameter )->RGB.g, AiParamGetDefault( parameter )->RGB.b ) ); break; case AI_TYPE_RGBA : plug = new Color4fPlug( name, direction, Color4f( AiParamGetDefault( parameter )->RGBA.r, AiParamGetDefault( parameter )->RGBA.g, AiParamGetDefault( parameter )->RGBA.b, AiParamGetDefault( parameter )->RGBA.a ) ); break; case AI_TYPE_POINT2 : plug = new V2fPlug( name, direction, V2f( AiParamGetDefault( parameter )->PNT2.x, AiParamGetDefault( parameter )->PNT2.y ) ); break; case AI_TYPE_POINT : plug = new V3fPlug( name, direction, V3f( AiParamGetDefault( parameter )->PNT.x, AiParamGetDefault( parameter )->PNT.y, AiParamGetDefault( parameter )->PNT.z ) ); break; case AI_TYPE_VECTOR : plug = new V3fPlug( name, direction, V3f( AiParamGetDefault( parameter )->VEC.x, AiParamGetDefault( parameter )->VEC.y, AiParamGetDefault( parameter )->VEC.z ) ); break; case AI_TYPE_ENUM : { AtEnum e = AiParamGetEnum( parameter ); plug = new StringPlug( name, direction, AiEnumGetString( e, AiParamGetDefault( parameter )->INT ) ); } break; case AI_TYPE_STRING : { plug = new StringPlug( name, direction, AiParamGetDefault( parameter )->STR ); } } if( plug ) { plug->setFlags( Plug::Dynamic, true ); plugParent->addChild( plug ); } else { msg( Msg::Warning, "GafferArnold::ParameterHandler::setupPlug", format( "Unsupported parameter \"%s\" of type \"%s\"" ) % AiParamGetName( parameter ) % AiParamGetTypeName( AiParamGetType( parameter ) ) ); } return plug.get(); }
void Plug::setInput( PlugPtr input, bool setChildInputs, bool updateParentInput ) { if( input.get()==m_input ) { return; } if( input && !acceptsInput( input.get() ) ) { std::string what = boost::str( boost::format( "Plug \"%s\" rejects input \"%s\"." ) % fullName() % input->fullName() ); throw IECore::Exception( what ); } // Connect our children first. // We use a dirty propagation scope to defer dirty signalling // until all connections have been made, when we're in our final // state. DirtyPropagationScope dirtyPropagationScope; if( setChildInputs ) { if( !input ) { for( PlugIterator it( this ); !it.done(); ++it ) { (*it)->setInput( NULL, /* setChildInputs = */ true, /* updateParentInput = */ false ); } } else { for( PlugIterator it1( this ), it2( input.get() ); !it1.done(); ++it1, ++it2 ) { (*it1)->setInput( *it2, /* setChildInputs = */ true, /* updateParentInput = */ false ); } } } // then connect ourselves if( refCount() ) { // someone is referring to us, so we're definitely fully constructed and we may have a ScriptNode // above us, so we should do things in a way compatible with the undo system. Action::enact( this, boost::bind( &Plug::setInputInternal, PlugPtr( this ), input, true ), boost::bind( &Plug::setInputInternal, PlugPtr( this ), PlugPtr( m_input ), true ) ); } else { // noone is referring to us. we're probably still constructing, and undo is impossible anyway (we // have no ScriptNode ancestor), so we can't make a smart pointer // to ourselves (it will result in double destruction). so we just set the input directly. setInputInternal( input, false ); } // finally, adjust our parent's connection to take account of // the changes to its child. if( updateParentInput ) { if( Plug *parentPlug = parent<Plug>() ) { parentPlug->updateInputFromChildInputs( this ); } } }
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; }