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 );
}
void SOP_CortexConverter::doConvert( const GU_DetailHandle &handle, const std::string &name, ResultType type, const std::string &attributeFilter, bool convertStandardAttributes )
{
	if ( handle.isNull() )
	{
		addError( SOP_MESSAGE, ( "Could not extract the geometry named " + name ).c_str() );
		return;
	}
	
	FromHoudiniGeometryConverterPtr fromConverter = FromHoudiniGeometryConverter::create( handle );
	if ( !fromConverter )
	{
		addError( SOP_MESSAGE, ( "Could not convert the geometry named " + name ).c_str() );
		return;
	}
	
	IECore::ObjectPtr result = fromConverter->convert();
	if ( !result )
	{
		addError( SOP_MESSAGE, ( "Could not find Cortex Object named " + name + " on input geometry" ).c_str() );
		return;
	}
	
	if ( IECore::ParameterisedProcedural *procedural = IECore::runTimeCast<IECore::ParameterisedProcedural>( result.get() ) )
	{
		IECore::CapturingRendererPtr renderer = new IECore::CapturingRenderer();
		// We are acquiring and releasing the GIL here to ensure that it is released when we render. This has
		// to be done because a procedural might jump between c++ and python a few times (i.e. if it spawns
		// subprocedurals that are implemented in python). In a normal call to cookMySop, this wouldn't be an
		// issue, but if cookMySop was called from HOM, hou.Node.cook appears to be holding onto the GIL.
		IECorePython::ScopedGILLock gilLock;
		{
			IECorePython::ScopedGILRelease gilRelease;
			{
				IECore::WorldBlock worldBlock( renderer );
				procedural->render( renderer.get() );
			}
		}
		
		result = boost::const_pointer_cast<IECore::Object>( IECore::runTimeCast<const IECore::Object>( renderer->world() ) );
	}
	
	ToHoudiniGeometryConverterPtr converter = ( type == Cortex ) ? new ToHoudiniCortexObjectConverter( result.get() ) : ToHoudiniGeometryConverter::create( result.get() );
	converter->nameParameter()->setTypedValue( name );
	converter->attributeFilterParameter()->setTypedValue( attributeFilter );
	converter->convertStandardAttributesParameter()->setTypedValue( convertStandardAttributes );
	
	if ( !converter->convert( myGdpHandle ) )
	{
		addError( SOP_MESSAGE, ( "Could not convert the Cortex Object named " + name + " to Houdini geometry" ).c_str() );
	}
}
bool ToHoudiniGroupConverter::doConversion( const VisibleRenderable *renderable, GU_Detail *geo ) const
{
    const Group *group = IECore::runTimeCast<const Group>( renderable );
    if ( !group )
    {
        return false;
    }

    Imath::M44f transform = ( runTimeCast<const M44fData>( m_transformParameter->getValue() ) )->readable();
    const Transform *groupTransform = group->getTransform();
    if ( groupTransform )
    {
        transform = transform * groupTransform->transform();
    }

    TransformOpPtr transformOp = new TransformOp();
    M44fDataPtr transformData = new M44fData( transform );
    transformOp->matrixParameter()->setValue( transformData );

    std::string groupName = nameParameter()->getTypedValue();
    if ( groupName == "" )
    {
        // backwards compatibility with older data
        if ( const StringData *groupNameData = group->blindData()->member<StringData>( "name" ) )
        {
            groupName = groupNameData->readable();
        }
    }

    const std::string &attribFilter = attributeFilterParameter()->getTypedValue();
    bool convertStandardAttributes = convertStandardAttributesParameter()->getTypedValue();

    size_t i = 0;
    const Group::ChildContainer &children = group->children();
    for ( Group::ChildContainer::const_iterator it=children.begin(); it != children.end(); ++it, ++i )
    {
        ConstVisibleRenderablePtr child = *it;

        ConstPrimitivePtr primitive = runTimeCast<const Primitive>( child );
        if ( primitive )
        {
            transformOp->inputParameter()->setValue( constPointerCast<Primitive>( primitive ) );
            child = staticPointerCast<VisibleRenderable>( transformOp->operate() );
        }

        ToHoudiniGeometryConverterPtr converter = ToHoudiniGeometryConverter::create( child );
        if ( !converter )
        {
            continue;
        }

        std::string name = groupName;
        if ( const StringData *childNameData = child->blindData()->member<StringData>( "name" ) )
        {
            const std::string &childName = childNameData->readable();
            if ( childName != "" )
            {
                if ( groupName != "" )
                {
                    name += "/";
                }

                name += childName;
            }
        }

        converter->nameParameter()->setTypedValue( name );
        converter->attributeFilterParameter()->setTypedValue( attribFilter );
        converter->convertStandardAttributesParameter()->setTypedValue( convertStandardAttributes );

        ToHoudiniGroupConverter *groupConverter = runTimeCast<ToHoudiniGroupConverter>( converter );
        if ( groupConverter )
        {
            groupConverter->transformParameter()->setValue( transformData );
        }

        GU_DetailHandle handle;
        handle.allocateAndSet( geo, false );

        if ( !converter->convert( handle ) )
        {
            continue;
        }
    }

    return true;
}
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;
	}
}