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() ) );
	}
}
void SOP_groupAsAttr::groupToAttrPrims(const UT_String& in_attr, const int& debug_in)
{

    groupNameIndex = gdp->findStringTuple(GA_ATTRIB_PRIMITIVE, in_attr);

    if(groupNameIndex.isInvalid())
    {
        groupNameIndex = gdp->addStringTuple(GA_ATTRIB_PRIMITIVE, in_attr, 1);
        if(groupNameIndex.isInvalid())
        {
            addError(SOP_ATTRIBUTE_INVALID, "Unable to create primitive attribut");

        }
    }


    //iterate thru all the points and for every point iterate thru all the groups
    GA_Primitive *prim;
    GA_FOR_ALL_PRIMITIVES(gdp, prim)
    {
        bool exist = false;

        //set our current group
        GA_PrimitiveGroup *curGrp;
        //for all the point groups
        GA_FOR_ALL_PRIMGROUPS(gdp, curGrp)
        {
            if(curGrp)
            {
                if(exist == false)
                {
                    if(curGrp->contains(*prim))
                    {
                        prim->setString(groupNameIndex, curGrp->getName());
                        exist = true;
                    }
                    else
                    {
                        prim->setString(groupNameIndex, "no group");
                    }
                }
            }
        }
    }
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 );
}
void IECoreMantra::ProceduralPrimitive::addVisibleRenderable( VisibleRenderablePtr renderable )
{
	ToHoudiniGeometryConverterPtr converter = ToHoudiniGeometryConverter::create( renderable );
	if( !converter ) 
	{
		msg( Msg::Warning, "ProceduralPrimitive::addVisibleRenderable", "converter could not be found" );
		return;
	}
	GU_Detail *gdp = allocateGeometry();
	GU_DetailHandle handle;
	handle.allocateAndSet( (GU_Detail*)gdp, false );
	bool converted = converter->convert( handle );
	if ( !converted )
	{
		msg( Msg::Warning, "ProceduralPrimitive::addVisibleRenderable", "converter failed" );
		return;
	}
	/// \todo ToHoudiniGeometryConverter does not create a Houdini style uv attribute.
	/// We make one from s and t. This code should probably live in a converter or in an Op that
	/// remaps IECore conventions to common Houdini ones.
	MeshPrimitivePtr mesh = runTimeCast<MeshPrimitive> (renderable);
	if ( mesh )
	{
		gdp->addTextureAttribute( GA_ATTRIB_VERTEX );
		GEO_AttributeHandle auv = gdp->getAttribute( GA_ATTRIB_VERTEX, "uv" );
		GEO_AttributeHandle as = gdp->getAttribute( GA_ATTRIB_VERTEX, "s" );
		GEO_AttributeHandle at = gdp->getAttribute( GA_ATTRIB_VERTEX, "t" );
		if ( auv.isAttributeValid() && as.isAttributeValid() && at.isAttributeValid() )
		{
			GA_GBPrimitiveIterator it( *gdp );
			GA_Primitive *p = it.getPrimitive();
			while ( p )
			{
				for (int i = 0; i < p->getVertexCount(); ++i)
				{
					GA_Offset v = p->getVertexOffset(i);
					as.setVertex(v);
					at.setVertex(v);
					auv.setVertex(v);
					auv.setF( as.getF(0), 0 );
					auv.setF( ((at.getF(0) * -1.0f) + 1.0f), 1 ); // wat, t arrives upside down for some reason.
					auv.setF( 0.0f, 2 );
				}
				++it;
				p = it.getPrimitive();
			}
		}
	}

	if ( m_renderer->m_motionType == RendererImplementation::Geometry )
	{
		msg(Msg::Debug, "IECoreMantra::ProceduralPrimitive::addVisibleRenderable", "MotionBlur:Geometry" );
		if ( !m_renderer->m_motionTimes.empty() )
		{
			if ( (size_t)m_renderer->m_motionSize == m_renderer->m_motionTimes.size() )
			{
				openGeometryObject();
			}
			addGeometry(gdp, m_renderer->m_motionTimes.front());
			m_renderer->m_motionTimes.pop_front();
			if ( m_renderer->m_motionTimes.empty() )
			{
				applySettings();
				closeObject();
			}
		}
	}
	else if ( m_renderer->m_motionType == RendererImplementation::ConcatTransform ||
			  m_renderer->m_motionType == RendererImplementation::SetTransform )
	{
		// It isn't clear that this will give correct results. 
		// ConcatTransform may need to interpolate transform snapshots.
		msg(Msg::Debug, "IECoreMantra::ProceduralPrimitive::addVisibleRenderable", "MotionBlur:Transform" );
		openGeometryObject();
			addGeometry(gdp, 0.0f);
			while ( !m_renderer->m_motionTimes.empty() )
			{
				setPreTransform( convert< UT_Matrix4T<float> >(m_renderer->m_motionTransforms.front()),
								 m_renderer->m_motionTimes.front() );
				m_renderer->m_motionTimes.pop_front();
				m_renderer->m_motionTransforms.pop_front();
			}
			applySettings();
		closeObject();
		m_renderer->m_motionType = RendererImplementation::Unknown;
	}
	else if ( m_renderer->m_motionType == RendererImplementation::Velocity )
	{
		msg(Msg::Debug, "IECoreMantra::ProceduralPrimitive::addVisibleRenderable", "MotionBlur:Velocity" );
		openGeometryObject();
			addGeometry(gdp, 0.0f);
			addVelocityBlurGeometry(gdp, m_preBlur, m_postBlur);
			applySettings();
		closeObject();
		m_renderer->m_motionType = RendererImplementation::Unknown;
	}
	else
	{
		msg(Msg::Debug, "IECoreMantra::ProceduralPrimitive::addVisibleRenderable", "MotionBlur:None" );
		openGeometryObject();
			addGeometry( gdp, 0.0f );
			setPreTransform( convert< UT_Matrix4T<float> >(m_renderer->m_transformStack.top()), 0.0f);
			applySettings();
		closeObject();
	}
}