IECore::ConstInternedStringVectorDataPtr DeleteSets::computeSetNames( const Gaffer::Context *context, const ScenePlug *parent ) const { ConstInternedStringVectorDataPtr inputSetNamesData = inPlug()->setNamesPlug()->getValue(); const std::vector<InternedString> &inputSetNames = inputSetNamesData->readable(); if( inputSetNames.empty() ) { return inputSetNamesData; } InternedStringVectorDataPtr outputSetNamesData = new InternedStringVectorData; std::vector<InternedString> &outputSetNames = outputSetNamesData->writable(); const std::string names = namesPlug()->getValue(); const bool invert = invertNamesPlug()->getValue(); for( std::vector<InternedString>::const_iterator it = inputSetNames.begin(); it != inputSetNames.end(); ++it ) { if( StringAlgo::matchMultiple( *it, names ) != (!invert) ) { outputSetNames.push_back( *it ); } } return outputSetNamesData; }
void Prune::hashChildNames( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent, IECore::MurmurHash &h ) const { FilterPlug::SceneScope sceneScope( context, inPlug() ); const Filter::Result m = (Filter::Result)filterPlug()->getValue(); if( m & Filter::ExactMatch ) { h = inPlug()->childNamesPlug()->defaultValue()->Object::hash(); } else if( m & Filter::DescendantMatch ) { // we might be computing new childnames for this level. FilteredSceneProcessor::hashChildNames( path, context, parent, h ); ConstInternedStringVectorDataPtr inputChildNamesData = inPlug()->childNamesPlug()->getValue(); const vector<InternedString> &inputChildNames = inputChildNamesData->readable(); ScenePath childPath = path; childPath.push_back( InternedString() ); // for the child name for( vector<InternedString>::const_iterator it = inputChildNames.begin(), eIt = inputChildNames.end(); it != eIt; ++it ) { childPath[path.size()] = *it; sceneScope.set( ScenePlug::scenePathContextName, childPath ); filterPlug()->hash( h ); } } else { // pass through h = inPlug()->childNamesPlug()->hash(); } }
IECore::ConstInternedStringVectorDataPtr Isolate::computeChildNames( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent ) const { ContextPtr tmpContext = filterContext( context ); Context::Scope scopedContext( tmpContext.get() ); if( mayPruneChildren( path, filterPlug()->getValue() ) ) { // we may need to delete one or more of our children ConstInternedStringVectorDataPtr inputChildNamesData = inPlug()->childNamesPlug()->getValue(); const vector<InternedString> &inputChildNames = inputChildNamesData->readable(); InternedStringVectorDataPtr outputChildNamesData = new InternedStringVectorData; vector<InternedString> &outputChildNames = outputChildNamesData->writable(); ScenePath childPath = path; childPath.push_back( InternedString() ); // for the child name for( vector<InternedString>::const_iterator it = inputChildNames.begin(), eIt = inputChildNames.end(); it != eIt; it++ ) { childPath[path.size()] = *it; tmpContext->set( ScenePlug::scenePathContextName, childPath ); if( filterPlug()->getValue() != Filter::NoMatch ) { outputChildNames.push_back( *it ); } } return outputChildNamesData; } else { // pass through return inPlug()->childNamesPlug()->getValue(); } }
IECore::MurmurHash SceneNode::hashOfTransformedChildBounds( const ScenePath &path, const ScenePlug *out, const IECore::InternedStringVectorData *childNamesData ) const { ConstInternedStringVectorDataPtr computedChildNames; if( !childNamesData ) { computedChildNames = out->childNames( path ); childNamesData = computedChildNames.get(); } const vector<InternedString> &childNames = childNamesData->readable(); IECore::MurmurHash result; if( childNames.size() ) { ContextPtr tmpContext = new Context( *Context::current(), Context::Borrowed ); Context::Scope scopedContext( tmpContext.get() ); ScenePath childPath( path ); childPath.push_back( InternedString() ); // room for the child name for( vector<InternedString>::const_iterator it = childNames.begin(); it != childNames.end(); it++ ) { childPath[path.size()] = *it; tmpContext->set( ScenePlug::scenePathContextName, childPath ); out->boundPlug()->hash( result ); out->transformPlug()->hash( result ); } } else { result.append( typeId() ); result.append( "emptyBound" ); } return result; }
GafferScene::ConstPathMatcherDataPtr Duplicate::computeBranchSet( const ScenePath &parentPath, const IECore::InternedString &setName, const Gaffer::Context *context ) const { ConstPathMatcherDataPtr inputSetData = inPlug()->set( setName ); const PathMatcher &inputSet = inputSetData->readable(); if( inputSet.isEmpty() ) { return outPlug()->setPlug()->defaultValue(); } PathMatcher subTree = inputSet.subTree( targetPlug()->getValue() ); if( subTree.isEmpty() ) { return outPlug()->setPlug()->defaultValue(); } ConstInternedStringVectorDataPtr childNamesData = childNamesPlug()->getValue(); const vector<InternedString> &childNames = childNamesData->readable(); PathMatcherDataPtr resultData = new PathMatcherData; PathMatcher &result = resultData->writable(); ScenePath prefix( 1 ); for( vector<InternedString>::const_iterator it = childNames.begin(), eIt = childNames.end(); it != eIt; ++it ) { prefix.back() = *it; result.addPaths( subTree, prefix ); } return resultData; }
Imath::Box3f SceneNode::unionOfTransformedChildBounds( const ScenePath &path, const ScenePlug *out, const IECore::InternedStringVectorData *childNamesData ) const { ConstInternedStringVectorDataPtr computedChildNames; if( !childNamesData ) { computedChildNames = out->childNames( path ); childNamesData = computedChildNames.get(); } const vector<InternedString> &childNames = childNamesData->readable(); Box3f result; if( childNames.size() ) { ContextPtr tmpContext = new Context( *Context::current(), Context::Borrowed ); Context::Scope scopedContext( tmpContext.get() ); ScenePath childPath( path ); childPath.push_back( InternedString() ); // room for the child name for( vector<InternedString>::const_iterator it = childNames.begin(); it != childNames.end(); it++ ) { childPath[path.size()] = *it; tmpContext->set( ScenePlug::scenePathContextName, childPath ); Box3f childBound = out->boundPlug()->getValue(); childBound = transform( childBound, out->transformPlug()->getValue() ); result.extendBy( childBound ); } } return result; }
virtual task *execute() { ContextPtr context = new Context( *m_context ); context->set( ScenePlug::scenePathContextName, m_scenePath ); Context::Scope scopedContext( context ); m_scenePlug->transformPlug()->getValue(); m_scenePlug->boundPlug()->getValue(); m_scenePlug->attributesPlug()->getValue(); m_scenePlug->objectPlug()->getValue(); ConstInternedStringVectorDataPtr childNamesData = m_scenePlug->childNamesPlug()->getValue(); const vector<InternedString> &childNames = childNamesData->readable(); set_ref_count( 1 + childNames.size() ); ScenePlug::ScenePath childPath = m_scenePath; childPath.push_back( InternedString() ); // space for the child name for( vector<InternedString>::const_iterator it = childNames.begin(), eIt = childNames.end(); it != eIt; it++ ) { childPath[m_scenePath.size()] = *it; SceneTraversalTask *t = new( allocate_child() ) SceneTraversalTask( m_scenePlug, m_context, childPath ); spawn( *t ); } wait_for_all(); return 0; }
void Duplicate::compute( ValuePlug *output, const Context *context ) const { if( output == outParentPlug() ) { ScenePath target; ScenePlug::stringToPath( targetPlug()->getValue(), target ); string parent; for( size_t i = 0; i < target.size(); ++i ) { parent += "/"; if( i < target.size() - 1 ) { parent += target[i]; } } static_cast<StringPlug *>( output )->setValue( parent ); return; } else if( output == childNamesPlug() ) { // get the path to our target. ScenePath target; ScenePlug::stringToPath( targetPlug()->getValue(), target ); // throw if the target path doesn't exist in the input. we need to compute the input child names at the // parent for this, but it's not necessary to represent that in the hash, because it doesn't actually // affect our result (if we throw we will have no result). ScenePath parent( target ); parent.pop_back(); ConstInternedStringVectorDataPtr parentChildNamesData = inPlug()->childNames( parent ); vector<InternedString> parentChildNames = parentChildNamesData->readable(); if( find( parentChildNames.begin(), parentChildNames.end(), target.back() ) == parentChildNames.end() ) { throw Exception( boost::str( boost::format( "Target \"%s\" does not exist" ) % target.back().string() ) ); } // go ahead and generate our childnames by incrementing a numeric suffix on // the target name. std::string stem; int suffix = numericSuffix( target.back(), 0, &stem ); InternedStringVectorDataPtr childNames = new InternedStringVectorData; boost::format formatter( "%s%d" ); int copies = copiesPlug()->getValue(); for( int i = 0; i < copies; ++i ) { childNames->writable().push_back( boost::str( formatter % stem % ++suffix ) ); } static_cast<InternedStringVectorDataPlug *>( output )->setValue( childNames ); return; } BranchCreator::compute( output, context ); }
void SceneWriter::writeLocation( const GafferScene::ScenePlug *scene, const ScenePlug::ScenePath &scenePath, Context *context, IECore::SceneInterface *output, double time ) const { context->set( ScenePlug::scenePathContextName, scenePath ); ConstCompoundObjectPtr attributes = scene->attributesPlug()->getValue(); for( CompoundObject::ObjectMap::const_iterator it = attributes->members().begin(), eIt = attributes->members().end(); it != eIt; it++ ) { output->writeAttribute( it->first, it->second.get(), time ); } if( scenePath.empty() ) { ConstCompoundObjectPtr globals = scene->globalsPlug()->getValue(); output->writeAttribute( "gaffer:globals", globals.get(), time ); } ConstObjectPtr object = scene->objectPlug()->getValue(); if( object->typeId() != IECore::NullObjectTypeId && scenePath.size() > 0 ) { output->writeObject( object.get(), time ); } Imath::Box3f b = scene->boundPlug()->getValue(); output->writeBound( Imath::Box3d( Imath::V3f( b.min ), Imath::V3f( b.max ) ), time ); if( scenePath.size() ) { Imath::M44f t = scene->transformPlug()->getValue(); Imath::M44d transform( t[0][0], t[0][1], t[0][2], t[0][3], t[1][0], t[1][1], t[1][2], t[1][3], t[2][0], t[2][1], t[2][2], t[2][3], t[3][0], t[3][1], t[3][2], t[3][3] ); output->writeTransform( new IECore::M44dData( transform ), time ); } ConstInternedStringVectorDataPtr childNames = scene->childNamesPlug()->getValue(); ScenePlug::ScenePath childScenePath = scenePath; childScenePath.push_back( InternedString() ); for( vector<InternedString>::const_iterator it=childNames->readable().begin(); it!=childNames->readable().end(); it++ ) { childScenePath[scenePath.size()] = *it; SceneInterfacePtr outputChild = output->child( *it, SceneInterface::CreateIfMissing ); writeLocation( scene, childScenePath, context, outputChild.get(), time ); } }
void ScenePath::doChildren( std::vector<PathPtr> &children ) const { Context::Scope scopedContext( m_context.get() ); ConstInternedStringVectorDataPtr childNamesData = m_scene->childNames( names() ); const std::vector<InternedString> &childNames = childNamesData->readable(); ScenePlug::ScenePath childPath( names() ); childPath.push_back( InternedString() ); // for the child name children.reserve( childNames.size() ); for( std::vector<InternedString>::const_iterator it = childNames.begin(), eIt = childNames.end(); it != eIt; ++it ) { childPath.back() = *it; children.push_back( new ScenePath( m_scene, m_context, childPath, root(), const_cast<PathFilter *>( getFilter() ) ) ); } }
void SetVisualiser::compute( Gaffer::ValuePlug *output, const Gaffer::Context *context ) const { if( output == outSetsPlug() ) { const StringAlgo::MatchPattern requestedSetsPattern = setsPlug()->getValue(); std::vector<InternedString> names; std::vector<Color3f> colors; if( !requestedSetsPattern.empty() ) { const std::vector<Override> overrides = unpackOverrides( colorOverridesPlug() ); ConstInternedStringVectorDataPtr allSetNamesData = inPlug()->setNames(); // Sorting now makes everything easier, otherwise you have to // sort parallel arrays later, which is a pain. std::vector<InternedString> allNames = allSetNamesData->readable(); std::sort( allNames.begin(), allNames.end(), internedStringCompare ); for( auto &name : allNames ) { // Gaffer has some internal sets that begin with the '__' // prefix. These are usually Lights, Cameras, etc... We filter // these out as they most of their objects don't even draw in // the viewer in a meaningful way for visualising set Membership if( boost::starts_with( name.string(), "__" ) ) { continue; } if( StringAlgo::matchMultiple( name, requestedSetsPattern ) ) { names.push_back( name ); colors.push_back( colorForSetName( name, overrides ) ); } } } CompoundDataPtr data = new CompoundData(); data->writable()["names"] = new InternedStringVectorData( names ); data->writable()["colors"] = new Color3fVectorData( colors ); static_cast<AtomicCompoundDataPlug *>( output )->setValue( data ); } else { SceneElementProcessor::compute( output, context ); } }
bool SceneView::expandWalk( const std::string &path, size_t depth, PathMatcher &expanded, RenderableGadget::Selection &selected ) { bool result = false; ScenePlug::ScenePath scenePath; ScenePlug::stringToPath( path, scenePath ); ConstInternedStringVectorDataPtr childNamesData = preprocessedInPlug<ScenePlug>()->childNames( scenePath ); const vector<InternedString> &childNames = childNamesData->readable(); if( childNames.size() ) { // expand ourselves to show our children, and make sure we're // not selected - we only want selection at the leaf levels of // our expansion. result |= expanded.addPath( path ); result |= selected.erase( path ); for( vector<InternedString>::const_iterator cIt = childNames.begin(), ceIt = childNames.end(); cIt != ceIt; cIt++ ) { std::string childPath( path ); if( *childPath.rbegin() != '/' ) { childPath += '/'; } childPath += cIt->string(); if( depth == 1 ) { // at the bottom of the expansion - just select the child result |= selected.insert( childPath ).second; } else { // continue the expansion result |= expandWalk( childPath, depth - 1, expanded, selected ); } } } else { // we have no children, just make sure we're selected to mark the // leaf of the expansion. result |= selected.insert( path ).second; } return result; }
IECore::ConstInternedStringVectorDataPtr Set::computeSetNames( const Gaffer::Context *context, const ScenePlug *parent ) const { ConstInternedStringVectorDataPtr inNamesData = inPlug()->setNamesPlug()->getValue(); const std::string &names = namePlug()->getValue(); if( !names.size() ) { return inNamesData; } if( modePlug()->getValue() == Remove ) { return inNamesData; } vector<InternedString> tokenizedNames; StringAlgo::tokenize( names, ' ', tokenizedNames ); // specific logic if we have only one item, to avoid the more complex logic of adding two lists together if( tokenizedNames.size() == 1 ) { const std::vector<InternedString> &inNames = inNamesData->readable(); if( std::find( inNames.begin(), inNames.end(), tokenizedNames[0] ) != inNames.end() ) { return inNamesData; } InternedStringVectorDataPtr resultData = inNamesData->copy(); resultData->writable().push_back( tokenizedNames[0] ); return resultData; } // inserting the new names into the vector // while making sure we don't have duplicates InternedStringVectorDataPtr resultData = inNamesData->copy(); std::vector<InternedString> &result = resultData->writable(); result.reserve( result.size() + tokenizedNames.size() ); std::copy( tokenizedNames.begin(), tokenizedNames.end(), std::back_inserter( result ) ); std::sort( result.begin(), result.end() ); std::vector<InternedString>::iterator it; it = std::unique( result.begin(), result.end() ); result.resize( std::distance( result.begin(), it ) ); return resultData; }
IECore::ConstCompoundDataPtr GafferScene::sets( const ScenePlug *scene ) { ConstInternedStringVectorDataPtr setNamesData = scene->setNamesPlug()->getValue(); std::vector<GafferScene::ConstPathMatcherDataPtr> setsVector; setsVector.resize( setNamesData->readable().size(), NULL ); Sets setsCompute( scene, setNamesData->readable(), setsVector ); parallel_for( tbb::blocked_range<size_t>( 0, setsVector.size() ), setsCompute ); CompoundDataPtr result = new CompoundData; for( size_t i = 0, e = setsVector.size(); i < e; ++i ) { // The const_pointer_cast is ok because we're just using it to put the set into // a container that will be const on return - we never modify the set itself. result->writable()[setNamesData->readable()[i]] = boost::const_pointer_cast<GafferScene::PathMatcherData>( setsVector[i] ); } return result; }
void InteractiveRender::updateShadersWalk( const ScenePlug::ScenePath &path ) { /// \todo Keep a track of the hashes of the shaders at each path, /// and use it to only update the shaders when they've changed. ConstCompoundObjectPtr attributes = inPlug()->attributes( path ); // terminate recursion for invisible locations ConstBoolDataPtr visibility = attributes->member<BoolData>( SceneInterface::visibilityName ); if( visibility && ( !visibility->readable() ) ) { return; } ConstObjectVectorPtr shader = attributes->member<ObjectVector>( "shader" ); if( shader ) { std::string name; ScenePlug::pathToString( path, name ); CompoundDataMap parameters; parameters["exactscopename"] = new StringData( name ); { EditBlock edit( m_renderer.get(), "attribute", parameters ); for( ObjectVector::MemberContainer::const_iterator it = shader->members().begin(), eIt = shader->members().end(); it != eIt; it++ ) { const StateRenderable *s = runTimeCast<const StateRenderable>( it->get() ); if( s ) { s->render( m_renderer.get() ); } } } } ConstInternedStringVectorDataPtr childNames = inPlug()->childNames( path ); ScenePlug::ScenePath childPath = path; childPath.push_back( InternedString() ); // for the child name for( vector<InternedString>::const_iterator it=childNames->readable().begin(); it!=childNames->readable().end(); it++ ) { childPath[path.size()] = *it; updateShadersWalk( childPath ); } }
Imath::M44f Duplicate::computeBranchTransform( const ScenePath &parentPath, const ScenePath &branchPath, const Gaffer::Context *context ) const { ScenePath source; sourcePath( branchPath, source ); Imath::M44f result = inPlug()->transform( source ); if( branchPath.size() == 1 ) { const Imath::M44f matrix = transformPlug()->matrix(); ConstInternedStringVectorDataPtr childNamesData = childNamesPlug()->getValue(); const vector<InternedString> &childNames = childNamesData->readable(); size_t i = 0; do { result = result * matrix; } while( i < childNames.size() && branchPath[0] != childNames[i++] ); } return result; }
void SetVisualiser::hashProcessedAttributes( const ScenePath &path, const Gaffer::Context *context, MurmurHash &h ) const { ConstCompoundDataPtr outSetsData = outSetsPlug()->getValue(); outSetsData->hash( h ); includeInheritedPlug()->hash( h ); // We also need to consider each of our candidate sets membership // definition (which we didn't need to when computing outSets). // outSetsData is map of names -> colors. ConstInternedStringVectorDataPtr setNames = outSetsData->member<InternedStringVectorData>( "names" ); for( auto &setName : setNames->readable() ) { h.append( inPlug()->setHash( setName ) ); } h.append( path.data(), path.size() ); stripeWidthPlug()->hash( h ); }
bool GafferScene::SceneAlgo::exists( const ScenePlug *scene, const ScenePlug::ScenePath &path ) { ScenePlug::PathScope pathScope( Context::current() ); ScenePlug::ScenePath p; p.reserve( path.size() ); for( ScenePlug::ScenePath::const_iterator it = path.begin(), eIt = path.end(); it != eIt; ++it ) { pathScope.setPath( p ); ConstInternedStringVectorDataPtr childNamesData = scene->childNamesPlug()->getValue(); const vector<InternedString> &childNames = childNamesData->readable(); if( find( childNames.begin(), childNames.end(), *it ) == childNames.end() ) { return false; } p.push_back( *it ); } return true; }
bool GafferScene::exists( const ScenePlug *scene, const ScenePlug::ScenePath &path ) { ContextPtr context = new Context( *Context::current(), Context::Borrowed ); Context::Scope scopedContext( context.get() ); ScenePlug::ScenePath p; p.reserve( path.size() ); for( ScenePlug::ScenePath::const_iterator it = path.begin(), eIt = path.end(); it != eIt; ++it ) { context->set( ScenePlug::scenePathContextName, p ); ConstInternedStringVectorDataPtr childNamesData = scene->childNamesPlug()->getValue(); const vector<InternedString> &childNames = childNamesData->readable(); if( find( childNames.begin(), childNames.end(), *it ) == childNames.end() ) { return false; } p.push_back( *it ); } return true; }
bool SceneView::expandWalk( const GafferScene::ScenePlug::ScenePath &path, size_t depth, PathMatcher &expanded, PathMatcher &selected ) { bool result = false; ConstInternedStringVectorDataPtr childNamesData = preprocessedInPlug<ScenePlug>()->childNames( path ); const vector<InternedString> &childNames = childNamesData->readable(); if( childNames.size() ) { // expand ourselves to show our children, and make sure we're // not selected - we only want selection at the leaf levels of // our expansion. result |= expanded.addPath( path ); result |= selected.removePath( path ); ScenePlug::ScenePath childPath = path; childPath.push_back( InternedString() ); // room for the child name for( vector<InternedString>::const_iterator cIt = childNames.begin(), ceIt = childNames.end(); cIt != ceIt; cIt++ ) { childPath.back() = *cIt; if( depth == 1 ) { // at the bottom of the expansion - just select the child result |= selected.addPath( childPath ); } else { // continue the expansion result |= expandWalk( childPath, depth - 1, expanded, selected ); } } } else { // we have no children, just make sure we're selected to mark the // leaf of the expansion. result |= selected.addPath( path ); } return result; }
void Isolate::hashChildNames( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent, IECore::MurmurHash &h ) const { const SetsToKeep setsToKeep( this ); FilterPlug::SceneScope sceneScope( context, inPlug() ); if( mayPruneChildren( path, filterPlug()->getValue(), setsToKeep ) ) { // we might be computing new childnames for this level. FilteredSceneProcessor::hashChildNames( path, context, parent, h ); const IECore::MurmurHash inputChildNamesHash = inPlug()->childNamesPlug()->hash(); h.append( inputChildNamesHash ); ConstInternedStringVectorDataPtr inputChildNamesData = inPlug()->childNamesPlug()->getValue( &inputChildNamesHash ); const vector<InternedString> &inputChildNames = inputChildNamesData->readable(); ScenePath childPath = path; childPath.push_back( InternedString() ); // for the child name for( vector<InternedString>::const_iterator it = inputChildNames.begin(), eIt = inputChildNames.end(); it != eIt; ++it ) { childPath[path.size()] = *it; const unsigned m = setsToKeep.match( childPath ); if( m == Filter::NoMatch ) { sceneScope.set( ScenePlug::scenePathContextName, childPath ); filterPlug()->hash( h ); } else { h.append( 0 ); } } } else { // pass through h = inPlug()->childNamesPlug()->hash(); } }
IECore::ConstInternedStringVectorDataPtr Group::computeSetNames( const Gaffer::Context *context, const ScenePlug *parent ) const { InternedStringVectorDataPtr resultData = new InternedStringVectorData; vector<InternedString> &result = resultData->writable(); for( ScenePlugIterator it( inPlugs() ); it != it.end(); ++it ) { // This naive approach to merging set names preserves the order of the incoming names, // but at the expense of using linear search. We assume that the number of sets is small // enough and the InternedString comparison fast enough that this is OK. ConstInternedStringVectorDataPtr inputSetNamesData = (*it)->setNamesPlug()->getValue(); const vector<InternedString> &inputSetNames = inputSetNamesData->readable(); for( vector<InternedString>::const_iterator it = inputSetNames.begin(), eIt = inputSetNames.end(); it != eIt; ++it ) { if( std::find( result.begin(), result.end(), *it ) == result.end() ) { result.push_back( *it ); } } } return resultData; }
IECore::ConstInternedStringVectorDataPtr BranchCreator::computeSetNames( const Gaffer::Context *context, const ScenePlug *parent ) const { ConstInternedStringVectorDataPtr inputSetNamesData = inPlug()->setNamesPlug()->getValue(); ConstCompoundDataPtr mapping = boost::static_pointer_cast<const CompoundData>( mappingPlug()->getValue() ); if( !mapping->readable().size() ) { return inputSetNamesData; } ConstInternedStringVectorDataPtr branchSetNamesData = computeBranchSetNames( mapping->member<InternedStringVectorData>( g_parentKey )->readable(), context ); if( !branchSetNamesData ) { return inputSetNamesData; } const vector<InternedString> &branchSetNames = branchSetNamesData->readable(); if( !branchSetNames.size() ) { return inputSetNamesData; } InternedStringVectorDataPtr resultData = inputSetNamesData->copy(); vector<InternedString> &result = resultData->writable(); // This naive approach to merging set names preserves the order of the incoming names, // but at the expense of using linear search. We assume that the number of sets is small // enough and the InternedString comparison fast enough that this is OK. for( vector<InternedString>::const_iterator it = branchSetNames.begin(), eIt = branchSetNames.end(); it != eIt; ++it ) { if( std::find( result.begin(), result.end(), *it ) == result.end() ) { result.push_back( *it ); } } return resultData; }
IECore::ConstInternedStringVectorDataPtr Prune::computeChildNames( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent ) const { FilterPlug::SceneScope sceneScope( context, inPlug() ); const Filter::Result m = (Filter::Result)filterPlug()->getValue(); if( m & Filter::ExactMatch ) { return inPlug()->childNamesPlug()->defaultValue(); } else if( m & Filter::DescendantMatch ) { // we may need to delete one or more of our children ConstInternedStringVectorDataPtr inputChildNamesData = inPlug()->childNamesPlug()->getValue(); const vector<InternedString> &inputChildNames = inputChildNamesData->readable(); InternedStringVectorDataPtr outputChildNamesData = new InternedStringVectorData; vector<InternedString> &outputChildNames = outputChildNamesData->writable(); ScenePath childPath = path; childPath.push_back( InternedString() ); // for the child name for( vector<InternedString>::const_iterator it = inputChildNames.begin(), eIt = inputChildNames.end(); it != eIt; ++it ) { childPath[path.size()] = *it; sceneScope.set( ScenePlug::scenePathContextName, childPath ); if( !(filterPlug()->getValue() & Filter::ExactMatch) ) { outputChildNames.push_back( *it ); } } return outputChildNamesData; } else { // pass through return inPlug()->childNamesPlug()->getValue(); } }
/// \todo This mapping is very similar to the one created by the Group node. Perhaps /// some generalisation of the two could form the basis for a nice unified HierarchyProcessor? /// In this case I think we would have a custom mapping class rather than just pass around /// CompoundData, and then parentAndBranchPaths() (or the future version of it) could be a method /// on the mapping object. IECore::ConstCompoundDataPtr BranchCreator::computeMapping( const Gaffer::Context *context ) const { // get the parent. currently this is simply retrieving the value of parentPlug(), // but if we wanted to support multiple parents in future, here we would find the // parent appropriate to the current "scene:path" context entry. /// \todo We should introduce a plug type which stores its values as a ScenePath directly. ScenePlug::ScenePath parent; string parentAsString = parentPlug()->getValue(); if( parentAsString.empty() ) { // no parent specified so no mapping needed return static_cast<const CompoundData *>( mappingPlug()->defaultValue() ); } ScenePlug::stringToPath( parentAsString, parent ); // see if we're interested in creating children or not. if we're not // we can early out. no innuendo intended. ConstInternedStringVectorDataPtr branchChildNamesData = computeBranchChildNames( parent, ScenePath(), context ); if( !branchChildNamesData->readable().size() ) { return static_cast<const CompoundData *>( mappingPlug()->defaultValue() ); } // create our result. in future it might be useful to create our datatype for this, // but for now we're just packing everything into a CompoundData. CompoundDataPtr result = new CompoundData; result->writable()["__BranchCreatorParent"] = new InternedStringVectorData( parent ); // calculate the child names for the result. this is the full list of child names // immediately below the parent. we need to be careful to ensure that we rename any // branch names which conflict with existing children of the parent. ConstInternedStringVectorDataPtr inChildNamesData = inPlug()->childNames( parent ); InternedStringVectorDataPtr childNamesData = new InternedStringVectorData(); const vector<InternedString> &inChildNames = inChildNamesData->readable(); const vector<InternedString> &branchChildNames = branchChildNamesData->readable(); vector<InternedString> &childNames = childNamesData->writable(); result->writable()["__BranchCreatorChildNames"] = childNamesData; set<InternedString> allNames; for( vector<InternedString>::const_iterator it = inChildNames.begin(); it != inChildNames.end(); ++it ) { allNames.insert( *it ); childNames.push_back( *it ); } boost::regex namePrefixSuffixRegex( "^(.*[^0-9]+)([0-9]+)$" ); boost::format namePrefixSuffixFormatter( "%s%d" ); for( vector<InternedString>::const_iterator it = branchChildNames.begin(); it != branchChildNames.end(); ++it ) { InternedString name = *it; if( allNames.find( name ) != allNames.end() ) { // uniqueify the name string prefix = name; int suffix = 1; boost::cmatch match; if( regex_match( name.value().c_str(), match, namePrefixSuffixRegex ) ) { prefix = match[1]; suffix = boost::lexical_cast<int>( match[2] ); } do { name = boost::str( namePrefixSuffixFormatter % prefix % suffix ); suffix++; } while( allNames.find( name ) != allNames.end() ); } allNames.insert( name ); childNames.push_back( name ); result->writable()[name] = new InternedStringData( *it ); } return result; }
void SceneProcedural::render( Renderer *renderer ) const { tbb::task_scheduler_init tsi( tbb::task_scheduler_init::deferred ); initializeTaskScheduler( tsi ); Context::Scope scopedContext( m_context.get() ); std::string name; ScenePlug::pathToString( m_scenePath, name ); /// \todo See above. try { // get all the attributes, and early out if we're not visibile const BoolData *visibilityData = m_attributesObject->member<BoolData>( g_visibleAttributeName ); if( visibilityData && !visibilityData->readable() ) { if( !m_rendered ) { decrementPendingProcedurals(); } m_rendered = true; return; } // if we are visible then make an attribute block to contain everything, set the name // and get on with generating things. AttributeBlock attributeBlock( renderer ); renderer->setAttribute( "name", new StringData( name ) ); // transform std::set<float> transformTimes; motionTimes( ( m_options.transformBlur && m_attributes.transformBlur ) ? m_attributes.transformBlurSegments : 0, transformTimes ); { ContextPtr timeContext = new Context( *m_context, Context::Borrowed ); Context::Scope scopedTimeContext( timeContext.get() ); MotionBlock motionBlock( renderer, transformTimes, transformTimes.size() > 1 ); for( std::set<float>::const_iterator it = transformTimes.begin(), eIt = transformTimes.end(); it != eIt; it++ ) { timeContext->setFrame( *it ); renderer->concatTransform( m_scenePlug->transformPlug()->getValue() ); } } // attributes outputAttributes( m_attributesObject.get(), renderer ); // object std::set<float> deformationTimes; motionTimes( ( m_options.deformationBlur && m_attributes.deformationBlur ) ? m_attributes.deformationBlurSegments : 0, deformationTimes ); { ContextPtr timeContext = new Context( *m_context, Context::Borrowed ); Context::Scope scopedTimeContext( timeContext.get() ); unsigned timeIndex = 0; for( std::set<float>::const_iterator it = deformationTimes.begin(), eIt = deformationTimes.end(); it != eIt; it++, timeIndex++ ) { timeContext->setFrame( *it ); ConstObjectPtr object = m_scenePlug->objectPlug()->getValue(); if( const Primitive *primitive = runTimeCast<const Primitive>( object.get() ) ) { if( deformationTimes.size() > 1 && timeIndex == 0 ) { renderer->motionBegin( deformationTimes ); } primitive->render( renderer ); if( deformationTimes.size() > 1 && timeIndex == deformationTimes.size() - 1 ) { renderer->motionEnd(); } } else if( const VisibleRenderable* renderable = runTimeCast< const VisibleRenderable >( object.get() ) ) { renderable->render( renderer ); break; // no motion blur for these chappies. } } } // children ConstInternedStringVectorDataPtr childNames = m_scenePlug->childNamesPlug()->getValue(); if( childNames->readable().size() ) { // Creating a SceneProcedural involves an attribute/bound evaluation, which are // potentially expensive, so we're parallelizing them. // allocate space for child procedurals: SceneProceduralCreate::SceneProceduralContainer childProcedurals( childNames->readable().size() ); // create procedurals in parallel: SceneProceduralCreate s( childProcedurals, *this, childNames->readable() ); tbb::parallel_for( tbb::blocked_range<int>( 0, childNames->readable().size() ), s ); // send to the renderer in series: std::vector<SceneProceduralPtr>::const_iterator procIt = childProcedurals.begin(), procEit = childProcedurals.end(); for( ; procIt != procEit; ++procIt ) { renderer->procedural( *procIt ); } } } catch( const std::exception &e ) { IECore::msg( IECore::Msg::Error, "SceneProcedural::render() " + name, e.what() ); } if( !m_rendered ) { decrementPendingProcedurals(); } m_rendered = true; }
void SceneProcedural::render( RendererPtr renderer ) const { Context::Scope scopedContext( m_context ); /// \todo See above. try { // get all the attributes, and early out if we're not visibile ConstCompoundObjectPtr attributes = m_scenePlug->attributesPlug()->getValue(); const BoolData *visibilityData = attributes->member<BoolData>( "gaffer:visibility" ); if( visibilityData && !visibilityData->readable() ) { return; } // if we are visible then make an attribute block to contain everything, set the name // and get on with generating things. AttributeBlock attributeBlock( renderer ); std::string name = ""; for( ScenePlug::ScenePath::const_iterator it = m_scenePath.begin(), eIt = m_scenePath.end(); it != eIt; it++ ) { name += "/" + it->string(); } renderer->setAttribute( "name", new StringData( name ) ); // transform std::set<float> transformTimes; motionTimes( ( m_options.transformBlur && m_attributes.transformBlur ) ? m_attributes.transformBlurSegments : 0, transformTimes ); { ContextPtr timeContext = new Context( *m_context ); Context::Scope scopedTimeContext( timeContext ); MotionBlock motionBlock( renderer, transformTimes, transformTimes.size() > 1 ); for( std::set<float>::const_iterator it = transformTimes.begin(), eIt = transformTimes.end(); it != eIt; it++ ) { timeContext->setFrame( *it ); renderer->concatTransform( m_scenePlug->transformPlug()->getValue() ); } } // attributes for( CompoundObject::ObjectMap::const_iterator it = attributes->members().begin(), eIt = attributes->members().end(); it != eIt; it++ ) { if( const StateRenderable *s = runTimeCast<const StateRenderable>( it->second.get() ) ) { s->render( renderer ); } else if( const ObjectVector *o = runTimeCast<const ObjectVector>( it->second.get() ) ) { for( ObjectVector::MemberContainer::const_iterator it = o->members().begin(), eIt = o->members().end(); it != eIt; it++ ) { const StateRenderable *s = runTimeCast<const StateRenderable>( it->get() ); if( s ) { s->render( renderer ); } } } else if( const Data *d = runTimeCast<const Data>( it->second.get() ) ) { renderer->setAttribute( it->first, d ); } } // object std::set<float> deformationTimes; motionTimes( ( m_options.deformationBlur && m_attributes.deformationBlur ) ? m_attributes.deformationBlurSegments : 0, deformationTimes ); { ContextPtr timeContext = new Context( *m_context ); Context::Scope scopedTimeContext( timeContext ); unsigned timeIndex = 0; for( std::set<float>::const_iterator it = deformationTimes.begin(), eIt = deformationTimes.end(); it != eIt; it++, timeIndex++ ) { timeContext->setFrame( *it ); ConstObjectPtr object = m_scenePlug->objectPlug()->getValue(); if( const Primitive *primitive = runTimeCast<const Primitive>( object.get() ) ) { if( deformationTimes.size() > 1 && timeIndex == 0 ) { renderer->motionBegin( deformationTimes ); } primitive->render( renderer ); if( deformationTimes.size() > 1 && timeIndex == deformationTimes.size() - 1 ) { renderer->motionEnd(); } } else if( const Camera *camera = runTimeCast<const Camera>( object.get() ) ) { /// \todo This absolutely does not belong here, but until we have /// a mechanism for drawing manipulators, we don't have any other /// means of visualising the cameras. if( renderer->isInstanceOf( "IECoreGL::Renderer" ) ) { drawCamera( camera, renderer.get() ); } break; // no motion blur for these chappies. } else if( const Light *light = runTimeCast<const Light>( object.get() ) ) { /// \todo This doesn't belong here. if( renderer->isInstanceOf( "IECoreGL::Renderer" ) ) { drawLight( light, renderer.get() ); } break; // no motion blur for these chappies. } else if( const VisibleRenderable* renderable = runTimeCast< const VisibleRenderable >( object.get() ) ) { renderable->render( renderer ); break; // no motion blur for these chappies. } } } // children ConstInternedStringVectorDataPtr childNames = m_scenePlug->childNamesPlug()->getValue(); if( childNames->readable().size() ) { bool expand = true; if( m_pathsToExpand ) { expand = m_pathsToExpand->readable().match( m_scenePath ) & Filter::ExactMatch; } if( !expand ) { renderer->setAttribute( "gl:primitive:wireframe", new BoolData( true ) ); renderer->setAttribute( "gl:primitive:solid", new BoolData( false ) ); renderer->setAttribute( "gl:curvesPrimitive:useGLLines", new BoolData( true ) ); Box3f b = m_scenePlug->boundPlug()->getValue(); CurvesPrimitive::createBox( b )->render( renderer ); } else { ScenePlug::ScenePath childScenePath = m_scenePath; childScenePath.push_back( InternedString() ); // for the child name for( vector<InternedString>::const_iterator it=childNames->readable().begin(); it!=childNames->readable().end(); it++ ) { childScenePath[m_scenePath.size()] = *it; renderer->setAttribute( "name", new StringData( *it ) ); renderer->procedural( new SceneProcedural( *this, childScenePath ) ); } } } } catch( const std::exception &e ) { IECore::msg( IECore::Msg::Error, "SceneProcedural::render()", e.what() ); } }
void Duplicate::compute( ValuePlug *output, const Context *context ) const { if( output == outParentPlug() ) { ScenePath target; ScenePlug::stringToPath( targetPlug()->getValue(), target ); string parent; for( size_t i = 0; i < target.size(); ++i ) { parent += "/"; if( i < target.size() - 1 ) { parent += target[i]; } } static_cast<StringPlug *>( output )->setValue( parent ); return; } else if( output == childNamesPlug() ) { // get the path to our target. ScenePath target; ScenePlug::stringToPath( targetPlug()->getValue(), target ); // throw if the target path doesn't exist in the input. we need to compute the input child names at the // parent for this, but it's not necessary to represent that in the hash, because it doesn't actually // affect our result (if we throw we will have no result). ScenePath parent( target ); parent.pop_back(); ConstInternedStringVectorDataPtr parentChildNamesData = inPlug()->childNames( parent ); vector<InternedString> parentChildNames = parentChildNamesData->readable(); if( find( parentChildNames.begin(), parentChildNames.end(), target.back() ) == parentChildNames.end() ) { throw Exception( boost::str( boost::format( "Target \"%s\" does not exist" ) % target.back().string() ) ); } // go ahead and generate our childnames. // these are composed of a stem and possibly // a numeric suffix. we default to deriving // these from the name of the target. std::string stem; int suffix = StringAlgo::numericSuffix( target.back(), 0, &stem ); suffix++; const int copies = copiesPlug()->getValue(); const std::string name = namePlug()->getValue(); // if a name is provided explicitly, then // it overrides the name and suffix derived // from the target. if( name.size() ) { std::string nameStem; const int nameSuffix = StringAlgo::numericSuffix( name, &nameStem ); stem = nameStem; suffix = copies == 1 ? nameSuffix : max( nameSuffix, 1 ); } InternedStringVectorDataPtr childNamesData = new InternedStringVectorData; std::vector<InternedString> &childNames = childNamesData->writable(); childNames.reserve( copies ); if( suffix == -1 ) { assert( copies == 1 ); childNames.push_back( stem ); } else { boost::format formatter( "%s%d" ); for( int i = 0; i < copies; ++i ) { childNames.push_back( boost::str( formatter % stem % suffix++ ) ); } } static_cast<InternedStringVectorDataPlug *>( output )->setValue( childNamesData ); return; } BranchCreator::compute( output, context ); }
SceneInterfacePtr LinkedScene::scene( const Path &path, MissingBehaviour missingBehaviour ) { if ( missingBehaviour == SceneInterface::CreateIfMissing ) { throw Exception( "createIfMissing is not supported!" ); } SceneInterfacePtr s = m_mainScene->scene( SceneInterface::rootPath ); Path::const_iterator pIt; /// first try to get as close as possible using the m_mainScene... for ( pIt = path.begin(); pIt != path.end(); pIt++ ) { SceneInterfacePtr n = s->child( *pIt, SceneInterface::NullIfMissing ); if ( !n ) { break; } s = n; } ConstSceneInterfacePtr l = 0; int linkDepth = 0; bool atLink = false; bool timeRemapped = false; if ( s->hasAttribute( fileNameLinkAttribute ) && s->hasAttribute( rootLinkAttribute ) ) { atLink = true; timeRemapped = s->hasAttribute( timeLinkAttribute ); ConstStringDataPtr fileName = runTimeCast< const StringData >( s->readAttribute( fileNameLinkAttribute, 0 ) ); ConstInternedStringVectorDataPtr root = runTimeCast< const InternedStringVectorData >( s->readAttribute( rootLinkAttribute, 0 ) ); l = expandLink( fileName.get(), root.get(), linkDepth ); if (!l) { atLink = false; timeRemapped = false; } } else if( s->hasAttribute( linkAttribute ) ) { atLink = true; ConstCompoundDataPtr d = runTimeCast< const CompoundData >( s->readAttribute( linkAttribute, 0 ) ); l = expandLink( d->member< const StringData >( g_fileName ), d->member< const InternedStringVectorData >( g_root ), linkDepth ); if ( !l ) { atLink = false; } } if ( pIt != path.end() ) { if ( !atLink ) { if ( missingBehaviour == SceneInterface::NullIfMissing ) { return 0; } throw Exception( "Could not find child '" + pIt->value() + "'" ); } for ( ; pIt != path.end(); pIt++ ) { l = l->child( *pIt, missingBehaviour ); if ( !l ) { return 0; } } atLink = false; } return new LinkedScene( s, l, linkDepth, m_readOnly, atLink, timeRemapped ); }
IECore::ObjectPtr Group::computeMapping( const Gaffer::Context *context ) const { /// \todo It might be more optimal to make our own Object subclass better tailored /// for passing the information we want. CompoundObjectPtr result = new CompoundObject(); InternedStringVectorDataPtr childNamesData = new InternedStringVectorData(); vector<InternedString> &childNames = childNamesData->writable(); result->members()["__GroupChildNames"] = childNamesData; ObjectVectorPtr forwardMappings = new ObjectVector; result->members()["__GroupForwardMappings"] = forwardMappings; boost::regex namePrefixSuffixRegex( "^(.*[^0-9]+)([0-9]+)$" ); boost::format namePrefixSuffixFormatter( "%s%d" ); set<InternedString> allNames; for( ScenePlugIterator it( inPlugs() ); it != it.end(); ++it ) { ConstInternedStringVectorDataPtr inChildNamesData = (*it)->childNames( ScenePath() ); CompoundDataPtr forwardMapping = new CompoundData; forwardMappings->members().push_back( forwardMapping ); const vector<InternedString> &inChildNames = inChildNamesData->readable(); for( vector<InternedString>::const_iterator cIt = inChildNames.begin(), ceIt = inChildNames.end(); cIt!=ceIt; cIt++ ) { InternedString name = *cIt; if( allNames.find( name ) != allNames.end() ) { // uniqueify the name /// \todo This code is almost identical to code in GraphComponent::setName(), /// is there a sensible place it can be shared? The primary obstacle is that /// each use has a different method of storing the existing names. string prefix = name; int suffix = 1; boost::cmatch match; if( regex_match( name.value().c_str(), match, namePrefixSuffixRegex ) ) { prefix = match[1]; suffix = boost::lexical_cast<int>( match[2] ); } do { name = boost::str( namePrefixSuffixFormatter % prefix % suffix ); suffix++; } while( allNames.find( name ) != allNames.end() ); } allNames.insert( name ); childNames.push_back( name ); forwardMapping->writable()[*cIt] = new InternedStringData( name ); CompoundObjectPtr entry = new CompoundObject; entry->members()["n"] = new InternedStringData( *cIt ); entry->members()["i"] = new IntData( it.base() - inPlugs()->children().begin() ); result->members()[name] = entry; } } return result; }