// general cortex render function, takes a gu_detail and uses the NodePassData attribute
// to call the required render method
void GR_Cortex::render( GU_Detail *gdp, const IECoreGL::State *displayState )
{
	// gl scene from a parameterised procedural
	const GA_ROAttributeRef attrRef = gdp->findAttribute( GA_ATTRIB_DETAIL, GA_SCOPE_PRIVATE, "IECoreHoudiniNodePassData" );
	if ( attrRef.isInvalid() )
	{
		return;
	}
	
	const GA_Attribute *attr = attrRef.getAttribute();
	const GA_AIFBlindData *blindData = attr->getAIFBlindData();
	const NodePassData passData = blindData->getValue<NodePassData>( attr, 0 );
	
	switch( passData.type() )
	{
		case IECoreHoudini::NodePassData::CORTEX_OPHOLDER :
		{
			SOP_OpHolder *sop = dynamic_cast<SOP_OpHolder*>( const_cast<OP_Node*>( passData.nodePtr() ) );
			if ( !sop )
			{
				return;
			}

			IECore::OpPtr op = IECore::runTimeCast<IECore::Op>( sop->getParameterised() );
			if ( !op )
			{
				return;
			}

			const IECore::Parameter *result_parameter = op->resultParameter();
			const IECore::Object *result_object = result_parameter->getValue();
			renderObject( result_object, displayState );
			break;
		}
		case IECoreHoudini::NodePassData::CORTEX_PROCEDURALHOLDER :
		{
			SOP_ProceduralHolder *sop = dynamic_cast<SOP_ProceduralHolder*>( const_cast<OP_Node*>( passData.nodePtr() ) );
			if ( !sop )
			{
				return;
			}

			IECoreGL::ConstScenePtr scene = sop->scene();
			if ( !scene )
			{
				return;
			}

			scene->render( const_cast<IECoreGL::State *>( displayState ) );
			break;
		}
		default :
		{
			break;
		}
	}
}
ObjectPtr FromHoudiniGroupConverter::doConversion( ConstCompoundObjectPtr operands ) const
{
	GU_DetailHandleAutoReadLock readHandle( handle() );
	const GU_Detail *geo = readHandle.getGdp();
	if ( !geo )
	{
		return 0;
	}
	
	size_t numResultPrims = 0;
	size_t numOrigPrims = geo->getNumPrimitives();
	
	GroupPtr result = new Group();
	
	if ( operands->member<const IntData>( "groupingMode" )->readable() == NameAttribute )
	{
		GA_ROAttributeRef attributeRef = geo->findPrimitiveAttribute( "name" );
		if ( attributeRef.isInvalid() || !attributeRef.isString() )
		{
			GU_Detail ungroupedGeo( (GU_Detail*)geo );
			GA_PrimitiveGroup *ungrouped = static_cast<GA_PrimitiveGroup*>( ungroupedGeo.createInternalElementGroup( GA_ATTRIB_PRIMITIVE, "FromHoudiniGroupConverter__ungroupedPrimitives" ) );
			ungrouped->toggleRange( ungroupedGeo.getPrimitiveRange() );
			
			VisibleRenderablePtr renderable = 0;
			doGroupConversion( &ungroupedGeo, ungrouped, renderable, operands );
			if ( renderable )
			{
				Group *group = runTimeCast<Group>( renderable );
				if ( group )
				{
					const Group::ChildContainer &children = group->children();
					for ( Group::ChildContainer::const_iterator it = children.begin(); it != children.end(); ++it )
					{
						result->addChild( *it );
					}
				}
				else
				{
					result->addChild( renderable );
				}
			}
			
			return result;
		}
		
		GU_Detail groupGeo( (GU_Detail*)geo );
		
		AttributePrimIdGroupMap groupMap;
		regroup( &groupGeo, groupMap, attributeRef );
		
		for ( AttributePrimIdGroupMapIterator it=groupMap.begin(); it != groupMap.end(); ++it )
		{
			convertAndAddPrimitive( &groupGeo, it->second, result, operands, it->first.first );
		}
	}
	else
	{
		for ( GA_GroupTable::iterator<GA_ElementGroup> it=geo->primitiveGroups().beginTraverse(); !it.atEnd(); ++it )
		{
			GA_PrimitiveGroup *group = static_cast<GA_PrimitiveGroup*>( it.group() );
			if ( group->getInternal() || group->isEmpty() )
			{
				continue;
			}

			VisibleRenderablePtr renderable = 0;
			numResultPrims += doGroupConversion( geo, group, renderable, operands );
			if( !renderable )
			{
				continue;
			}
			
			renderable->blindData()->member<StringData>( "name", false, true )->writable() = group->getName().toStdString();
			result->addChild( renderable );
		}

		if ( numOrigPrims == numResultPrims )
		{
			return result;
		}

		GU_Detail ungroupedGeo( (GU_Detail*)geo );
		GA_PrimitiveGroup *ungrouped = static_cast<GA_PrimitiveGroup*>( ungroupedGeo.createInternalElementGroup( GA_ATTRIB_PRIMITIVE, "FromHoudiniGroupConverter__ungroupedPrimitives" ) );
		for ( GA_GroupTable::iterator<GA_ElementGroup> it=geo->primitiveGroups().beginTraverse(); !it.atEnd(); ++it )
		{
			*ungrouped |= *static_cast<GA_PrimitiveGroup*>( it.group() );
		}
		ungrouped->toggleRange( ungroupedGeo.getPrimitiveRange() );

		if ( ungrouped->isEmpty() )
		{
			return result;
		}

		VisibleRenderablePtr renderable = 0;
		doGroupConversion( &ungroupedGeo, ungrouped, renderable, operands );
		if ( renderable )
		{
			result->addChild( renderable );
		}
	}
	
	return result;
}