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::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 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 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; } } } }
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(); }
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 ) ); }
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 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; }