bool pathFromSelectionIdWalk( GLuint selectionId, ScenePlug::ScenePath &path ) const { if( m_selectionId == selectionId ) { path.push_back( m_name ); return true; } else { for( std::vector<SceneGraph *>::const_iterator it = m_children.begin(), eIt = m_children.end(); it != eIt; ++it ) { /// \todo Should be able to prune recursion based on knowledge that child /// selection ids are always greater than parent selection ids. if( (*it)->pathFromSelectionIdWalk( selectionId, path ) ) { if( m_name != IECore::InternedString() ) { path.push_back( m_name ); } return true; } } } return false; }
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 path( ScenePlug::ScenePath &p ) { if( !m_parent ) { return; } m_parent->path( p ); p.push_back( m_name ); }
void ScenePlug::stringToPath( const std::string &s, ScenePlug::ScenePath &path ) { typedef boost::tokenizer<boost::char_separator<char> > Tokenizer; Tokenizer tokenizer( s, boost::char_separator<char>( "/" ) ); for( Tokenizer::const_iterator it = tokenizer.begin(), eIt = tokenizer.end(); it != eIt; it++ ) { path.push_back( *it ); } }
void operator()( const tbb::blocked_range<int> &range ) const { for( int i=range.begin(); i!=range.end(); ++i ) { ScenePlug::ScenePath childScenePath = m_parent.m_scenePath; childScenePath.push_back( m_childNames[i] ); SceneProceduralPtr sceneProcedural = new SceneProcedural( m_parent, childScenePath ); m_childProcedurals[ i ] = sceneProcedural; } }
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 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 ); } }
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 ); } }
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 GafferScene::SceneAlgo::visible( 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 ) { p.push_back( *it ); pathScope.setPath( p ); ConstCompoundObjectPtr attributes = scene->attributesPlug()->getValue(); const BoolData *visibilityData = attributes->member<BoolData>( "scene:visible" ); if( visibilityData && !visibilityData->readable() ) { return false; } } 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; }
bool GafferScene::visible( 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 ) { p.push_back( *it ); context->set( ScenePlug::scenePathContextName, p ); ConstCompoundObjectPtr attributes = scene->attributesPlug()->getValue(); const BoolData *visibilityData = attributes->member<BoolData>( "scene:visible" ); if( visibilityData && !visibilityData->readable() ) { return false; } } return true; }
void SceneView::expandSelection() { Context::Scope scopedContext( getContext() ); RenderableGadget::Selection &selection = m_renderableGadget->getSelection(); vector<string> pathsToSelect; vector<const string *> pathsToDeselect; IECore::PathMatcherData *expandedData = expandedPaths(); PathMatcher &expanded = expandedData->writable(); bool needUpdate = false; for( RenderableGadget::Selection::const_iterator it = selection.begin(), eIt = selection.end(); it != eIt; it++ ) { if( expanded.addPath( *it ) ) { needUpdate = true; /// \todo Maybe if RenderableGadget used PathMatcher for specifying selection, and /// we had a nice means of getting ScenePaths out of PathMatcher, we wouldn't need /// to do all this string manipulation. typedef boost::tokenizer<boost::char_separator<char> > Tokenizer; Tokenizer pathTokenizer( *it, boost::char_separator<char>( "/" ) ); ScenePlug::ScenePath path; for( Tokenizer::const_iterator pIt = pathTokenizer.begin(), pEIt = pathTokenizer.end(); pIt != pEIt; pIt++ ) { path.push_back( *pIt ); } ConstInternedStringVectorDataPtr childNamesData = preprocessedInPlug<ScenePlug>()->childNames( path ); const vector<InternedString> &childNames = childNamesData->readable(); if( childNames.size() ) { pathsToDeselect.push_back( &(*it) ); for( vector<InternedString>::const_iterator cIt = childNames.begin(), ceIt = childNames.end(); cIt != ceIt; cIt++ ) { if( *(*it).rbegin() != '/' ) { pathsToSelect.push_back( *it + "/" + cIt->string() ); } else { pathsToSelect.push_back( *it + cIt->string() ); } } } } } for( vector<string>::const_iterator it = pathsToSelect.begin(), eIt = pathsToSelect.end(); it != eIt; it++ ) { selection.insert( *it ); } for( vector<const string *>::const_iterator it = pathsToDeselect.begin(), eIt = pathsToDeselect.end(); it != eIt; it++ ) { selection.erase( **it ); } if( needUpdate ) { // we were naughty and modified the expanded paths in place (to avoid // unecessary copying), so the context doesn't know they've changed. // so we emit the changed signal ourselves. this will then trigger update() // via contextChanged(). getContext()->changedSignal()( getContext(), "ui:scene:expandedPaths" ); // and this will trigger a selection update also via contextChanged(). transferSelectionToContext(); } }
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() ); } }
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; }