Example #1
0
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 );
	}
}
Example #2
0
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;
}
Example #3
0
void ScriptingKeyframesBool::set_key (void)
{
	PROFILER(SCRIPTING);

	const std::vector<PlugBase*> &outgoing = _out.outgoing_connections();
	if (outgoing.size() > 0) {
		// get first connected plug
		Plug<DTboolean> *outplug = static_cast<Plug<DTboolean>*>(*(outgoing.begin()));
		
		// get the value of the first connected plug
		DTboolean val = outplug->value_without_compute();
				
		// clear any existing key
		clear_key();
		
		// add the keyframe
		keyframe k;
		k._time = _t;
		k._value = val;
		k._id = _id++;
		_keyframes.push_back(k);
		
		std::sort(_keyframes.begin(), _keyframes.end());
	}
}
Example #4
0
void Plug::removeOutputs()
{
    for( OutputContainer::iterator it = m_outputs.begin(); it!=m_outputs.end();  )
    {
        Plug *p = *it++;
        p->setInput( 0 );
    }
}
Example #5
0
Gaffer::Node *DotNodeGadget::upstreamNode()
{
	Plug *plug = dotNode()->inPlug<Plug>();
	while( plug && runTimeCast<Dot>( plug->node() ) )
	{
		plug = plug->getInput<Plug>();
	}
	return plug ? plug->node() : NULL;
}
Example #6
0
void BoxIO::setupPromotedPlug()
{
	Plug *toPromote = m_direction == Plug::In ? inPlugInternal() : outPlugInternal();
	if( toPromote && parent<Box>() )
	{
		Plug *promoted = PlugAlgo::promoteWithName( toPromote, namePlug()->getValue() );
		namePlug()->setValue( promoted->getName() );
	}
}
Example #7
0
std::vector<NoduleLayout::GadgetKey> NoduleLayout::layoutOrder()
{
	typedef pair<int, GadgetKey> SortItem;
	vector<SortItem> toSort;

	// Add any plugs which should be visible

	for( PlugIterator plugIt( m_parent.get() ); !plugIt.done(); ++plugIt )
	{
		Plug *plug = plugIt->get();
		if( boost::starts_with( plug->getName().string(), "__" ) )
		{
			continue;
		}
		if( !::visible( plug, m_section ) )
		{
			continue;
		}

		toSort.push_back( SortItem( index( plug, toSort.size() ), plug ) );
	}

	// Then any custom gadgets specified by the metadata

	vector<InternedString> metadata;
	Metadata::registeredValues( m_parent.get(), metadata );
	boost::regex customGadgetRegex( "noduleLayout:customGadget:(.+):gadgetType" );
	for( vector<InternedString>::const_iterator it = metadata.begin(), eIt = metadata.end(); it != eIt; ++it )
	{
		boost::cmatch match;
		if( !boost::regex_match( it->c_str(), match, customGadgetRegex ) )
		{
			continue;
		}
		const InternedString name = match[1].str();
		if( !::visible( m_parent.get(), name, m_section ) )
		{
			continue;
		}

		toSort.push_back( SortItem( index( m_parent.get(), name, toSort.size() ), name ) );
	}

	// Sort and return the result

	sort( toSort.begin(), toSort.end() );

	vector<GadgetKey> result;
	result.reserve( toSort.size() );
	for( vector<SortItem>::const_iterator it = toSort.begin(), eIt = toSort.end(); it != eIt; ++it )
	{
		result.push_back( it->second );
	}

	return result;
}
Example #8
0
void ArnoldShader::loadShader( const std::string &shaderName, bool keepExistingValues )
{
	IECoreArnold::UniverseBlock arnoldUniverse( /* writable = */ false );

	const AtNodeEntry *shader = AiNodeEntryLookUp( AtString( shaderName.c_str() ) );
	if( !shader )
	{
		throw Exception( str( format( "Shader \"%s\" not found" ) % shaderName ) );
	}

	Plug *parametersPlug = this->parametersPlug()->source<Plug>();

	if( !keepExistingValues )
	{
		parametersPlug->clearChildren();
		if( Plug *out = outPlug() )
		{
			removeChild( out );
		}
	}

	const bool isLightShader = AiNodeEntryGetType( shader ) == AI_NODE_LIGHT;
	namePlug()->setValue( AiNodeEntryGetName( shader ) );

	int aiOutputType = AI_TYPE_POINTER;
	string type = "ai:light";
	if( !isLightShader )
	{
		const CompoundData *metadata = ArnoldShader::metadata();
		const StringData *shaderTypeData = static_cast<const StringData*>( metadata->member<IECore::CompoundData>( "shader" )->member<IECore::Data>( "shaderType" ) );
		if( shaderTypeData )
		{
			type = "ai:" + shaderTypeData->readable();
		}
		else
		{
			type = "ai:surface";
		}

		if( type == "ai:surface" )
		{
			aiOutputType = AiNodeEntryGetOutputType( shader );
		}
	}

	if( !keepExistingValues && type == "ai:lightFilter" )
	{
		attributeSuffixPlug()->setValue( shaderName );
	}

	typePlug()->setValue( type );

	ParameterHandler::setupPlugs( shader, parametersPlug );
	ParameterHandler::setupPlug( "out", aiOutputType, this, Plug::Out );

}
Example #9
0
void Expression::removeChildren( ValuePlug *parentPlug, size_t startChildIndex )
{
	// Remove backwards, because children() is a vector and
	// it's therefore cheaper to remove from the end.
	for( int i = (int)(parentPlug->children().size() ) - 1; i >= (int)startChildIndex; --i )
	{
		Plug *toRemove = parentPlug->getChild<Plug>( i );
		toRemove->removeOutputs();
		parentPlug->removeChild( toRemove );
	}
}
Example #10
0
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--;
	}
}
Example #11
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() );
		}
	}

}
Example #12
0
void TaskNode::postTasks( const Context *context, Tasks &tasks ) const
{
	for( PlugIterator cIt( postTasksPlug() ); !cIt.done(); ++cIt )
	{
		Plug *source = (*cIt)->source();
		if( source != *cIt && source->direction() == Plug::Out )
		{
			if( TaskNodePtr n = runTimeCast<TaskNode>( source->node() ) )
			{
				tasks.push_back( Task( n, context ) );
			}
		}
	}
}
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 );
			}
		}
	}
}
Example #14
0
void TaskNode::preTasks( const Context *context, Tasks &tasks ) const
{
	for( PlugIterator cIt( preTasksPlug() ); !cIt.done(); ++cIt )
	{
		Plug *source = (*cIt)->source<Plug>();
		if( source != *cIt )
		{
			if( TaskNodePtr n = runTimeCast<TaskNode>( source->node() ) )
			{
				tasks.push_back( Task( n, context ) );
			}
		}
	}
}
Example #15
0
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 );
}
Example #16
0
void ExecutableNode::requirements( const Context *context, Tasks &requirements ) const
{
	for( PlugIterator cIt( requirementsPlug() ); cIt != cIt.end(); ++cIt )
	{
		Plug *p = (*cIt)->source<Plug>();
		if( p != *cIt )
		{
			if( ExecutableNode *n = runTimeCast<ExecutableNode>( p->node() ) )
			{
				/// \todo Can we not just reuse the context? Maybe we need to make
				/// the context in Task const?
				requirements.push_back( Task( n, new Context( *context ) ) );
			}
		}
	}
}
Example #17
0
		void emit()
		{
			// Because we hold a reference to the plugs via m_graph,
			// we may be the last owner. This means that when we clear
			// the graph below, those plugs may be destroyed, which can
			// trigger another dirty propagation as their child plugs are
			// removed etc.
			//
			// Additionally, emitting plugDirtiedSignal() can cause
			// ill-behaved code to trigger another dirty propagation
			// phase while we're emitting this one. This is explicitly
			// disallowed in the documentation for the Node class, but
			// unfortunately we can't control what the python interpreter
			// does - entering python via plugDirtiedSignal() can
			// trigger a garbage collection which might delete plugs
			// and trigger dirty propagation again as their children
			// and inputs are removed.
			//
			// We use the m_emitting flag to disable these unwanted
			// secondary propagations during emit(), since they're not
			// needed, and can cause crashes.

			ScopedAssignment<bool> scopedAssignment( m_emitting, true );

			std::vector<VertexDescriptor> sorted;
			try
			{
				topological_sort( m_graph, std::back_inserter( sorted ) );
			}
			catch( const std::exception &e )
			{
				IECore::msg( IECore::Msg::Error, "Plug dirty propagation", e.what() );
			}

			for( std::vector<VertexDescriptor>::const_iterator it = sorted.begin(), eIt = sorted.end(); it != eIt; ++it )
			{
				Plug *plug = m_graph[*it].get();
				plug->dirty();
				if( Node *node = plug->node() )
				{
					node->plugDirtiedSignal()( plug );
				}
			}

			m_graph.clear();
			m_plugs.clear();
		}
