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();
}
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 );
}
Beispiel #3
0
// 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;
		}
	}
}
Beispiel #4
0
// Tell Houdini to only render GU_ProceduralDetails with this render hook.
GA_PrimCompat::TypeMask GR_Cortex::getShadedMask( GU_Detail *gdp, const GR_DisplayOption *dopt ) const
{
	const GA_ROAttributeRef attrRef = gdp->findAttribute( GA_ATTRIB_DETAIL, GA_SCOPE_PRIVATE, "IECoreHoudiniNodePassData" );
	if ( attrRef.isValid() )
	{
		return GA_PrimCompat::TypeMask( 0 );
	}
	else
	{
		return GEO_PrimTypeCompat::GEOPRIMALL;
	}
}
Beispiel #5
0
bool HoudiniScene::hasObject() const
{
	OP_Node *node = retrieveNode( true );
	if ( node->isManager() )
	{
		return false;
	}
	
	OBJ_Node *objNode = node->castToOBJNode();
	if ( !objNode )
	{
		return false;
	}
	
	OBJ_OBJECT_TYPE type = objNode->getObjectType();
	if ( type == OBJ_GEOMETRY  )
	{
		OP_Context context( getDefaultTime() );
		const GU_Detail *geo = objNode->getRenderGeometry( context, false );
		// multiple named shapes define children that contain each object
		/// \todo: similar attribute logic is repeated in several places. unify in a single function if possible
		GA_ROAttributeRef nameAttrRef = geo->findStringTuple( GA_ATTRIB_PRIMITIVE, "name" );
		if ( !nameAttrRef.isValid() )
		{
			return true;
		}
		
		const GA_Attribute *nameAttr = nameAttrRef.getAttribute();
		const GA_AIFSharedStringTuple *tuple = nameAttr->getAIFSharedStringTuple();
		GA_Size numShapes = tuple->getTableEntries( nameAttr );
		if ( !numShapes )
		{
			return true;
		}
		
		for ( GA_Size i=0; i < numShapes; ++i )
		{
			const char *currentName = tuple->getTableString( nameAttr, tuple->validateTableHandle( nameAttr, i ) );
			const char *match = matchPath( currentName );
			if ( match && *match == *emptyString )
			{
				// exact match
				return true;
			}
		}
		
		return false;
	}
	
	/// \todo: need to account for OBJ_CAMERA and OBJ_LIGHT
	
	return false;
}
FromHoudiniGeometryConverter::Convertability FromHoudiniCurvesConverter::canConvert( const GU_Detail *geo )
{
	const GA_PrimitiveList &primitives = geo->getPrimitiveList();
	
	unsigned numPrims = geo->getNumPrimitives();
	GA_Iterator firstPrim = geo->getPrimitiveRange().begin();
	if ( !numPrims || !compatiblePrimitive( primitives.get( firstPrim.getOffset() )->getTypeId() ) )
	{
		return Inapplicable;
	}
	
	const GEO_Curve *firstCurve = (const GEO_Curve*)primitives.get( firstPrim.getOffset() );
	bool periodic = firstCurve->isClosed();
	unsigned order = firstCurve->getOrder();
	
	for ( GA_Iterator it=firstPrim; !it.atEnd(); ++it )
	{
		const GA_Primitive *prim = primitives.get( it.getOffset() );
		if ( !compatiblePrimitive( prim->getTypeId() ) )
		{
			return Inapplicable;
		}
		
		const GEO_Curve *curve = (const GEO_Curve*)prim;
		if ( curve->getOrder() != order )
		{
			return Inapplicable;
		}
		
		if ( curve->isClosed() != periodic )
		{
			return Inapplicable;
		}
	}
	
	// is there a single named shape?
	GA_ROAttributeRef attrRef = geo->findPrimitiveAttribute( "name" );
	if ( attrRef.isValid() && attrRef.isString() )
	{
		const GA_Attribute *nameAttr = attrRef.getAttribute();
		const GA_AIFSharedStringTuple *tuple = nameAttr->getAIFSharedStringTuple();
		GA_StringTableStatistics stats;
		tuple->getStatistics( nameAttr, stats );
		if ( stats.getEntries() < 2 )
		{
			return Ideal;
		}
	}
	
	return Suitable;
}
int
SOP_PrimCentroid::copyLocalVariables(const char *attr,
                                     const char *varname,
                                     void *data)
{
    GA_ROAttributeRef           gah;

    GU_Detail                   *gdp;

    // Extract the detail.
    gdp = (GU_Detail *)data;

    // Try to find the attribute we are processing.
    gah = gdp->findPointAttribute(attr);

    // If a point attribute exists then we can copy this variable mapping.
    if (gah.isValid())
        gdp->addVariableName(attr, varname);

    return 1;
}
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 );
}
static void exportParticlesDetail( const GU_Detail* gdp,
                                  const std::string& filePath,
                                  const std::map<std::string,
                                  channel_type>& desiredChannels )
{
	prt_ofstream ostream;

	static std::map<std::string, std::string> s_reservedChannels;
	if( s_reservedChannels.empty() ) {
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_NORMAL ) ] = "Normal";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_TEXTURE ) ] = "TextureCoord";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_VELOCITY ) ] = "Velocity";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_DIFFUSE ) ] = "Color";
		//s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_ALPHA ) ] = "Density";
		//s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_MASS ) ] = "Density";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_LIFE ) ] = "";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_ID ) ] = "ID";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_PSCALE ) ] = "Scale";
		s_reservedChannels[ "accel" ] = "Acceleration";
	}

	float posVal[3];
	float lifeVal[2];
	
	ostream.bind( "Position", posVal, 3 );

	//We handle the life channel in a special manner
	GA_ROAttributeRef lifeAttrib = gdp->findPointAttribute( gdp->getStdAttributeName( GEO_ATTRIBUTE_LIFE ) );
	if( lifeAttrib.isValid() ){
		std::map<std::string,channel_type>::const_iterator it;
		
		it = desiredChannels.find( "Age" );
		if( it != desiredChannels.end() && it->second.second == 1 )
			ostream.bind( "Age", &lifeVal[0], 1, it->second.first );
		else if( desiredChannels.empty() )
			ostream.bind( "Age", &lifeVal[0], 1, prtio::data_types::type_float16 );

		it = desiredChannels.find( "LifeSpan" );
		if( it != desiredChannels.end() && it->second.second == 1 )
			ostream.bind( "LifeSpan", &lifeVal[1], 1, it->second.first );
		else if( desiredChannels.empty() )
			ostream.bind( "LifeSpan", &lifeVal[1], 1, prtio::data_types::type_float16 );
	}
	
	//Using a deque to prevent the memory from moving around after adding the bound_attribute to the container.
	std::deque< bound_attribute<int> > m_intAttrs;
	std::deque< bound_attribute<float> > m_floatAttrs;
	std::deque< bound_attribute<float> > m_vectorAttrs;
	
	for ( GA_AttributeDict::iterator it = gdp->getAttributes().getDict(GA_ATTRIB_POINT).begin(GA_SCOPE_PUBLIC); !it.atEnd(); ++it) {
		
		GA_Attribute *node = it.attrib();

		std::string channelName = node->getName();

		//Translate special names
		std::map<std::string,std::string>::const_iterator itResChannel = s_reservedChannels.find( channelName );
		if( itResChannel != s_reservedChannels.end() ){
			//If its empty, that means we reserve some sort of special handling.
			if( itResChannel->second.empty() )
				continue;
			channelName = itResChannel->second;
		}
		
		//Skip channels that aren't on the list.
		std::map<std::string,channel_type>::const_iterator itChannel = desiredChannels.find( channelName );
		bool channelIsDesired = ( itChannel != desiredChannels.end() );
		
		if( !desiredChannels.empty() && !channelIsDesired )
			continue;
			
		prtio::data_types::enum_t type;
		
		//Only add valid channel names
		if( detail::is_valid_channel_name( channelName.c_str() ) ) {
			//I add the new item to the deque, THEN initialize it since a deque will not move the object around and this allows
			//me to allocate the float array and not have to worry about the object getting deleted too early.
			switch( node->getStorageClass() ){
			case GA_STORECLASS_FLOAT:
				if( node->getTupleSize()==3 ){
					m_vectorAttrs.push_back( bound_attribute<float>() );
					m_vectorAttrs.back().attr =	gdp->findPointAttribute(node->getName());
					m_vectorAttrs.back().count = node->getTupleSize();
					m_vectorAttrs.back().data = new float[m_vectorAttrs.back().count];

					type = prtio::data_types::type_float16;
					if( channelIsDesired ){
						type = itChannel->second.first;
						if( itChannel->second.second != m_vectorAttrs.back().count )
							continue;
					}

					ostream.bind( channelName, m_vectorAttrs.back().data, m_vectorAttrs.back().count, type );

				} else {
					m_floatAttrs.push_back( bound_attribute<float>() );
					m_floatAttrs.back().attr =	gdp->findPointAttribute( node->getName() );
					m_floatAttrs.back().count = node->getTupleSize();
					m_floatAttrs.back().data = new float[m_floatAttrs.back().count];

					type = prtio::data_types::type_float16;
					if( channelIsDesired ){
						type = itChannel->second.first;
						if( itChannel->second.second != m_floatAttrs.back().count )
							continue;
					}

					ostream.bind( channelName, m_floatAttrs.back().data, m_floatAttrs.back().count, type );
				}
				break;
			case GA_STORECLASS_INT:
				m_intAttrs.push_back( bound_attribute<int>() );
				m_intAttrs.back().attr = gdp->findPointAttribute( node->getName() );
				m_intAttrs.back().count = node->getTupleSize();
				m_intAttrs.back().data = new int[m_intAttrs.back().count];

				type = prtio::data_types::type_int32;
				if( channelIsDesired ){
					type = itChannel->second.first;
					if( itChannel->second.second != m_intAttrs.back().count )
						continue;
				}
			
				ostream.bind( channelName, m_intAttrs.back().data, m_intAttrs.back().count, type );
				break;
			default:
				break;
			}
		}
	}

	try{
		ostream.open( filePath );
	} catch( const std::ios::failure& e ) {
		std::cerr << e.what() << std::endl;
		throw HOM_OperationFailed( "Failed to open the file" );
	}
		
	GA_IndexMap map = gdp->getPointMap();
	UT_Vector3 p;
	GEO_Point* pt;
	GA_Index indexSize = map.indexSize();
	GA_Offset offset;

	for( int i = 0 ; i < indexSize; i++ ) {
		offset = map.offsetFromIndex( i );
		p = gdp->getPos3( offset );
		posVal[0] = p.x();
		posVal[1] = p.y();
		posVal[2] = -1 * p.z();
		
		//TODO: Remove the GEO_Point object that is now deprecated. 
		pt = ( GEO_Point* )gdp->getGBPoint( offset );
		
		//TODO: Convert this into appropriate time values. Is it seconds or frames or what?!
		if( lifeAttrib.isValid() ) 
			pt->get( lifeAttrib, lifeVal, 2 );

		for( std::deque< bound_attribute<float> >::iterator it = m_floatAttrs.begin(), itEnd = m_floatAttrs.end(); it != itEnd; ++it )
			pt->get( it->attr, it->data, it->count );

		for( std::deque< bound_attribute<float> >::iterator it = m_vectorAttrs.begin(), itEnd = m_vectorAttrs.end(); it != itEnd; ++it ) {
			pt->get( it->attr, it->data, it->count );
				
			//TODO: Optionally transform into some consistent world space for PRT files.
		}

		for( std::deque< bound_attribute<int> >::iterator it = m_intAttrs.begin(), itEnd = m_intAttrs.end(); it != itEnd; ++it )
			pt->get( it->attr, it->data, it->count );

		ostream.write_next_particle();
	}
	
	ostream.close();
}
OP_ERROR SOP_SceneCacheSource::cookMySop( OP_Context &context )
{
	// make sure the state is valid
	if ( boost::indeterminate( m_static ) )
	{
		sceneChanged();
	}
	
	flags().setTimeDep( bool( !m_static ) );
	
	std::string file;
	if ( !ensureFile( file ) )
	{
		addError( SOP_ATTRIBUTE_INVALID, ( file + " is not a valid .scc" ).c_str() );
		gdp->clearAndDestroy();
		return error();
	}
	
	std::string path = getPath();
	Space space = getSpace();
	GeometryType geometryType = (GeometryType)this->evalInt( pGeometryType.getToken(), 0, 0 );
	
	UT_String tagFilterStr;
	getTagFilter( tagFilterStr );
	UT_StringMMPattern tagFilter;
	tagFilter.compile( tagFilterStr );
	
	UT_String shapeFilterStr;
	getShapeFilter( shapeFilterStr );
	UT_StringMMPattern shapeFilter;
	shapeFilter.compile( shapeFilterStr );
	
	UT_String p( "P" );
	UT_String attributeFilter;
	getAttributeFilter( attributeFilter );
	if ( !p.match( attributeFilter ) )
	{
		attributeFilter += " P";
	}
	
	UT_String attributeCopy;
	getAttributeCopy( attributeCopy );
	
	UT_String fullPathName;
	getFullPathName( fullPathName );
	
	ConstSceneInterfacePtr scene = this->scene( file, path );
	if ( !scene )
	{
		addError( SOP_ATTRIBUTE_INVALID, ( path + " is not a valid location in " + file ).c_str() );
		gdp->clearAndDestroy();
		return error();
	}
	
	MurmurHash hash;
	hash.append( file );
	hash.append( path );
	hash.append( space );
	hash.append( tagFilterStr );
	hash.append( shapeFilterStr );
	hash.append( attributeFilter );
	hash.append( attributeCopy );
	hash.append( fullPathName );
	hash.append( geometryType );
	hash.append( getObjectOnly() );
	
	if ( !m_loaded || m_hash != hash )
	{
		gdp->clearAndDestroy();
	}
	
	double readTime = time( context );
	Imath::M44d transform = ( space == World ) ? worldTransform( file, path, readTime ) : Imath::M44d();
	
	SceneInterface::Path rootPath;
	scene->path( rootPath );
	
	UT_Interrupt *progress = UTgetInterrupt();
	if ( !progress->opStart( ( "Cooking objects for " + getPath() ).c_str() ) )
	{
		addError( SOP_ATTRIBUTE_INVALID, "Cooking interrupted before it started" );
		gdp->clearAndDestroy();
		return error();
	}
	
	Parameters params;
	UT_String attribFilter;
	getAttributeFilter( attribFilter );
	params.attributeFilter = attribFilter.toStdString();
	params.attributeCopy = attributeCopy.toStdString();
	params.fullPathName = fullPathName.toStdString();
	params.geometryType = getGeometryType();
	getShapeFilter( params.shapeFilter );
	getTagFilter( params.tagFilter );
	
	// Building a map from shape name to primitive range, which will be used during
	// convertObject() to do a lazy update of animated primvars where possible, and
	// to destroy changing topology shapes when necessary.
	GA_ROAttributeRef nameAttrRef = gdp->findStringTuple( GA_ATTRIB_PRIMITIVE, "name" );
	if ( nameAttrRef.isValid() )
	{
		const GA_Attribute *attr = nameAttrRef.getAttribute();
		const GA_AIFSharedStringTuple *tuple = attr->getAIFSharedStringTuple();
		
		std::map<std::string, GA_OffsetList> offsets;
		GA_Range primRange = gdp->getPrimitiveRange();
		for ( GA_Iterator it = primRange.begin(); !it.atEnd(); ++it )
		{
			std::string current = "";
			if ( const char *value = tuple->getString( attr, it.getOffset() ) )
			{
				current = value;
			}
			
			std::map<std::string, GA_OffsetList>::iterator oIt = offsets.find( current );
			if ( oIt == offsets.end() )
			{
				oIt = offsets.insert( std::pair<std::string, GA_OffsetList>( current, GA_OffsetList() ) ).first;
			}
			
			oIt->second.append( it.getOffset() );
		}
		
		for ( std::map<std::string, GA_OffsetList>::iterator oIt = offsets.begin(); oIt != offsets.end(); ++oIt )
		{
			params.namedRanges[oIt->first] = GA_Range( gdp->getPrimitiveMap(), oIt->second );
		}
	}
	
	loadObjects( scene.get(), transform, readTime, space, params, rootPath.size() );
	
	if ( progress->opInterrupt( 100 ) )
	{
		addError( SOP_ATTRIBUTE_INVALID, "Cooking interrupted" );
		gdp->clearAndDestroy();		
		m_loaded = false;
		m_hash = MurmurHash();
	}
	else
	{
		m_loaded = true;
		m_hash = hash;
	}
	
	progress->opEnd();
	
	return error();
}
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() );
			}
		}
	}
}
Beispiel #12
0
OP_Node *HoudiniScene::retrieveChild( const Name &name, Path &contentPath, MissingBehaviour missingBehaviour ) const
{
	OP_Node *node = retrieveNode( false, missingBehaviour );
	OP_Node *contentBaseNode = retrieveNode( true, missingBehaviour );
	if ( !node || !contentBaseNode )
	{
		return 0;
	}
	
	OBJ_Node *objNode = node->castToOBJNode();
	OBJ_Node *contentNode = contentBaseNode->castToOBJNode();
	
	// check subnet children
	if ( node->isManager() || ( objNode && objNode->getObjectType() == OBJ_SUBNET ) )
	{
		for ( int i=0; i < node->getNchildren(); ++i )
		{
			OP_Node *child = node->getChild( i );
			// the contentNode is actually an extension of ourself
			if ( child == contentNode )
			{
				continue;
			}
			
			if ( child->getName().equal( name.c_str() ) && !hasInput( child ) )
			{
				return child;
			}
		}
	}
	
	if ( contentNode )
	{
		// check connected outputs
		for ( unsigned i=0; i < contentNode->nOutputs(); ++i )
		{
			OP_Node *child = contentNode->getOutput( i );
			if ( child->getName().equal( name.c_str() ) )
			{
				return child;
			}
		}
		
		// check child shapes within the geo
		if ( contentNode->getObjectType() == OBJ_GEOMETRY )
		{
			OP_Context context( getDefaultTime() );
			const GU_Detail *geo = contentNode->getRenderGeometry( context, false );
			GA_ROAttributeRef nameAttrRef = geo->findStringTuple( GA_ATTRIB_PRIMITIVE, "name" );
			if ( nameAttrRef.isValid() )
			{
				const GA_Attribute *nameAttr = nameAttrRef.getAttribute();
				const GA_AIFSharedStringTuple *tuple = nameAttr->getAIFSharedStringTuple();
				GA_Size numShapes = tuple->getTableEntries( nameAttr );
				for ( GA_Size i=0; i < numShapes; ++i )
				{
					const char *currentName = tuple->getTableString( nameAttr, tuple->validateTableHandle( nameAttr, i ) );
					const char *match = matchPath( currentName );
					if ( match && *match != *emptyString )
					{
						std::pair<const char *, size_t> childMarker = nextWord( match );
						std::string child( childMarker.first, childMarker.second );
						if ( name == child )
						{
							size_t contentSize = ( m_contentIndex ) ? m_path.size() - m_contentIndex : 0;
							if ( contentSize )
							{
								contentPath.resize( contentSize );
								std::copy( m_path.begin() + m_contentIndex, m_path.end(), contentPath.begin() );
							}
							
							contentPath.push_back( name );
							
							return contentNode;
						}
					}
				}
			}
		}
	}
	
	if ( missingBehaviour == SceneInterface::ThrowIfMissing )
	{
		Path p;
		path( p );
		std::string pStr;
		pathToString( p, pStr );
		throw Exception( "IECoreHoudini::HoudiniScene::retrieveChild: Path \"" + pStr + "\" has no child named " + name.string() + "." );
	}
	
	return 0;
}
Beispiel #13
0
void HoudiniScene::childNames( NameList &childNames ) const
{
	OP_Node *node = retrieveNode();
	OBJ_Node *objNode = node->castToOBJNode();
	OBJ_Node *contentNode = retrieveNode( true )->castToOBJNode();
	
	// add subnet children
	if ( node->isManager() || ( objNode && objNode->getObjectType() == OBJ_SUBNET ) )
	{
		for ( int i=0; i < node->getNchildren(); ++i )
		{
			OP_Node *child = node->getChild( i );
			
			// ignore children that have incoming connections, as those are actually grandchildren
			// also ignore the contentNode, which is actually an extension of ourself
			if ( child != contentNode && !hasInput( child ) )
			{
				childNames.push_back( Name( child->getName() ) );
			}
		}
	}
	
	if ( !contentNode )
	{
		return;
	}
	
	// add connected outputs
	for ( unsigned i=0; i < contentNode->nOutputs(); ++i )
	{
		childNames.push_back( Name( contentNode->getOutput( i )->getName() ) );
	}
	
	// add child shapes within the geometry
	if ( contentNode->getObjectType() == OBJ_GEOMETRY )
	{
		OP_Context context( getDefaultTime() );
		const GU_Detail *geo = contentNode->getRenderGeometry( context, false );
		GA_ROAttributeRef nameAttrRef = geo->findStringTuple( GA_ATTRIB_PRIMITIVE, "name" );
		if ( !nameAttrRef.isValid() )
		{
			return;
		}
		
		const GA_Attribute *nameAttr = nameAttrRef.getAttribute();
		const GA_AIFSharedStringTuple *tuple = nameAttr->getAIFSharedStringTuple();
		GA_Size numShapes = tuple->getTableEntries( nameAttr );
		for ( GA_Size i=0; i < numShapes; ++i )
		{
			const char *currentName = tuple->getTableString( nameAttr, tuple->validateTableHandle( nameAttr, i ) );
			const char *match = matchPath( currentName );
			if ( match && *match != *emptyString )
			{
				std::pair<const char *, size_t> childMarker = nextWord( match );
				std::string child( childMarker.first, childMarker.second );
				if ( std::find( childNames.begin(), childNames.end(), child ) == childNames.end() )
				{
					childNames.push_back( child );
				}
			}
		}
	}
}
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;
}
FromHoudiniGeometryConverter::Convertability FromHoudiniGroupConverter::canConvert( const GU_Detail *geo )
{
	const GA_PrimitiveList &primitives = geo->getPrimitiveList();
	
	// are there multiple primitives?
	unsigned numPrims = geo->getNumPrimitives();
	if ( numPrims < 2 )
	{
		return Admissible;
	}
	
	// are there mixed primitive types?
	GA_Iterator firstPrim = geo->getPrimitiveRange().begin();
	GA_PrimitiveTypeId firstPrimId = primitives.get( firstPrim.getOffset() )->getTypeId();
	for ( GA_Iterator it=firstPrim; !it.atEnd(); ++it )
	{
		if ( primitives.get( it.getOffset() )->getTypeId() != firstPrimId )
		{
			return Ideal;
		}
	}
	
	// are there multiple named shapes?
	GA_ROAttributeRef attrRef = geo->findPrimitiveAttribute( "name" );
	if ( attrRef.isValid() && attrRef.isString() )
	{
		const GA_Attribute *nameAttr = attrRef.getAttribute();
		const GA_AIFSharedStringTuple *tuple = nameAttr->getAIFSharedStringTuple();
		if ( tuple->getTableEntries( nameAttr ) > 1 )
		{
			return Ideal;
		}
	}
	
	// are the primitives split into groups?
	UT_PtrArray<const GA_ElementGroup*> primGroups;
	geo->getElementGroupList( GA_ATTRIB_PRIMITIVE, primGroups );
	if ( primGroups.isEmpty() )
	{
		return Admissible;
	}
	
	bool externalGroups = false;
	for ( unsigned i=0; i < primGroups.entries(); ++i )
	{
		const GA_ElementGroup *group = primGroups[i];
		if ( group->getInternal() )
		{
			continue;
		}
		
		if ( group->entries() == numPrims )
		{
			return Admissible;
		}
		
		externalGroups = true;
	}
	
	if ( externalGroups )
	{
		return Ideal;
	}
	
	return Admissible;
}