void applySelectionWalk( const PathMatcher &selection, const ScenePlug::ScenePath &path, bool check ) { const unsigned m = check ? selection.match( path ) : 0; m_selected = m & Filter::ExactMatch; ScenePlug::ScenePath childPath = path; childPath.push_back( IECore::InternedString() ); // space for the child name for( std::vector<SceneGraph *>::const_iterator it = m_children.begin(), eIt = m_children.end(); it != eIt; ++it ) { childPath.back() = (*it)->m_name; (*it)->applySelectionWalk( selection, childPath, m & Filter::DescendantMatch ); } }
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; }
virtual task *execute() { ContextPtr context = new Context( *m_context, Context::Borrowed ); context->set( ScenePlug::scenePathContextName, m_scenePath ); Context::Scope scopedContext( context.get() ); // we need the attributes so we can terminate recursion at invisible locations, so // we might as well store them in the scene graph, along with the hash: m_sceneGraph->m_attributesHash = m_scene->attributesPlug()->hash(); // use the precomputed hash in getValue() to save a bit of time: m_sceneGraph->m_attributes = m_scene->attributesPlug()->getValue( &m_sceneGraph->m_attributesHash ); const BoolData *visibilityData = m_sceneGraph->m_attributes->member<BoolData>( SceneInterface::visibilityName ); if( visibilityData && !visibilityData->readable() ) { // terminate recursion for invisible locations return NULL; } // store the hash of the child names so we know when they change: m_sceneGraph->m_childNamesHash = m_scene->childNamesPlug()->hash(); // compute child names: IECore::ConstInternedStringVectorDataPtr childNamesData = m_scene->childNamesPlug()->getValue( &m_sceneGraph->m_childNamesHash ); std::vector<IECore::InternedString> childNames = childNamesData->readable(); if( childNames.empty() ) { // nothing more to do return NULL; } // sort the child names so we can compare child name lists easily in ChildNamesUpdateTask: std::sort( childNames.begin(), childNames.end() ); // add children for this location: std::vector<InteractiveRender::SceneGraph *> children; for( std::vector<IECore::InternedString>::const_iterator it = childNames.begin(), eIt = childNames.end(); it != eIt; ++it ) { SceneGraph *child = new SceneGraph(); child->m_name = *it; child->m_parent = m_sceneGraph; children.push_back( child ); } // spawn child tasks: set_ref_count( 1 + children.size() ); ScenePlug::ScenePath childPath = m_scenePath; childPath.push_back( IECore::InternedString() ); // space for the child name for( std::vector<SceneGraph *>::const_iterator it = children.begin(), eIt = children.end(); it != eIt; ++it ) { childPath.back() = (*it)->m_name; SceneGraphBuildTask *t = new( allocate_child() ) SceneGraphBuildTask( m_scene, m_context, (*it), childPath ); spawn( *t ); } wait_for_all(); // add visible children to m_sceneGraph->m_children: for( std::vector<SceneGraph *>::const_iterator it = children.begin(), eIt = children.end(); it != eIt; ++it ) { const BoolData *visibilityData = (*it)->m_attributes->member<BoolData>( SceneInterface::visibilityName ); if( visibilityData && !visibilityData->readable() ) { continue; } m_sceneGraph->m_children.push_back( *it ); } return NULL; }
virtual task *execute() { ContextPtr context = new Context( *m_context, Context::Borrowed ); context->set( ScenePlug::scenePathContextName, m_scenePath ); Context::Scope scopedContext( context.get() ); IECore::MurmurHash childNamesHash = m_scene->childNamesPlug()->hash(); if( childNamesHash != m_sceneGraph->m_childNamesHash ) { // child names have changed - we need to update m_locationPresent on the children: m_sceneGraph->m_childNamesHash = childNamesHash; // read updated child names: IECore::ConstInternedStringVectorDataPtr childNamesData = m_scene->childNamesPlug()->getValue( &m_sceneGraph->m_childNamesHash ); std::vector<IECore::InternedString> childNames = childNamesData->readable(); // m_sceneGraph->m_children should be sorted by name. Sort this list too so we can // compare the two easily: std::sort( childNames.begin(), childNames.end() ); std::vector<InternedString>::iterator childNamesBegin = childNames.begin(); for( std::vector<SceneGraph *>::const_iterator it = m_sceneGraph->m_children.begin(), eIt = m_sceneGraph->m_children.end(); it != eIt; ++it ) { // try and find the current child name in the list of child names: std::vector<InternedString>::iterator nameIt = std::find( childNamesBegin, childNames.end(), (*it)->m_name ); if( nameIt != childNames.end() ) { // ok, it's there - mark this child as still present (*it)->m_locationPresent = true; // As both the name lists are sorted, no further child names will be found beyond nameIt // in the list, nor will they be found at nameIt as there shouldn't be any duplicates. // This means we can move the start of the child names list one position past nameIt // to save a bit of time: /// \todo Note that if all the children have changed names, we never end up in here, and /// we will end up with quadratic behaviour calling find (a linear search N times). childNamesBegin = nameIt; ++childNamesBegin; } else { (*it)->m_locationPresent = false; } } } // count children currently present in the scene: size_t numPresentChildren = 0; for( std::vector<SceneGraph *>::const_iterator it = m_sceneGraph->m_children.begin(), eIt = m_sceneGraph->m_children.end(); it != eIt; ++it ) { numPresentChildren += (*it)->m_locationPresent; } // spawn child tasks: set_ref_count( 1 + numPresentChildren ); ScenePlug::ScenePath childPath = m_scenePath; childPath.push_back( IECore::InternedString() ); // space for the child name for( std::vector<SceneGraph *>::const_iterator it = m_sceneGraph->m_children.begin(), eIt = m_sceneGraph->m_children.end(); it != eIt; ++it ) { if( (*it)->m_locationPresent ) { childPath.back() = (*it)->m_name; ChildNamesUpdateTask *t = new( allocate_child() ) ChildNamesUpdateTask( m_scene, m_context, (*it), childPath ); spawn( *t ); } } wait_for_all(); return NULL; }
virtual task *execute() { ScenePlug::PathScope pathScope( m_sceneGadget->m_context.get(), m_scenePath ); // Update attributes, and compute visibility. const bool previouslyVisible = m_sceneGraph->m_visible; if( m_dirtyFlags & AttributesDirty ) { const IECore::MurmurHash attributesHash = m_sceneGadget->m_scene->attributesPlug()->hash(); if( attributesHash != m_sceneGraph->m_attributesHash ) { IECore::ConstCompoundObjectPtr attributes = m_sceneGadget->m_scene->attributesPlug()->getValue( &attributesHash ); const IECore::BoolData *visibilityData = attributes->member<IECore::BoolData>( "scene:visible" ); m_sceneGraph->m_visible = visibilityData ? visibilityData->readable() : true; IECore::ConstRunTimeTypedPtr glStateCachedTyped = IECoreGL::CachedConverter::defaultCachedConverter()->convert( attributes.get() ); IECoreGL::ConstStatePtr glStateCached = IECore::runTimeCast<const IECoreGL::State>( glStateCachedTyped ); IECoreGL::ConstStatePtr visState = NULL; deferReferenceRemoval( m_sceneGraph->m_attributesRenderable ); m_sceneGraph->m_attributesRenderable = AttributeVisualiser::allVisualisations( attributes.get(), visState ); deferReferenceRemoval( m_sceneGraph->m_state ); if( visState ) { IECoreGL::StatePtr glState = new IECoreGL::State( *glStateCached ); glState->add( const_cast< IECoreGL::State* >( visState.get() ) ); m_sceneGraph->m_state = glState; } else { m_sceneGraph->m_state = glStateCached; } m_sceneGraph->m_attributesHash = attributesHash; } } if( !m_sceneGraph->m_visible ) { // No need to update further since we're not visible. return NULL; } else if( !previouslyVisible ) { // We didn't perform any updates when we were invisible, // so we need to update everything now. m_dirtyFlags = AllDirty; } // Update the object - converting it into an IECoreGL::Renderable if( m_dirtyFlags & ObjectDirty ) { const IECore::MurmurHash objectHash = m_sceneGadget->m_scene->objectPlug()->hash(); if( objectHash != m_sceneGraph->m_objectHash ) { IECore::ConstObjectPtr object = m_sceneGadget->m_scene->objectPlug()->getValue( &objectHash ); deferReferenceRemoval( m_sceneGraph->m_renderable ); if( !object->isInstanceOf( IECore::NullObjectTypeId ) ) { m_sceneGraph->m_renderable = objectToRenderable( object.get() ); } m_sceneGraph->m_objectHash = objectHash; } } // Update the transform and bound if( m_dirtyFlags & TransformDirty ) { m_sceneGraph->m_transform = m_sceneGadget->m_scene->transformPlug()->getValue(); } m_sceneGraph->m_bound = m_sceneGraph->m_renderable ? m_sceneGraph->m_renderable->bound() : Box3f(); // Update the expansion state const bool previouslyExpanded = m_sceneGraph->m_expanded; if( m_dirtyFlags & ExpansionDirty ) { m_sceneGraph->m_expanded = m_sceneGadget->m_minimumExpansionDepth >= m_scenePath.size(); if( !m_sceneGraph->m_expanded ) { m_sceneGraph->m_expanded = m_sceneGadget->m_expandedPaths->readable().match( m_scenePath ) & Filter::ExactMatch; } } // If we're not expanded, then we can early out after creating a bounding box. deferReferenceRemoval( m_sceneGraph->m_boundRenderable ); if( !m_sceneGraph->m_expanded ) { // We're not expanded, so we early out before updating the children. // We do however need to see if we have any children, and arrange to // draw their bounding box if we do. bool haveChildren = m_sceneGraph->m_children.size(); if( m_dirtyFlags & ChildNamesDirty || !previouslyExpanded ) { IECore::ConstInternedStringVectorDataPtr childNamesData = m_sceneGadget->m_scene->childNamesPlug()->getValue(); haveChildren = childNamesData->readable().size(); } m_sceneGraph->clearChildren(); m_sceneGraph->m_bound.extendBy( m_sceneGadget->m_scene->boundPlug()->getValue() ); if( haveChildren ) { IECore::CurvesPrimitivePtr curvesBound = IECore::CurvesPrimitive::createBox( m_sceneGraph->m_bound ); m_sceneGraph->m_boundRenderable = boost::static_pointer_cast<const IECoreGL::Renderable>( IECoreGL::CachedConverter::defaultCachedConverter()->convert( curvesBound.get() ) ); } return NULL; } // We are expanded, so we need to visit all the children // and update those too. if( !previouslyExpanded ) { m_dirtyFlags = AllDirty; } // Make sure we have a child for each child name if( m_dirtyFlags & ChildNamesDirty ) { IECore::ConstInternedStringVectorDataPtr childNamesData = m_sceneGadget->m_scene->childNamesPlug()->getValue(); const std::vector<IECore::InternedString> &childNames = childNamesData->readable(); if( !existingChildNamesValid( childNames ) ) { m_sceneGraph->clearChildren(); for( std::vector<IECore::InternedString>::const_iterator it = childNames.begin(), eIt = childNames.end(); it != eIt; ++it ) { SceneGraph *child = new SceneGraph(); child->m_name = *it; m_sceneGraph->m_children.push_back( child ); } m_dirtyFlags = AllDirty; // We've made brand new children, so they need a full update. } } // And then update each child if( m_sceneGraph->m_children.size() ) { set_ref_count( 1 + m_sceneGraph->m_children.size() ); ScenePlug::ScenePath childPath = m_scenePath; childPath.push_back( IECore::InternedString() ); // space for the child name for( std::vector<SceneGraph *>::const_iterator it = m_sceneGraph->m_children.begin(), eIt = m_sceneGraph->m_children.end(); it != eIt; ++it ) { childPath.back() = (*it)->m_name; UpdateTask *t = new( allocate_child() ) UpdateTask( m_sceneGadget, *it, m_dirtyFlags, childPath ); spawn( *t ); } wait_for_all(); } // Finally compute our bound from the child bounds. for( std::vector<SceneGraph *>::const_iterator it = m_sceneGraph->m_children.begin(), eIt = m_sceneGraph->m_children.end(); it != eIt; ++it ) { const Box3f childBound = transform( (*it)->m_bound, (*it)->m_transform ); m_sceneGraph->m_bound.extendBy( childBound ); } return NULL; }