Example #18
0
void BoxIO::plugInputChanged( Plug *plug )
{
	// An input has changed either on this node or on
	// the parent box node. This gives us the opportunity
	// to discover our promoted plug and connect to its
	// signals.
	Plug *promoted = nullptr;
	if( m_direction == Plug::In && plug == inPlugInternal() )
	{
		promoted = promotedPlug();
	}
	else if( m_direction == Plug::Out && plug == promotedPlug() )
	{
		promoted = plug;
	}

	if( promoted )
	{
		m_promotedPlugNameChangedConnection = promoted->nameChangedSignal().connect(
			boost::bind( &BoxIO::promotedPlugNameChanged, this, ::_1 )
		);
		m_promotedPlugParentChangedConnection = promoted->parentChangedSignal().connect(
			boost::bind( &BoxIO::promotedPlugParentChanged, this, ::_1 )
		);
	}

	// Detect manual setups created by legacy scripts from before
	// we added the pass-through, and fix them to include a pass-through.

	if(
		m_direction == Plug::Out &&
		plug == outPlugInternal() &&
		plug->getInput() == inPlugInternal() &&
		!passThroughPlugInternal()
	)
	{
		setupPassThrough();
	}

	// If a connection has been made to our passThrough plug
	// for the first time, then we also want to create an enabled
	// plug for the Box and connect to it.
	if( plug == passThroughPlugInternal() && passThroughPlugInternal()->getInput() )
	{
		setupBoxEnabledPlug();
	}
}
Example #19
0
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;
}
Example #20
0
static boost::python::tuple outputs( Plug &p )
{
	const Plug::OutputContainer &o = p.outputs();
	boost::python::list l;
	for( Plug::OutputContainer::const_iterator it=o.begin(); it!=o.end(); it++ )
	{
		l.append( PlugPtr( *it ) );
	}
	return boost::python::tuple( l );
}
Example #21
0
void OSLShader::loadShader( const std::string &shaderName, bool keepExistingValues )
{
	const char *searchPath = getenv( "OSL_SHADER_PATHS" );

	OSLQuery query;
	if( !query.open( shaderName, searchPath ? searchPath : "" ) )
	{
		throw Exception( query.error() );
	}
	
	loadShaderParameters( query, parametersPlug(), keepExistingValues );
	
	if( query.shadertype() == "shader" )
	{
		CompoundPlug *existingOut = getChild<CompoundPlug>( "out" );
		if( !existingOut || existingOut->typeId() != CompoundPlug::staticTypeId() )
		{
			CompoundPlugPtr outPlug = new CompoundPlug( "out", Plug::Out, Plug::Default | Plug::Dynamic );
			setChild( "out", outPlug );
		}
		loadShaderParameters( query, getChild<CompoundPlug>( "out" ), keepExistingValues );		
	}
	else
	{
		Plug *existingOut = getChild<Plug>( "out" );
		if( !existingOut || existingOut->typeId() != Plug::staticTypeId() )
		{
			PlugPtr outPlug = new Plug( "out", Plug::Out, Plug::Default | Plug::Dynamic );
			setChild( "out", outPlug );
		}
	}
	
	namePlug()->setValue( shaderName );
	typePlug()->setValue( "osl:" + query.shadertype() );
	
	m_metadata = NULL;
}
Example #22
0
void PathFilter::plugDirtied( const Gaffer::Plug *plug )
{
	if( plug == pathsPlug() )
	{
		//\todo: share this logic with Switch::variesWithContext()
		Plug* sourcePlug = pathsPlug()->source();
		if( sourcePlug->direction() == Plug::Out && IECore::runTimeCast<const ComputeNode>( sourcePlug->node() ) )
		{
			// pathsPlug() is receiving data from a plug whose value is context varying, meaning
			// we need to use the intermediate pathMatcherPlug() in computeMatch() instead:

			m_pathMatcher = nullptr;
		}
		else
		{
			// pathsPlug() value is not context varying, meaning we can save on graph evaluations
			// by just precomputing it here and directly using it in computeMatch():

			ConstStringVectorDataPtr paths = pathsPlug()->getValue();
			m_pathMatcher = new PathMatcherData;
			m_pathMatcher->writable().init( paths->readable().begin(), paths->readable().end() );
		}
	}
}
Example #23
0
void Scene::removeEdge(PlugEdge* edge)
{
    Plug* fromPlug = edge->getStartPlug();
    Plug* toPlug = edge->getEndPlug();
    QPair<Plug*, Plug*> edgeKey(fromPlug, toPlug);
#ifdef QT_DEBUG
    Q_ASSERT(m_edges.contains(edgeKey));
#else
    if(!m_edges.contains(edgeKey)){
        return;
    }
#endif

    // unregister from the connected plugs
    fromPlug->removeEdge(edge);
    toPlug->removeEdge(edge);

    // remove the edge from the Scene's register
    m_edges.remove(edgeKey);

    // remove the edge from its group
    EdgeGroup* edgeGroup  = edge->getGroup();
    edgeGroup->removeEdge(edge);

    // if the group is now empty, we can only delete it if the other group in the pair is also empty
    EdgeGroupPair* edgeGroupPair = edgeGroup->getEdgeGroupPair();
    if(edgeGroupPair->isEmpty()){
        uint firstHash = edgeGroupPair->getFirstGroup()->getHash();
        uint secondHash = edgeGroupPair->getSecondGroup()->getHash();
        Q_ASSERT(m_edgeGroups.contains(firstHash));
        Q_ASSERT(m_edgeGroups.contains(secondHash));
        m_edgeGroups.remove(firstHash);
        m_edgeGroups.remove(secondHash);
        m_edgeGroupPairs.remove(edgeGroupPair);
        delete edgeGroupPair; // also deletes the EdgeGroups
        edgeGroupPair = nullptr;
    }

    // lastly, remove the QGraphicsItem from the scene, thereby taking possession of the last pointer to the edge
    removeItem(edge);

    // delete the edge from memory (automatically deletes all Qt-children as well)
    edge->deleteLater();

    // emit signals
    emit fromPlug->getNode()->outputDisconnected(fromPlug, toPlug);
    emit toPlug->getNode()->inputDisconnected(toPlug, fromPlug);
}
Example #24
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 );
}
Example #25
0
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() );
	}
}
Example #26
0
static NodePtr node( Plug &p )
{
	return p.node();
}
Example #27
0
void DependencyNode::propagateDirtiness( Plug *plugToDirty )
{
	// we're not able to signal anything if there's no node, so just early out
	Node *node = plugToDirty->ancestor<Node>();
	if( !node )
	{
		return;
	}
	
	// we don't emit dirtiness immediately for each plug as we traverse the
	// dependency graph for two reasons :
	//
	// - we don't want to emit dirtiness for the same plug more than once
	// - we don't want to emit dirtiness while the graph may still be being
	//   rewired by slots connected to plugSetSignal() or plugInputChangedSignal()
	//
	// instead we collect all the dirty plugs in a container as we traverse
	// the graph and only when the traversal is complete do we emit the plugDirtiedSignal().
	//
	// the container used is stored per-thread as although it's illegal to be
	// monkeying with a script from multiple threads, it's perfectly legal to
	// be monkeying with a different script in each thread.
	
	DirtyPlugsContainer &dirtyPlugs = g_dirtyPlugsContainers.local();
	
	// if the container is currently empty then we are at the start of a traversal,
	// and will emit plugDirtiedSignal() and empty the container before returning
	// from this function. if the container isn't empty then we are mid-traversal
	// and will just add to it.
	const bool emit = dirtyPlugs.empty();

	Plug *p = plugToDirty;
	while( p )
	{
		dirtyPlugs.insert( p );
		p = p->parent<Plug>();
	}	
	
	// we only propagate dirtiness along leaf level plugs, because
	// they are the only plugs which can be the target of the affects(),
	// and compute() methods.
	if( !plugToDirty->isInstanceOf( (IECore::TypeId)CompoundPlugTypeId ) )
	{
		DependencyNode *dependencyNode = IECore::runTimeCast<DependencyNode>( node );
		if( dependencyNode )
		{
			AffectedPlugsContainer affected;
			dependencyNode->affects( plugToDirty, affected );
			for( AffectedPlugsContainer::const_iterator it=affected.begin(); it!=affected.end(); it++ )
			{
				if( ( *it )->isInstanceOf( (IECore::TypeId)Gaffer::CompoundPlugTypeId ) )
				{
					// DependencyNode::affects() implementations are only allowed to place leaf plugs in the outputs,
					// so we helpfully report any mistakes.
					dirtyPlugs.clear();
					throw IECore::Exception( "Non-leaf plug " + (*it)->fullName() + " cannot be returned by affects()" );
				}
				// cast is ok - AffectedPlugsContainer only holds const pointers so that
				// affects() can be const to discourage implementations from having side effects.
				propagateDirtiness( const_cast<Plug *>( *it ) );
			}
		}
	
		for( Plug::OutputContainer::const_iterator it=plugToDirty->outputs().begin(), eIt=plugToDirty->outputs().end(); it!=eIt; ++it )
		{
			propagateDirtiness( *it );
		}		
	}
	
	if( emit )
	{
		for( size_t i = 0, e = dirtyPlugs.size(); i < e; ++i )
		{
			Plug *plug = dirtyPlugs.get<1>()[i];
			Node *node = plug->node();
			if( node )
			{
				node->plugDirtiedSignal()( plug );
			}
		}
		dirtyPlugs.clear();
	}
}
Example #28
0
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 ) );
	}
}
Example #29
0
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--;
	}
}
Example #30
0
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 );
			}
		}
	}

}