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;
}
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?
	const GEO_AttributeHandle attrHandle = geo->getPrimAttribute( "name" );
	if ( attrHandle.isAttributeValid() )
	{
		const GA_ROAttributeRef attrRef( attrHandle.getAttribute() );
		if ( geo->getUniqueValueCount( attrRef ) < 2 )
		{
			return Ideal;
		}
	}
	
	return Suitable;
}
ObjectPtr FromHoudiniCurvesConverter::doDetailConversion( const GU_Detail *geo, const CompoundObject *operands ) const
{
	const GA_PrimitiveList &primitives = geo->getPrimitiveList();
	
	CurvesPrimitivePtr result = new CurvesPrimitive();
	
	GA_Iterator firstPrim = geo->getPrimitiveRange().begin();
	if ( !geo->getNumPrimitives() || !compatiblePrimitive( primitives.get( firstPrim.getOffset() )->getTypeId() ) )
	{
		throw std::runtime_error( "FromHoudiniCurvesConverter: Geometry contains no curves or non-curve primitives" );
	}
	
	// set periodic based on the first curve
	const GEO_Curve *firstCurve = (const GEO_Curve*)primitives.get( firstPrim.getOffset() );
	bool periodic = firstCurve->isClosed();
	
	// set basis based on the first curve
	bool duplicateEnds = false;
	CubicBasisf basis = CubicBasisf::linear();
	unsigned order = firstCurve->getOrder();
	if ( order == 4 )
	{
		basis = CubicBasisf::bSpline();
		
		if ( !periodic )
		{
			// there's an implicit duplication of the end points that we need to make explicit
			duplicateEnds = true;
		}
	}
	
	std::vector<int> origVertsPerCurve;
	std::vector<int> finalVertsPerCurve;
	for ( GA_Iterator it=firstPrim; !it.atEnd(); ++it )
	{
		const GA_Primitive *prim = primitives.get( it.getOffset() );
		if ( !compatiblePrimitive( prim->getTypeId() ) )
		{
			throw std::runtime_error( "FromHoudiniCurvesConverter: Geometry contains non-curve primitives" );
		}
		
		const GEO_Curve *curve = (const GEO_Curve*)prim;
		if ( curve->getOrder() != order )
		{
			throw std::runtime_error( "FromHoudiniCurvesConverter: Geometry contains multiple curves with differing order. Set all curves to order 2 (linear) or 4 (cubic bSpline)" );
		}
		
		if ( curve->isClosed() != periodic )
		{
			throw std::runtime_error( "FromHoudiniCurvesConverter: Geometry contains both open and closed curves" );
		}
		
		int numPrimVerts = prim->getVertexCount();
		
		origVertsPerCurve.push_back( numPrimVerts );
		
		if ( duplicateEnds && numPrimVerts )
		{
			numPrimVerts += 4;
		}
		
		finalVertsPerCurve.push_back( numPrimVerts );
	}
	
	if ( !origVertsPerCurve.size() )
	{
		throw std::runtime_error( "FromHoudiniCurvesConverter: Geometry does not contain curve vertices" );
	}
	
	result->setTopology( new IntVectorData( origVertsPerCurve ), basis, periodic );
	
	transferAttribs( geo, result, operands, PrimitiveVariable::Vertex );
	
	if ( !duplicateEnds )
	{
		return result;
	}
	
	// adjust for duplicated end points
	DuplicateEnds func( result->verticesPerCurve()->readable() );
	for ( PrimitiveVariableMap::const_iterator it=result->variables.begin() ; it != result->variables.end(); it++ )
	{
		// only duplicate point and vertex attrib end points
		if ( it->second.interpolation == IECore::PrimitiveVariable::Vertex )
		{
			despatchTypedData<DuplicateEnds, TypeTraits::IsVectorAttribTypedData, DespatchTypedDataIgnoreError>( it->second.data, func );
		}
	}
	
	result->setTopology( new IntVectorData( finalVertsPerCurve ), basis, periodic );
	
	return result;
}
Ejemplo n.º 4
0
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();
}
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?
	const GEO_AttributeHandle attrHandle = geo->getPrimAttribute( "name" );
	if ( attrHandle.isAttributeValid() )
	{
		const GA_ROAttributeRef attrRef( attrHandle.getAttribute() );
		if ( geo->getUniqueValueCount( attrRef ) > 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;
}