// 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;
		}
	}
}
void SOP_ParameterisedHolder::setInputParameterValues( float now )
{
	for ( unsigned int i=0; i < m_inputParameters.size(); i++ )
	{
		useInputSource( i, m_dirty, false );
		
		IECore::ParameterPtr inputParameter = m_inputParameters[i];
		
		GU_DetailHandle inputHandle = inputGeoHandle( i );
		GU_DetailHandleAutoReadLock readHandle( inputHandle );
		const GU_Detail *inputGdp = readHandle.getGdp();
		if ( !inputGdp )
		{
			continue;
		}
		
		const GA_ROAttributeRef attrRef = inputGdp->findAttribute( GA_ATTRIB_DETAIL, GA_SCOPE_PRIVATE, "IECoreHoudiniNodePassData" );
		if ( attrRef.isValid() )
		{
			// looks like data passed from another ParameterisedHolder
			const GA_Attribute *attr = attrRef.getAttribute();
			const GA_AIFBlindData *blindData = attr->getAIFBlindData();
			const NodePassData passData = blindData->getValue<NodePassData>( attr, 0 );
			SOP_ParameterisedHolder *sop = dynamic_cast<SOP_ParameterisedHolder*>( const_cast<OP_Node*>( passData.nodePtr() ) );
			
			IECore::ConstObjectPtr result = 0;
			if ( passData.type() == IECoreHoudini::NodePassData::CORTEX_OPHOLDER )
			{
				IECore::OpPtr op = IECore::runTimeCast<IECore::Op>( sop->getParameterised() );
				result = op->resultParameter()->getValue();
			}
			else if ( passData.type() == IECoreHoudini::NodePassData::CORTEX_PROCEDURALHOLDER )
			{
				IECore::ParameterisedProcedural *procedural = IECore::runTimeCast<IECore::ParameterisedProcedural>( sop->getParameterised() );
				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 );
					}
				}
				result = IECore::runTimeCast<const IECore::Object>( renderer->world() );
			}
			else
			{
				continue;
			}
			
			try
			{
				inputParameter->setValidatedValue( IECore::constPointerCast<IECore::Object>( result ) );
			}
			catch ( const IECore::Exception &e )
			{
				addError( SOP_MESSAGE, e.what() );
			}
		}
		else
		{
			// looks like a regular Houdini detail
			IECore::ObjectParameterPtr objectParameter = IECore::runTimeCast<IECore::ObjectParameter>( inputParameter );
			if ( !objectParameter )
			{
				continue;
			}
			
			FromHoudiniGeometryConverterPtr converter = FromHoudiniGeometryConverter::create( inputHandle, objectParameter->validTypes() );
			if ( !converter )
			{
				continue;
			}
			
			// set converter parameters from the node values
			const CompoundParameter::ParameterVector &converterParameters = converter->parameters()->orderedParameters();
			for ( CompoundParameter::ParameterVector::const_iterator it=converterParameters.begin(); it != converterParameters.end(); ++it )
			{
				updateParameter( *it, now, "parm_" + inputParameter->name() + "_" );
			}
			
			try
			{
				IECore::ObjectPtr converted = converter->convert();
				if ( converted )
				{
					inputParameter->setValidatedValue( converted );
				}
			}
			catch ( const IECore::Exception &e )
			{
				addError( SOP_MESSAGE, e.what() );
			}
			catch ( std::runtime_error &e )
			{
				addError( SOP_MESSAGE, e.what() );
			}
		}
	}
}