void IECoreArnold::RendererImplementation::procedural( IECore::Renderer::ProceduralPtr proc )
{
	Box3f bound = proc->bound();
	if( bound.isEmpty() )
	{
		return;
	}

	AtNode *procedural = AiNode( "procedural" );

	if( ExternalProcedural *externalProc = dynamic_cast<ExternalProcedural *>( proc.get() ) )
	{
		AiNodeSetStr( procedural, "dso", externalProc->fileName().c_str() );
		ParameterAlgo::setParameters( procedural, externalProc->parameters() );
		applyTransformToNode( procedural );
	}
	else
	{

		// we have to transform the bound, as we're not applying the current transform to the
		// procedural node, but instead applying absolute transforms to the shapes the procedural
		// generates.
		if( bound != Procedural::noBound )
		{
			Box3f transformedBound;
			for( size_t i = 0, e = m_transformStack.numSamples(); i < e; ++i )
			{
				transformedBound.extendBy( transform( bound, m_transformStack.sample( i ) ) );
			}
			bound = transformedBound;
		}

		AiNodeSetPtr( procedural, "funcptr", (void *)procLoader );

		ProceduralData *data = new ProceduralData;
		data->procedural = proc;
		data->renderer = new IECoreArnold::Renderer( new RendererImplementation( *this ) );

		AiNodeSetPtr( procedural, "userptr", data );
	}

	if( bound != Procedural::noBound )
	{
		AiNodeSetPnt( procedural, "min", bound.min.x, bound.min.y, bound.min.z );
		AiNodeSetPnt( procedural, "max", bound.max.x, bound.max.y, bound.max.z );
	}
	else
	{
		// No bound available - expand procedural immediately.
		AiNodeSetBool( procedural, "load_at_init", true );
	}

	// we call addNode() rather than addShape() as we don't want to apply transforms and
	// shaders and attributes to procedurals. if we do, they override the things we set
	// on the nodes generated by the procedurals, which is frankly useless.
	addNode( procedural );
}
void IECoreArnold::RendererImplementation::procedural( IECore::Renderer::ProceduralPtr proc )
{
	Box3f bound = proc->bound();
	if( bound.isEmpty() )
	{
		return;
	}

	AtNode *node = NULL;
	std::string nodeType = "procedural";

	if( const ExternalProcedural *externalProc = dynamic_cast<ExternalProcedural *>( proc.get() ) )
	{
		// Allow a parameter "ai:nodeType" == "volume" to create a volume shape rather
		// than a procedural shape. Volume shapes provide "dso", "min" and "max" parameters
		// just as procedural shapes do, so the mapping is a fairly natural one.
		CompoundDataMap::const_iterator nodeTypeIt = externalProc->parameters().find( "ai:nodeType" );
		if( nodeTypeIt != externalProc->parameters().end() && nodeTypeIt->second->isInstanceOf( StringData::staticTypeId() ) )
		{
			nodeType = static_cast<const StringData *>( nodeTypeIt->second.get() )->readable();
		}
		node = AiNode( nodeType.c_str() );

		AiNodeSetStr( node, "dso", externalProc->fileName().c_str() );
		ParameterAlgo::setParameters( node, externalProc->parameters() );
		applyTransformToNode( node );
	}
	else
	{
		node = AiNode( nodeType.c_str() );

		// we have to transform the bound, as we're not applying the current transform to the
		// procedural node, but instead applying absolute transforms to the shapes the procedural
		// generates.
		if( bound != Procedural::noBound )
		{
			Box3f transformedBound;
			for( size_t i = 0, e = m_transformStack.numSamples(); i < e; ++i )
			{
				transformedBound.extendBy( transform( bound, m_transformStack.sample( i ) ) );
			}
			bound = transformedBound;
		}

		AiNodeSetPtr( node, "funcptr", (void *)procLoader );

		ProceduralData *data = new ProceduralData;
		data->procedural = proc;
		data->renderer = new IECoreArnold::Renderer( new RendererImplementation( *this ) );

		AiNodeSetPtr( node, "userptr", data );
	}

	if( bound != Procedural::noBound )
	{
		AiNodeSetPnt( node, "min", bound.min.x, bound.min.y, bound.min.z );
		AiNodeSetPnt( node, "max", bound.max.x, bound.max.y, bound.max.z );
	}
	else
	{
		// No bound available - expand procedural immediately.
		AiNodeSetBool( node, "load_at_init", true );
	}

	if( nodeType == "procedural" )
	{
		// We call addNode() rather than addShape() as we don't want to apply transforms and
		// shaders and attributes to procedurals. If we do, they override the things we set
		// on the nodes generated by the procedurals, which is frankly useless.
		addNode( node );
	}
	else
	{
		addShape( node );
	}
}
void IECoreRI::SXRendererImplementation::procedural( IECore::Renderer::ProceduralPtr proc )
{
	proc->render( m_parent );
}