bool SOP_SceneCacheSource::convertObject( const IECore::Object *object, const std::string &name, const std::string &attributeFilter, GeometryType geometryType, bool hasAnimatedTopology, bool hasAnimatedPrimVars, const std::vector<InternedString> &animatedPrimVars )
{
	ToHoudiniGeometryConverterPtr converter = 0;
	if ( geometryType == Cortex )
	{
		converter = new ToHoudiniCortexObjectConverter( object );
	}
	else
	{
		const VisibleRenderable *renderable = IECore::runTimeCast<const VisibleRenderable>( object );
		if ( !renderable )
		{
			return false;
		}
		
		converter = ToHoudiniGeometryConverter::create( renderable );
	}
	
	if ( !converter )
	{
		return false;
	}
	
	// attempt to optimize the conversion by re-using animated primitive variables
	const Primitive *primitive = IECore::runTimeCast<const Primitive>( object );
	GA_ROAttributeRef nameAttrRef = gdp->findStringTuple( GA_ATTRIB_PRIMITIVE, "name" );
	GA_Range primRange = gdp->getRangeByValue( nameAttrRef, name.c_str() );
	if ( primitive && !hasAnimatedTopology && hasAnimatedPrimVars && nameAttrRef.isValid() && !primRange.isEmpty() )
	{
		// this means constant topology and primitive variables, even though multiple samples were written
		if ( animatedPrimVars.empty() )
		{
			return true;
		}
		
		GA_Range pointRange( *gdp, primRange, GA_ATTRIB_POINT, GA_Range::primitiveref(), false );
		
		std::string animatedPrimVarStr = "";
		for ( std::vector<InternedString>::const_iterator it = animatedPrimVars.begin(); it != animatedPrimVars.end(); ++it )
		{
			animatedPrimVarStr += it->string() + " ";
		}
		
		converter->attributeFilterParameter()->setTypedValue( animatedPrimVarStr );
		converter->transferAttribs( gdp, pointRange, primRange );
		
		return true;
	}
	else
	{
		gdp->destroyPrimitives( primRange, true );
	}
	
	// fallback to full conversion
	converter->nameParameter()->setTypedValue( name );
	converter->attributeFilterParameter()->setTypedValue( attributeFilter );
	return converter->convert( myGdpHandle );
}
bool SOP_SceneCacheSource::convertObject( const IECore::Object *object, const std::string &name, const SceneInterface *scene, Parameters &params )
{
	ToHoudiniGeometryConverterPtr converter = 0;
	if ( params.geometryType == Cortex )
	{
		converter = new ToHoudiniCortexObjectConverter( object );
	}
	else
	{
		const VisibleRenderable *renderable = IECore::runTimeCast<const VisibleRenderable>( object );
		if ( !renderable )
		{
			return false;
		}
		
		converter = ToHoudiniGeometryConverter::create( renderable );
	}
	
	if ( !converter )
	{
		return false;
	}
	
	// we need to set the name regardless of whether
	// we're reusing prims or doing the full conversion
	// because this parameter can have an affect in
	// transferAttribs() as well as convert()
	converter->nameParameter()->setTypedValue( name );
	
	// check the primitve range map to see if this shape exists already
	std::map<std::string, GA_Range>::iterator rIt = params.namedRanges.find( name );
	if ( rIt != params.namedRanges.end() && !rIt->second.isEmpty() )
	{
		GA_Range primRange = rIt->second;
		const Primitive *primitive = IECore::runTimeCast<const Primitive>( object );
		if ( primitive && !params.hasAnimatedTopology && params.hasAnimatedPrimVars )
		{
			// this means constant topology and primitive variables, even though multiple samples were written
			if ( params.animatedPrimVars.empty() )
			{
				return true;
			}
			
			GA_Range pointRange( *gdp, primRange, GA_ATTRIB_POINT, GA_Range::primitiveref(), false );
			
			// update the animated primitive variables only
			std::string animatedPrimVarStr = "";
			for ( std::vector<InternedString>::const_iterator it = params.animatedPrimVars.begin(); it != params.animatedPrimVars.end(); ++it )
			{
				animatedPrimVarStr += it->string() + " ";
			}
			
			converter->attributeFilterParameter()->setTypedValue( animatedPrimVarStr );
			
			try
			{
				converter->transferAttribs( gdp, pointRange, primRange );
				return true;
			}
			catch ( std::exception &e )
			{
				addWarning( SOP_MESSAGE, e.what() );
				return false;
			}
			catch ( ... )
			{
				addWarning( SOP_MESSAGE, "Attribute transfer failed for unknown reasons" );
				return false;
			}
		}
		else
		{
			// topology is changing, so destroy the exisiting primitives
			gdp->destroyPrimitives( primRange, true );
		}
	}
	
	// fallback to full conversion
	converter->attributeFilterParameter()->setTypedValue( params.attributeFilter );
	
	try
	{
		GA_Offset firstNewPrim = gdp->getPrimitiveMap().lastOffset() + 1;
		
		bool status = converter->convert( myGdpHandle );
		
		if ( params.fullPathName != "" )
		{
			// adds the full path in addition to the relative name
			const GA_IndexMap &primMap = gdp->getPrimitiveMap();
			GA_Range newPrims( primMap, firstNewPrim, primMap.lastOffset() + 1 );
			if ( newPrims.isValid() )
			{
				std::string fullName;
				SceneInterface::Path path;
				scene->path( path );
				SceneInterface::pathToString( path, fullName );
				
				GA_RWAttributeRef pathAttribRef = ToHoudiniStringVectorAttribConverter::convertString( params.fullPathName, fullName, gdp, newPrims );
				status = status && pathAttribRef.isValid();
			}
		}
		
		return status;
	}
	catch ( std::exception &e )
	{
		addWarning( SOP_MESSAGE, e.what() );
		return false;
	}
	catch ( ... )
	{
		addWarning( SOP_MESSAGE, "Conversion failed for unknown reasons" );
		return false;
	}
}