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