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; }
void outputCameras( const ScenePlug *scene, const IECore::CompoundObject *globals, IECore::Renderer *renderer ) { ConstPathMatcherDataPtr cameraSetData = scene->set( "__cameras" ); const PathMatcher &cameraSet = cameraSetData->readable(); // Output all the cameras, skipping the primary one - we need to output this // last, as that's how cortex determines the primary camera. ScenePlug::ScenePath primaryCameraPath; if( const StringData *primaryCameraPathData = globals->member<StringData>( "option:render:camera" ) ) { ScenePlug::stringToPath( primaryCameraPathData->readable(), primaryCameraPath ); } for( PathMatcher::Iterator it = cameraSet.begin(), eIt = cameraSet.end(); it != eIt; ++it ) { if( *it != primaryCameraPath ) { outputCamera( scene, *it, globals, renderer ); } } // Output the primary camera, or a default if it doesn't exist. outputCamera( scene, globals, renderer ); }
GafferScene::ConstPathMatcherDataPtr Group::computeSet( const IECore::InternedString &setName, const Gaffer::Context *context, const ScenePlug *parent ) const { InternedString groupName = namePlug()->getValue(); ConstCompoundObjectPtr mapping = boost::static_pointer_cast<const CompoundObject>( mappingPlug()->getValue() ); const ObjectVector *forwardMappings = mapping->member<ObjectVector>( "__GroupForwardMappings", true /* throw if missing */ ); PathMatcherDataPtr resultData = new PathMatcherData; PathMatcher &result = resultData->writable(); for( size_t i = 0, e = inPlugs()->children().size(); i < e; i++ ) { ConstPathMatcherDataPtr inputSetData = inPlugs()->getChild<ScenePlug>( i )->setPlug()->getValue(); const PathMatcher &inputSet = inputSetData->readable(); const CompoundData *forwardMapping = static_cast<const IECore::CompoundData *>( forwardMappings->members()[i].get() ); /// \todo If PathMatcher allowed access to the internal nodes, and allowed them to be shared between /// matchers, we could be much more efficient here by making a new matcher which referenced the contents /// of the input matchers. vector<InternedString> outputPath; outputPath.push_back( groupName ); for( PathMatcher::Iterator pIt = inputSet.begin(), peIt = inputSet.end(); pIt != peIt; ++pIt ) { const vector<InternedString> &inputPath = *pIt; if( !inputPath.size() ) { continue; } const InternedStringData *outputName = forwardMapping->member<InternedStringData>( inputPath[0] ); if( !outputName ) { // Getting here indicates either a bug in computeMapping() or an inconsistency in one // of our inputs whereby a forward declaration has been made with a name which isn't // in childNames( "/" ). The second case can occur in practice when an input is being // connected or disconnected - because our inputs are CompoundPlugs, part way through // the setInput() process the child connections for globalsPlug() and childNamesPlug() // will not correspond, leading us here. This problem occurs in InteractiveRenderManRenderTest // when the scene is being updated from a plugDirtiedSignal() which is emitted when one // child plug has been disconnected, but before the other one has. The real solution to // this would be to properly batch up dirty signals so that only a single signal is // emitted for the parent after all signals for the children have been emitted. Then we // would only ever be called in a consistent connection state. /// \todo Now we have proper batching of dirty propagation we should remove this workaround, /// reverting to a call to forwardMapping->member<InternedStringData>( inputName, true ), /// which will throw when an error is detected. continue; } outputPath.resize( 2 ); outputPath[1] = outputName->readable(); outputPath.insert( outputPath.end(), inputPath.begin() + 1, inputPath.end() ); result.addPath( outputPath ); } } return resultData; }
void outputClippingPlanes( const ScenePlug *scene, const IECore::CompoundObject *globals, IECore::Renderer *renderer ) { ConstPathMatcherDataPtr clippingPlanesSetData = scene->set( "__clippingPlanes" ); const PathMatcher &clippingPlanesSet = clippingPlanesSetData->readable(); for( PathMatcher::Iterator it = clippingPlanesSet.begin(), eIt = clippingPlanesSet.end(); it != eIt; ++it ) { outputClippingPlane( scene, *it, renderer ); } }
void outputCoordinateSystems( const ScenePlug *scene, const IECore::CompoundObject *globals, IECore::Renderer *renderer ) { ConstPathMatcherDataPtr coordinateSystemSetData = scene->set( "__coordinateSystems" ); const PathMatcher &coordinateSystemSet = coordinateSystemSetData->readable(); for( PathMatcher::Iterator it = coordinateSystemSet.begin(), eIt = coordinateSystemSet.end(); it != eIt; ++it ) { outputCoordinateSystem( scene, *it, renderer ); } }
void outputLights( const ScenePlug *scene, const IECore::CompoundObject *globals, IECore::Renderer *renderer ) { ConstPathMatcherDataPtr lightSetData = scene->set( "__lights" ); const PathMatcher &lightSet = lightSetData->readable(); for( PathMatcher::Iterator it = lightSet.begin(), eIt = lightSet.end(); it != eIt; ++it ) { outputLight( scene, *it, renderer ); } }
GafferScene::ConstPathMatcherDataPtr Set::computeSet( const IECore::InternedString &setName, const Gaffer::Context *context, const ScenePlug *parent ) const { const std::string allSets = " " + namePlug()->getValue() + " "; const std::string setNameToFind = " " + setName.string() + " "; if( allSets.find( setNameToFind ) == std::string::npos ) { return inPlug()->setPlug()->getValue(); } ConstPathMatcherDataPtr pathMatcher = pathMatcherPlug()->getValue(); switch( modePlug()->getValue() ) { case Add : { ConstPathMatcherDataPtr inputSet = inPlug()->setPlug()->getValue(); if( !inputSet->readable().isEmpty() ) { PathMatcherDataPtr result = inputSet->copy(); result->writable().addPaths( pathMatcher->readable() ); return result; } // Input set empty - fall through to create mode. } case Create : { return pathMatcher; } case Remove : default : { ConstPathMatcherDataPtr inputSet = inPlug()->setPlug()->getValue(); if( inputSet->readable().isEmpty() ) { return inputSet; } PathMatcherDataPtr result = inputSet->copy(); result->writable().removePaths( pathMatcher->readable() ); return result; } } }
GafferScene::ConstPathMatcherDataPtr BranchCreator::computeSet( const IECore::InternedString &setName, const Gaffer::Context *context, const ScenePlug *parent ) const { ConstPathMatcherDataPtr inputSetData = inPlug()->set( setName ); ConstCompoundDataPtr mapping = boost::static_pointer_cast<const CompoundData>( mappingPlug()->getValue() ); if( !mapping->readable().size() ) { return inputSetData; } ScenePlug::ScenePath parentPath = mapping->member<InternedStringVectorData>( g_parentKey )->readable(); ConstPathMatcherDataPtr branchSetData = computeBranchSet( parentPath, setName, context ); if( !branchSetData ) { return inputSetData; } const PathMatcher &branchSet = branchSetData->readable(); if( branchSet.isEmpty() ) { return inputSetData; } const CompoundData *forwardMapping = mapping->member<CompoundData>( g_forwardMappingKey ); PathMatcherDataPtr outputSetData = inputSetData->copy(); PathMatcher &outputSet = outputSetData->writable(); vector<InternedString> outputPrefix( parentPath ); for( PathMatcher::RawIterator pIt = branchSet.begin(), peIt = branchSet.end(); pIt != peIt; ++pIt ) { const ScenePlug::ScenePath &branchPath = *pIt; if( !branchPath.size() ) { continue; // Skip root } assert( branchPath.size() == 1 ); const InternedStringData *outputName = forwardMapping->member<InternedStringData>( branchPath[0], /* throwExceptions = */ true ); outputPrefix.resize( parentPath.size() + 1 ); outputPrefix.back() = outputName->readable(); outputSet.addPaths( branchSet.subTree( *pIt ), outputPrefix ); pIt.prune(); // We only want to visit the first level } return outputSetData; }
unsigned PathFilter::computeMatch( const ScenePlug *scene, const Gaffer::Context *context ) const { typedef IECore::TypedData<ScenePlug::ScenePath> ScenePathData; const ScenePathData *pathData = context->get<ScenePathData>( ScenePlug::scenePathContextName, nullptr ); if( pathData ) { // If we have a precomputed PathMatcher, we use that to compute matches, otherwise // we grab the PathMatcher from the intermediate plug (which is a bit more expensive // as it involves graph evaluations): ConstPathMatcherDataPtr pathMatcher = m_pathMatcher ? m_pathMatcher : pathMatcherPlug()->getValue(); return pathMatcher->readable().match( pathData->readable() ); } return NoMatch; }
GafferScene::ConstPathMatcherDataPtr Prune::computeSet( const IECore::InternedString &setName, const Gaffer::Context *context, const ScenePlug *parent ) const { ConstPathMatcherDataPtr inputSetData = inPlug()->setPlug()->getValue(); const PathMatcher &inputSet = inputSetData->readable(); if( inputSet.isEmpty() ) { return inputSetData; } PathMatcherDataPtr outputSetData = inputSetData->copy(); PathMatcher &outputSet = outputSetData->writable(); FilterPlug::SceneScope sceneScope( context, inPlug() ); for( PathMatcher::RawIterator pIt = inputSet.begin(), peIt = inputSet.end(); pIt != peIt; ) { sceneScope.set( ScenePlug::scenePathContextName, *pIt ); const int m = filterPlug()->getValue(); if( m & ( Filter::ExactMatch | Filter::AncestorMatch ) ) { // This path and all below it are pruned, so we can // ignore it and prune the traversal to the descendant // paths. outputSet.prune( *pIt ); pIt.prune(); ++pIt; } else if( m & Filter::DescendantMatch ) { // This path isn't pruned, so we continue our traversal // as normal to find out which descendants _are_ pruned. ++pIt; } else { // This path isn't pruned, and neither is anything // below it. We can avoid retesting the filter for // all descendant paths, since we know they're not // pruned. assert( m == Filter::NoMatch ); pIt.prune(); ++pIt; } } return outputSetData; }
unsigned SetFilter::computeMatch( const ScenePlug *scene, const Gaffer::Context *context ) const { if( !scene ) { return NoMatch; } const ScenePlug::ScenePath &path = context->get<ScenePlug::ScenePath>( ScenePlug::scenePathContextName ); // See explanatory comments in hashMatch(). ContextPtr tmpContext = new Context( *context, Context::Borrowed ); tmpContext->remove( Filter::inputSceneContextName ); tmpContext->remove( ScenePlug::scenePathContextName ); Context::Scope scopedContext( tmpContext.get() ); ConstPathMatcherDataPtr set = scene->set( setPlug()->getValue() ); return set->readable().match( path ); }
GafferScene::ConstPathMatcherDataPtr Isolate::computeSet( const IECore::InternedString &setName, const Gaffer::Context *context, const ScenePlug *parent ) const { ConstPathMatcherDataPtr inputSetData = inPlug()->setPlug()->getValue(); const PathMatcher &inputSet = inputSetData->readable(); if( inputSet.isEmpty() ) { return inputSetData; } PathMatcherDataPtr outputSetData = new PathMatcherData; PathMatcher &outputSet = outputSetData->writable(); ContextPtr tmpContext = filterContext( context ); Context::Scope scopedContext( tmpContext.get() ); const std::string fromString = fromPlug()->getValue(); ScenePlug::ScenePath fromPath; ScenePlug::stringToPath( fromString, fromPath ); for( PathMatcher::RawIterator pIt = inputSet.begin(), peIt = inputSet.end(); pIt != peIt; ) { tmpContext->set( ScenePlug::scenePathContextName, *pIt ); const int m = filterPlug()->getValue(); if( m & ( Filter::ExactMatch | Filter::AncestorMatch ) ) { // We want to keep everything below this point, and // we can speed things up by not checking the filter // for our descendants. PathMatcher::RawIterator next = pIt; next.prune(); ++next; while( pIt != next ) { if( pIt.exactMatch() ) { outputSet.addPath( *pIt ); } ++pIt; } } else if( m & Filter::DescendantMatch ) { // We might be removing things below here, // so just continue our iteration normally // so we can find out. if( pIt.exactMatch() ) { outputSet.addPath( *pIt ); } ++pIt; } else { assert( m == Filter::NoMatch ); if( boost::starts_with( *pIt, fromPath ) ) { // Not going to keep anything below // here, so we can prune traversal // entirely. pIt.prune(); } else if( pIt.exactMatch() ) { outputSet.addPath( *pIt ); } ++pIt; } } return outputSetData; }
void InteractiveRender::outputLightsInternal( const IECore::CompoundObject *globals, bool editing ) { // Get the paths to all the lights ConstPathMatcherDataPtr lightSet = inPlug()->set( "__lights" ); std::vector<std::string> lightPaths; lightSet->readable().paths( lightPaths ); // Create or update lights in the renderer as necessary for( vector<string>::const_iterator it = lightPaths.begin(), eIt = lightPaths.end(); it != eIt; ++it ) { ScenePlug::ScenePath path; ScenePlug::stringToPath( *it, path ); if( !editing ) { // defining the scene for the first time if( outputLight( inPlug(), path, m_renderer.get() ) ) { m_lightHandles.insert( *it ); } } else { if( m_lightHandles.find( *it ) != m_lightHandles.end() ) { // we've already output this light - update it bool visible = false; { EditBlock edit( m_renderer.get(), "light", CompoundDataMap() ); visible = outputLight( inPlug(), path, m_renderer.get() ); } // we may have turned it off before, and need to turn // it back on, or it may have been hidden and we need // to turn it off. { EditBlock edit( m_renderer.get(), "attribute", CompoundDataMap() ); m_renderer->illuminate( *it, visible ); } } else { // we've not seen this light before - create a new one EditBlock edit( m_renderer.get(), "attribute", CompoundDataMap() ); if( outputLight( inPlug(), path, m_renderer.get() ) ) { m_lightHandles.insert( *it ); } } } } // Turn off any lights we don't want any more for( LightHandles::const_iterator it = m_lightHandles.begin(), eIt = m_lightHandles.end(); it != eIt; ++it ) { if( !lightSet || !(lightSet->readable().match( *it ) & Filter::ExactMatch) ) { EditBlock edit( m_renderer.get(), "attribute", CompoundDataMap() ); m_renderer->illuminate( *it, false ); } } }
GafferScene::ConstPathMatcherDataPtr Isolate::computeSet( const IECore::InternedString &setName, const Gaffer::Context *context, const ScenePlug *parent ) const { ConstPathMatcherDataPtr inputSetData = inPlug()->setPlug()->getValue(); if( ( setName == g_lightsSetName && keepLightsPlug()->getValue() ) || ( setName == g_camerasSetName && keepCamerasPlug()->getValue() ) ) { return inputSetData; } const PathMatcher &inputSet = inputSetData->readable(); if( inputSet.isEmpty() ) { return inputSetData; } PathMatcherDataPtr outputSetData = inputSetData->copy(); PathMatcher &outputSet = outputSetData->writable(); FilterPlug::SceneScope sceneScope( context, inPlug() ); const std::string fromString = fromPlug()->getValue(); ScenePlug::ScenePath fromPath; ScenePlug::stringToPath( fromString, fromPath ); const SetsToKeep setsToKeep( this ); for( PathMatcher::RawIterator pIt = inputSet.begin(), peIt = inputSet.end(); pIt != peIt; ) { sceneScope.set( ScenePlug::scenePathContextName, *pIt ); const int m = filterPlug()->getValue() || setsToKeep.match( *pIt ); if( m & ( Filter::ExactMatch | Filter::AncestorMatch ) ) { // We want to keep everything below this point, so // can just prune our iteration. pIt.prune(); ++pIt; } else if( m & Filter::DescendantMatch ) { // We might be removing things below here, // so just continue our iteration normally // so we can find out. ++pIt; } else { assert( m == Filter::NoMatch ); if( boost::starts_with( *pIt, fromPath ) ) { // Not going to keep anything below // here, so we can prune traversal // entirely. outputSet.prune( *pIt ); pIt.prune(); } ++pIt; } } return outputSetData; }