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 ); }
// 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; } }
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() ); } } } }
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; }
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 ); } } } } }
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; }