size_t FromHoudiniGroupConverter::regroup( GU_Detail *geo, AttributePrimIdGroupMap &groupMap, GA_ROAttributeRef attrRef ) const
{
	const GA_Attribute *attr = attrRef.getAttribute();
	const GA_AIFStringTuple *attrAIF = attrRef.getAIFStringTuple();
	
	AttributePrimIdGroupMapIterator it;
	const GA_PrimitiveList &primitives = geo->getPrimitiveList();
	for ( GA_Iterator pIt=geo->getPrimitiveRange().begin(); !pIt.atEnd(); ++pIt )
	{
		GA_Primitive *prim = primitives.get( pIt.getOffset() );
		unsigned primType = prim->getTypeId().get();
		
		std::string value = "";
		const char *tmp = attrAIF->getString( attr, pIt.getOffset() );
		if ( tmp )
		{
			value = tmp;
		}
		
		AttributePrimIdPair key( value, primType );
		it = groupMap.find( key );
		if ( it == groupMap.end() )
		{
			AttributePrimIdGroupPair pair( key, static_cast<GA_PrimitiveGroup*>( geo->createInternalElementGroup( GA_ATTRIB_PRIMITIVE, ( boost::format( "FromHoudiniGroupConverter__typedPrimitives%d%s" ) % primType % value ).str().c_str() ) ) );
			it = groupMap.insert( pair ).first;
		}
		
		it->second->add( prim );
	}
	
	return groupMap.size();
}
void ToHoudiniCortexObjectConverter::transferAttribs( GU_Detail *geo, const GA_Range &points, const GA_Range &prims ) const
{
	GA_Primitive *hPrim = geo->getPrimitiveList().get( prims.begin().getOffset() );
	if ( hPrim->getTypeId() != GU_CortexPrimitive::typeId() )
	{
		return;
	}
	
	const Primitive *input = IECore::runTimeCast<const Primitive>( srcParameter()->getValue() );
	Primitive *output = IECore::runTimeCast<Primitive>( ((GU_CortexPrimitive *)hPrim)->getObject() );
	if ( !input || !output )
	{
		return;
	}
	
	const char *filter = attributeFilterParameter()->getTypedValue().c_str();
	for ( PrimitiveVariableMap::const_iterator it = input->variables.begin() ; it != input->variables.end(); ++it )
	{
		if ( !UT_String( it->first ).multiMatch( filter ) )
		{
			continue;
		}
		
		if ( output->isPrimitiveVariableValid( it->second ) )
		{
			output->variables[it->first] = it->second;
		}
	}
	
	if ( UT_String( "P" ).multiMatch( filter ) )
	{
		geo->setPos3( points.begin().getOffset(), IECore::convert<UT_Vector3>( input->bound().center() ) );
	}
}
size_t FromHoudiniGroupConverter::regroup( GU_Detail *geo, PrimIdGroupMap &groupMap ) const
{
	PrimIdGroupMapIterator it;
	const GA_PrimitiveList &primitives = geo->getPrimitiveList();
	for ( GA_Iterator pIt=geo->getPrimitiveRange().begin(); !pIt.atEnd(); ++pIt )
	{
		GA_Primitive *prim = primitives.get( pIt.getOffset() );
		unsigned primType = prim->getTypeId().get();
		it = groupMap.find( primType );
		if ( it == groupMap.end() )
		{
			PrimIdGroupPair pair( primType, static_cast<GA_PrimitiveGroup*>( geo->createInternalElementGroup( GA_ATTRIB_PRIMITIVE, ( boost::format( "FromHoudiniGroupConverter__typedPrimitives%d" ) % primType ).str().c_str() ) ) );
			it = groupMap.insert( pair ).first;
		}
		
		it->second->add( prim );
	}
	
	return groupMap.size();
}
void SOP_SceneCacheSource::holdObject( IECore::Object *object, const std::string &name, bool hasAnimatedTopology, bool hasAnimatedPrimVars, const std::vector<InternedString> &animatedPrimVars )
{
	// attempt to optimize the conversion by re-using animated primitive variables
	const Primitive *primitive = IECore::runTimeCast<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;
		}
		
		GA_Primitive *hPrim = gdp->getPrimitiveList().get( primRange.begin().getOffset() );
		if ( hPrim->getTypeId() == GU_CortexPrimitive::typeId() )
		{
			/// \todo: can we just update the prim vars?
			((GU_CortexPrimitive *)hPrim)->setObject( primitive );
			GA_Range pointRange( *gdp, primRange, GA_ATTRIB_POINT, GA_Range::primitiveref(), false );
			gdp->setPos3( pointRange.begin().getOffset(), IECore::convert<UT_Vector3>( primitive->bound().center() ) );
			return;
		}
	}
	else
	{
		gdp->destroyPrimitives( primRange, true );
	}
	
	size_t numPrims = gdp->getNumPrimitives();
	GU_CortexPrimitive::build( gdp, object );
	GA_Offset primOffset = gdp->primitiveOffset( numPrims );
	
	GA_OffsetList offsets;
	offsets.append( primOffset );
	GA_Range newPrims( gdp->getPrimitiveMap(), offsets );
	
	ToHoudiniStringVectorAttribConverter::convertString( "name", name, gdp, newPrims );
}