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 ); } }
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( direction == Plug::Out ) { throw IECore::Exception( "Output ArrayPlugs are currently unsupported." ); } 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 ); } } parentChangedSignal().connect( boost::bind( &ArrayPlug::parentChanged, this ) ); }
void Expression::updatePlug( ValuePlug *parentPlug, size_t childIndex, ValuePlug *plug ) { if( parentPlug->children().size() > childIndex ) { // See if we can reuse the existing plug Plug *existingChildPlug = parentPlug->getChild<Plug>( childIndex ); if( ( existingChildPlug->direction() == Plug::In && existingChildPlug->getInput<Plug>() == plug ) || ( existingChildPlug->direction() == Plug::Out && plug->getInput<Plug>() == existingChildPlug ) ) { return; } } // Existing plug not OK, so we need to create one. First we must remove all // plugs from childIndex onwards, so that when we add the new plug it gets // the right index. removeChildren( parentPlug, childIndex ); // Finally we can add the plug we need. PlugPtr childPlug = plug->createCounterpart( "p0", parentPlug->direction() ); childPlug->setFlags( Plug::Dynamic, true ); parentPlug->addChild( childPlug ); if( childPlug->direction() == Plug::In ) { childPlug->setInput( plug ); } else { plug->setInput( childPlug ); } }
void Expression::addPlug( ValuePlug *parentPlug, const std::string &plugPath ) { Node *p = parent<Node>(); if( !p ) { throw IECore::Exception( "No parent" ); } ValuePlug *plug = p->descendant<ValuePlug>( plugPath ); if( !plug ) { throw IECore::Exception( boost::str( boost::format( "Plug \"%s\" does not exist" ) % plugPath ) ); } PlugPtr childPlug = plug->createCounterpart( "p0", parentPlug->direction() ); childPlug->setFlags( Plug::Dynamic, true ); parentPlug->addChild( childPlug ); if( childPlug->direction() == Plug::In ) { childPlug->setInput( plug ); } else { plug->setInput( childPlug ); } }
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; } } } }
PlugPtr CompoundDataPlug::MemberPlug::createCounterpart( const std::string &name, Direction direction ) const { PlugPtr result = new MemberPlug( name, direction, getFlags() ); for( PlugIterator it( this ); it != it.end(); it++ ) { result->addChild( (*it)->createCounterpart( (*it)->getName(), direction ) ); } return result; }
PlugPtr ValuePlug::createCounterpart( const std::string &name, Direction direction ) const { PlugPtr result = new ValuePlug( name, direction, getFlags() ); for( PlugIterator it( this ); !it.done(); ++it ) { result->addChild( (*it)->createCounterpart( (*it)->getName(), direction ) ); } return result; }
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(); }
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 ); }
static void loadCoshaderParameter( Gaffer::CompoundPlug *parametersPlug, const std::string &name ) { Plug *existingPlug = parametersPlug->getChild<Plug>( name ); if( existingPlug && existingPlug->typeId() == Plug::staticTypeId() ) { return; } PlugPtr plug = new Plug( name, Plug::In, Plug::Default | Plug::Dynamic ); if( existingPlug && existingPlug->getInput<Plug>() ) { plug->setInput( existingPlug->getInput<Plug>() ); } parametersPlug->setChild( name, plug ); }
void Expression::updatePlugs( const std::string &dstPlugPath, std::vector<std::string> &srcPlugPaths ) { Node *p = parent<Node>(); // if the expression was invalid, remove our plugs if( !dstPlugPath.size() ) { Plug *in = getChild<Plug>( "in" ); if( in ) { removeChild( in ); } Plug *out = getChild<Plug>( "out" ); if( out ) { removeChild( out ); } return; } // otherwise try to create connections to the plugs the expression wants ValuePlug *dstPlug = p->descendant<ValuePlug>( dstPlugPath ); if( !dstPlug ) { throw IECore::Exception( boost::str( boost::format( "Destination plug \"%s\" does not exist" ) % dstPlugPath ) ); } CompoundPlugPtr inPlugs = new CompoundPlug( "in", Plug::In, Plug::Default | Plug::Dynamic ); setChild( "in", inPlugs ); for( std::vector<std::string>::const_iterator it = srcPlugPaths.begin(); it!=srcPlugPaths.end(); it++ ) { ValuePlug *srcPlug = p->descendant<ValuePlug>( *it ); if( !srcPlug ) { throw IECore::Exception( boost::str( boost::format( "Source plug \"%s\" does not exist" ) % *it ) ); } PlugPtr inPlug = srcPlug->createCounterpart( "plug", Plug::In ); inPlugs->addChild( inPlug ); inPlug->setInput( srcPlug ); } PlugPtr outPlug = dstPlug->createCounterpart( "out", Plug::Out ); setChild( "out", outPlug ); dstPlug->setInput( outPlug ); }
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 addError( PlugPtr plug, const std::string &error ) { PlugEntry &entry = m_errors[plug]; entry.error = error; if( !entry.parentChangedConnection.connected() ) { entry.parentChangedConnection = plug->parentChangedSignal().connect( boost::bind( &ErrorGadget::parentChanged, this, ::_1 ) ); } m_image->setVisible( true ); }
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 ); } }
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 ); 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 ) ); } } } }
ColorInspector( ImageView *view ) : m_view( view ), m_sampler( new ImageSampler ) { PlugPtr plug = new Plug( "colorInspector" ); view->addChild( plug ); plug->addChild( new V2iPlug( "pixel" ) ); plug->addChild( new Color4fPlug( "color" ) ); // We want to sample the image before the display transforms // are applied. We can't simply get this image from inPlug() // because derived classes may have called insertConverter(), // so we take it from the input to the display transform chain. ImagePlug *image = view->getPreprocessor<Node>()->getChild<Clamp>( "__clamp" )->inPlug(); m_sampler->imagePlug()->setInput( image ); plug->getChild<Color4fPlug>( "color" )->setInput( m_sampler->colorPlug() ); m_view->viewportGadget()->mouseMoveSignal().connect( boost::bind( &ColorInspector::mouseMove, this, ::_2 ) ); m_view->viewportGadget()->getPrimaryChild()->buttonPressSignal().connect( boost::bind( &ColorInspector::buttonPress, this, ::_2 ) ); m_view->viewportGadget()->getPrimaryChild()->dragBeginSignal().connect( boost::bind( &ColorInspector::dragBegin, this, ::_2 ) ); m_view->viewportGadget()->getPrimaryChild()->dragEndSignal().connect( boost::bind( &ColorInspector::dragEnd, this, ::_2 ) ); }
void addError( PlugPtr plug, const std::string &error ) { PlugEntry &entry = m_errors[plug]; if( entry.error.empty() || !boost::ends_with( error, "Previous attempt to get item failed." ) ) { // Update the error message. Unfortunately the IECore::LRUCache at the // heart of Gaffer's caching does not remember the details of exceptions that // occurred when the cache entry is in error - instead it throws a different // exception saying "Previous attempt to get item failed.". We ignore these less // helpful messages in favour of a previous messages if one exists. /// \todo Improve LRUCache behaviour and remove this workaround. entry.error = error; } if( !entry.parentChangedConnection.connected() ) { entry.parentChangedConnection = plug->parentChangedSignal().connect( boost::bind( &ErrorGadget::parentChanged, this, ::_1 ) ); } m_image->setVisible( true ); }
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 ); } }
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(); } }
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 ); } } }
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 OSLShader::loadShader( const std::string &shaderName, bool keepExistingValues ) { Plug *existingOut = outPlug(); if( shaderName.empty() ) { parametersPlug()->clearChildren(); namePlug()->setValue( "" ); typePlug()->setValue( "" ); if( existingOut ) { existingOut->clearChildren(); } return; } const char *searchPath = getenv( "OSL_SHADER_PATHS" ); OSLQuery query; if( !query.open( shaderName, searchPath ? searchPath : "" ) ) { throw Exception( query.geterror() ); } const bool outPlugHadChildren = existingOut ? existingOut->children().size() : false; if( !keepExistingValues ) { // If we're not preserving existing values then remove all existing // parameter plugs - the various plug creators above know that if a // plug exists then they should preserve its values. parametersPlug()->clearChildren(); if( existingOut ) { existingOut->clearChildren(); } } m_metadata = NULL; namePlug()->setValue( shaderName ); typePlug()->setValue( std::string( "osl:" ) + query.shadertype().c_str() ); const IECore::CompoundData *metadata = OSLShader::metadata(); const IECore::CompoundData *parameterMetadata = NULL; if( metadata ) { parameterMetadata = metadata->member<IECore::CompoundData>( "parameter" ); } loadShaderParameters( query, parametersPlug(), parameterMetadata ); if( !existingOut || existingOut->typeId() != Plug::staticTypeId() ) { PlugPtr outPlug = new Plug( "out", Plug::Out, Plug::Default | Plug::Dynamic ); if( existingOut ) { // We had an out plug but it was the wrong type (we used // to use a CompoundPlug before that was deprecated). Move // over any existing child plugs onto our replacement. for( PlugIterator it( existingOut ); !it.done(); ++it ) { outPlug->addChild( *it ); } } setChild( "out", outPlug ); } if( query.shadertype() == "shader" ) { loadShaderParameters( query, outPlug(), parameterMetadata ); } else { outPlug()->clearChildren(); } if( static_cast<bool>( outPlug()->children().size() ) != outPlugHadChildren ) { // OSLShaderUI registers a dynamic metadata entry which depends on whether or // not the plug has children, so we must notify the world that the value will // have changed. Metadata::plugValueChangedSignal()( staticTypeId(), "out", "nodule:type", outPlug() ); } }
void Plug::parentChanging( Gaffer::GraphComponent *newParent ) { if( getFlags( Dynamic ) ) { // When a dynamic plug is removed from a node, we // need to propagate dirtiness based on that. We // must call DependencyNode::affects() now, while the // plug is still a child of the node, but we push // scope so that the emission of plugDirtiedSignal() // is deferred until parentChanged() when the operation // is complete. It is essential that exceptions don't // prevent us getting to parentChanged() where we pop // scope, so propateDirtiness() takes care of handling // exceptions thrown by DependencyNode::affects(). pushDirtyPropagationScope(); if( node() ) { propagateDirtinessForParentChange( this ); } } // This method manages the connections between plugs when // additional child plugs are added or removed. We only // want to react to these changes when they are first made - // after this our own actions will have been recorded in the // undo buffer anyway and will be undone/redone automatically. // So here we early out if we're in such an Undo/Redo situation. ScriptNode *scriptNode = ancestor<ScriptNode>(); scriptNode = scriptNode ? scriptNode : ( newParent ? newParent->ancestor<ScriptNode>() : NULL ); if( scriptNode && ( scriptNode->currentActionStage() == Action::Undo || scriptNode->currentActionStage() == Action::Redo ) ) { return; } // Now we can take the actions we need to based on the new parent // we're getting. if( !newParent ) { // We're losing our parent - remove all our connections first. // this must be done here (rather than in a parentChangedSignal() slot) // because we need a current parent for the operation to be undoable. setInput( 0 ); // Deal with outputs whose parent is an output of our parent. // For these we actually remove the destination plug itself, // so that the parent plugs may remain connected. if( Plug *oldParent = parent<Plug>() ) { for( OutputContainer::iterator it = m_outputs.begin(); it!=m_outputs.end(); ) { Plug *output = *it++; Plug *outputParent = output->parent<Plug>(); if( outputParent && outputParent->getInput<Plug>() == oldParent ) { // We're removing the child precisely so that the parent connection // remains valid, so we can block its updateInputFromChildInputs() call. assert( outputParent->m_skipNextUpdateInputFromChildInputs == false ); ScopedAssignment<bool> blocker( outputParent->m_skipNextUpdateInputFromChildInputs, true ); outputParent->removeChild( output ); } } } // Remove any remaining output connections. removeOutputs(); } else if( Plug *newParentPlug = IECore::runTimeCast<Plug>( newParent ) ) { // we're getting a new parent - update its input connection from // all the children including the pending one. newParentPlug->updateInputFromChildInputs( this ); // and add a new child plug to any of its outputs to maintain // the output connections. const OutputContainer &outputs = newParentPlug->outputs(); for( OutputContainer::const_iterator it = outputs.begin(), eIt = outputs.end(); it != eIt; ++it ) { Plug *output = *it; if( output->acceptsChild( this ) ) { PlugPtr outputChildPlug = createCounterpart( getName(), direction() ); { // We're adding the child so that the parent connection remains valid, // but the parent connection wouldn't be considered valid until the // child has both been added and had its input connected. We therefore // block the call to updateInputFromChildInputs() to keep the parent // connection intact. assert( output->m_skipNextUpdateInputFromChildInputs == false ); ScopedAssignment<bool> blocker( output->m_skipNextUpdateInputFromChildInputs, true ); output->addChild( outputChildPlug ); } outputChildPlug->setInput( this, /* setChildInputs = */ true, /* updateParentInput = */ 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(); }
ImageView::ImageView( const std::string &name ) : View( name, new GafferImage::ImagePlug() ), m_imageGadget( new ImageGadget() ), m_framed( false ) { // build the preprocessor we use for applying colour // transforms, and the stats node we use for displaying stats. NodePtr preprocessor = new Node; ImagePlugPtr preprocessorInput = new ImagePlug( "in" ); preprocessor->addChild( preprocessorInput ); ClampPtr clampNode = new Clamp(); preprocessor->setChild( "__clamp", clampNode ); clampNode->inPlug()->setInput( preprocessorInput ); clampNode->enabledPlug()->setValue( false ); clampNode->minClampToEnabledPlug()->setValue( true ); clampNode->maxClampToEnabledPlug()->setValue( true ); clampNode->minClampToPlug()->setValue( Color4f( 1.0f, 1.0f, 1.0f, 0.0f ) ); clampNode->maxClampToPlug()->setValue( Color4f( 0.0f, 0.0f, 0.0f, 1.0f ) ); BoolPlugPtr clippingPlug = new BoolPlug( "clipping" ); clippingPlug->setFlags( Plug::AcceptsInputs, false ); addChild( clippingPlug ); GradePtr gradeNode = new Grade; preprocessor->setChild( "__grade", gradeNode ); gradeNode->inPlug()->setInput( clampNode->outPlug() ); FloatPlugPtr exposurePlug = new FloatPlug( "exposure" ); exposurePlug->setFlags( Plug::AcceptsInputs, false ); addChild( exposurePlug ); // dealt with in plugSet() PlugPtr gammaPlug = gradeNode->gammaPlug()->getChild( 0 )->createCounterpart( "gamma", Plug::In ); gammaPlug->setFlags( Plug::AcceptsInputs, false ); addChild( gammaPlug ); addChild( new StringPlug( "displayTransform", Plug::In, "Default", Plug::Default & ~Plug::AcceptsInputs ) ); ImagePlugPtr preprocessorOutput = new ImagePlug( "out", Plug::Out ); preprocessor->addChild( preprocessorOutput ); preprocessorOutput->setInput( gradeNode->outPlug() ); // tell the base class about all the preprocessing we want to do setPreprocessor( preprocessor ); // connect up to some signals plugSetSignal().connect( boost::bind( &ImageView::plugSet, this, ::_1 ) ); viewportGadget()->keyPressSignal().connect( boost::bind( &ImageView::keyPress, this, ::_2 ) ); viewportGadget()->preRenderSignal().connect( boost::bind( &ImageView::preRender, this ) ); // get our display transform right insertDisplayTransform(); // Now we can connect up our ImageGadget, which will do the // hard work of actually displaying the image. m_imageGadget->setImage( preprocessedInPlug<ImagePlug>() ); m_imageGadget->setContext( getContext() ); viewportGadget()->setPrimaryChild( m_imageGadget ); m_colorInspector = shared_ptr<ColorInspector>( new ColorInspector( this ) ); }
void ArnoldShader::loadShader( const std::string &shaderName ) { IECoreArnold::UniverseBlock arnoldUniverse; const AtNodeEntry *shader = AiNodeEntryLookUp( shaderName.c_str() ); if( !shader ) { throw Exception( str( format( "Shader \"%s\" not found" ) % shaderName ) ); } namePlug()->setValue( AiNodeEntryGetName( shader ) ); typePlug()->setValue( "ai:surface" ); ParameterHandler::setupPlugs( shader, parametersPlug() ); PlugPtr outPlug = 0; const int outputType = AiNodeEntryGetOutputType( shader ); switch( outputType ) { case AI_TYPE_RGB : outPlug = new Color3fPlug( "out", Plug::Out ); break; case AI_TYPE_RGBA : outPlug = new Color4fPlug( "out", Plug::Out ); break; case AI_TYPE_FLOAT : outPlug = new FloatPlug( "out", Plug::Out ); break; case AI_TYPE_INT : outPlug = new IntPlug( "out", Plug::Out ); break; } if( outPlug ) { outPlug->setFlags( Plug::Dynamic, true ); addChild( outPlug ); } else { if( outputType != AI_TYPE_NONE ) { msg( Msg::Warning, "ArnoldShader::loadShader", format( "Unsupported output parameter of type \"%s\"" ) % AiParamGetTypeName( AiNodeEntryGetOutputType( shader ) ) ); } } }
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; }