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