/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include #include #include #include #include #include #include using namespace osg; Group::Group() { } Group::Group(const Group& group,const CopyOp& copyop): Node(group,copyop) { for(NodeList::const_iterator itr=group._children.begin(); itr!=group._children.end(); ++itr) { Node* child = copyop(itr->get()); if (child) addChild(child); } } Group::~Group() { // remove reference to this from children's parent lists. for(NodeList::iterator itr=_children.begin(); itr!=_children.end(); ++itr) { (*itr)->removeParent(this); } } void Group::traverse(NodeVisitor& nv) { for(NodeList::iterator itr=_children.begin(); itr!=_children.end(); ++itr) { (*itr)->accept(nv); } } bool Group::addChild( Node *child ) { return Group::insertChild( _children.size(), child ); } bool Group::insertChild( unsigned int index, Node *child ) { if (!child) return false; #if ENSURE_CHILD_IS_UNIQUE if (containsNode(child)) { notify(WARN)<<"Adding non unique child to osg::Group, ignoring call"< automatically handles incrementing child's reference count. if (index >= _children.size()) { _children.push_back(child); } else { _children.insert(_children.begin()+index, child); } // register as parent of child. child->addParent(this); // tell any subclasses that a child has been inserted so that they can update themselves. childInserted(index); dirtyBound(); // could now require app traversal thanks to the new subgraph, // so need to check and update if required. if (child->getNumChildrenRequiringUpdateTraversal()>0 || child->getUpdateCallback()) { setNumChildrenRequiringUpdateTraversal( getNumChildrenRequiringUpdateTraversal()+1 ); } // could now require app traversal thanks to the new subgraph, // so need to check and update if required. if (child->getNumChildrenRequiringEventTraversal()>0 || child->getEventCallback()) { setNumChildrenRequiringEventTraversal( getNumChildrenRequiringEventTraversal()+1 ); } // could now require disabling of culling thanks to the new subgraph, // so need to check and update if required. if (child->getNumChildrenWithCullingDisabled()>0 || !child->getCullingActive()) { setNumChildrenWithCullingDisabled( getNumChildrenWithCullingDisabled()+1 ); } if (child->getNumChildrenWithOccluderNodes()>0 || dynamic_cast(child)) { setNumChildrenWithOccluderNodes( getNumChildrenWithOccluderNodes()+1 ); } return true; } else return false; } bool Group::removeChildren(unsigned int pos,unsigned int numChildrenToRemove) { if (pos<_children.size() && numChildrenToRemove>0) { unsigned int endOfRemoveRange = pos+numChildrenToRemove; if (endOfRemoveRange>_children.size()) { notify(DEBUG_INFO)<<"Warning: Group::removeChild(i,numChildrenToRemove) has been passed an excessive number"<removeParent(this); if (child->getNumChildrenRequiringUpdateTraversal()>0 || child->getUpdateCallback()) ++updateCallbackRemoved; if (child->getNumChildrenRequiringEventTraversal()>0 || child->getEventCallback()) ++eventCallbackRemoved; if (child->getNumChildrenWithCullingDisabled()>0 || !child->getCullingActive()) ++numChildrenWithCullingDisabledRemoved; if (child->getNumChildrenWithOccluderNodes()>0 || dynamic_cast(child)) ++numChildrenWithOccludersRemoved; } childRemoved(pos,endOfRemoveRange-pos); _children.erase(_children.begin()+pos,_children.begin()+endOfRemoveRange); if (updateCallbackRemoved) { setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()-updateCallbackRemoved); } if (eventCallbackRemoved) { setNumChildrenRequiringEventTraversal(getNumChildrenRequiringEventTraversal()-eventCallbackRemoved); } if (numChildrenWithCullingDisabledRemoved) { setNumChildrenWithCullingDisabled(getNumChildrenWithCullingDisabled()-numChildrenWithCullingDisabledRemoved); } if (numChildrenWithOccludersRemoved) { setNumChildrenWithOccluderNodes(getNumChildrenWithOccluderNodes()-numChildrenWithOccludersRemoved); } dirtyBound(); return true; } else return false; } bool Group::replaceChild( Node *origNode, Node *newNode ) { if (newNode==NULL || origNode==newNode) return false; unsigned int pos = getChildIndex(origNode); if (pos<_children.size()) { return setChild(pos,newNode); } return false; } bool Group::setChild( unsigned int i, Node* newNode ) { if (i<_children.size() && newNode) { ref_ptr origNode = _children[i]; // first remove for origNode's parent list. origNode->removeParent(this); // note ref_ptr<> automatically handles decrementing origNode's reference count, // and inccrementing newNode's reference count. _children[i] = newNode; // register as parent of child. newNode->addParent(this); dirtyBound(); // could now require update traversal thanks to the new subgraph, // so need to check and update if required. int delta_numChildrenRequiringUpdateTraversal = 0; if (origNode->getNumChildrenRequiringUpdateTraversal()>0 || origNode->getUpdateCallback()) { --delta_numChildrenRequiringUpdateTraversal; } if (newNode->getNumChildrenRequiringUpdateTraversal()>0 || newNode->getUpdateCallback()) { ++delta_numChildrenRequiringUpdateTraversal; } if (delta_numChildrenRequiringUpdateTraversal!=0) { setNumChildrenRequiringUpdateTraversal( getNumChildrenRequiringUpdateTraversal()+delta_numChildrenRequiringUpdateTraversal ); } // could now require event traversal thanks to the new subgraph, // so need to check and Event if required. int delta_numChildrenRequiringEventTraversal = 0; if (origNode->getNumChildrenRequiringEventTraversal()>0 || origNode->getEventCallback()) { --delta_numChildrenRequiringEventTraversal; } if (newNode->getNumChildrenRequiringEventTraversal()>0 || newNode->getEventCallback()) { ++delta_numChildrenRequiringEventTraversal; } if (delta_numChildrenRequiringEventTraversal!=0) { setNumChildrenRequiringEventTraversal( getNumChildrenRequiringEventTraversal()+delta_numChildrenRequiringEventTraversal ); } // could now require disabling of culling thanks to the new subgraph, // so need to check and update if required. int delta_numChildrenWithCullingDisabled = 0; if (origNode->getNumChildrenWithCullingDisabled()>0 || !origNode->getCullingActive()) { --delta_numChildrenWithCullingDisabled; } if (newNode->getNumChildrenWithCullingDisabled()>0 || !newNode->getCullingActive()) { ++delta_numChildrenWithCullingDisabled; } if (delta_numChildrenWithCullingDisabled!=0) { setNumChildrenWithCullingDisabled( getNumChildrenWithCullingDisabled()+delta_numChildrenWithCullingDisabled ); } // could now require disabling of culling thanks to the new subgraph, // so need to check and update if required. int delta_numChildrenWithOccluderNodes = 0; if (origNode->getNumChildrenWithOccluderNodes()>0 || dynamic_cast(origNode.get())) { --delta_numChildrenWithOccluderNodes; } if (newNode->getNumChildrenWithOccluderNodes()>0 || dynamic_cast(newNode)) { ++delta_numChildrenWithOccluderNodes; } if (delta_numChildrenWithOccluderNodes!=0) { setNumChildrenWithOccluderNodes( getNumChildrenWithOccluderNodes()+delta_numChildrenWithOccluderNodes ); } return true; } else return false; } BoundingSphere Group::computeBound() const { BoundingSphere bsphere; if (_children.empty()) { return bsphere; } // note, special handling of the case when a child is an Transform, // such that only Transforms which are relative to their parents coordinates frame (i.e this group) // are handled, Transform relative to and absolute reference frame are ignored. BoundingBox bb; bb.init(); NodeList::const_iterator itr; for(itr=_children.begin(); itr!=_children.end(); ++itr) { const osg::Transform* transform = (*itr)->asTransform(); if (!transform || transform->getReferenceFrame()==osg::Transform::RELATIVE_RF) { bb.expandBy((*itr)->getBound()); } } if (!bb.valid()) { return bsphere; } bsphere._center = bb.center(); bsphere._radius = 0.0f; for(itr=_children.begin(); itr!=_children.end(); ++itr) { const osg::Transform* transform = (*itr)->asTransform(); if (!transform || transform->getReferenceFrame()==osg::Transform::RELATIVE_RF) { bsphere.expandRadiusBy((*itr)->getBound()); } } return bsphere; } void Group::setThreadSafeRefUnref(bool threadSafe) { Node::setThreadSafeRefUnref(threadSafe); for(NodeList::const_iterator itr=_children.begin(); itr!=_children.end(); ++itr) { (*itr)->setThreadSafeRefUnref(threadSafe); } } void Group::resizeGLObjectBuffers(unsigned int maxSize) { Node::resizeGLObjectBuffers(maxSize); for(NodeList::const_iterator itr=_children.begin(); itr!=_children.end(); ++itr) { (*itr)->resizeGLObjectBuffers(maxSize); } } void Group::releaseGLObjects(osg::State* state) const { Node::releaseGLObjects(state); for(NodeList::const_iterator itr=_children.begin(); itr!=_children.end(); ++itr) { (*itr)->releaseGLObjects(state); } }