osg::Group源码
/* -*-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 <osg/Group> #include <osg/BoundingBox> #include <osg/Transform> #include <osg/OccluderNode> #include <osg/Geometry> #include <osg/Notify> #include <stdio.h> #include <math.h> #include <algorithm> 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)) { OSG_WARN<<"Adding non unique child to osg::Group, ignoring call"<<std::endl; return false; } #endif // handle deprecated geometry configurations by calling fixDeprecatedData(). osg::Geometry* geometry = child->asGeometry(); if (geometry && geometry->containsDeprecatedData()) geometry->fixDeprecatedData(); // note ref_ptr<> automatically handles incrementing child's reference count. if (index >= _children.size()) { index = _children.size(); // set correct index value to be passed to the "childInserted" method _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<osg::OccluderNode*>(child)) { setNumChildrenWithOccluderNodes( getNumChildrenWithOccluderNodes()+1 ); } return true; } unsigned int Group::getNumChildren() const { return static_cast<unsigned int>(_children.size()); } bool Group::removeChild( Node *child ) { unsigned int pos = getChildIndex(child); if (pos<_children.size()) return removeChildren(pos,1); 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()) { OSG_DEBUG<<"Warning: Group::removeChild(i,numChildrenToRemove) has been passed an excessive number"<<std::endl; OSG_DEBUG<<" of chilren to remove, trimming just to end of child list."<<std::endl; endOfRemoveRange=_children.size(); } unsigned int updateCallbackRemoved = 0; unsigned int eventCallbackRemoved = 0; unsigned int numChildrenWithCullingDisabledRemoved = 0; unsigned int numChildrenWithOccludersRemoved = 0; for(unsigned i=pos;i<endOfRemoveRange;++i) { osg::Node* child = _children[i].get(); // remove this Geode from the child parent list. child->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<osg::OccluderNode*>(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<Node> 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<osg::OccluderNode*>(origNode.get())) { --delta_numChildrenWithOccluderNodes; } if (newNode->getNumChildrenWithOccluderNodes()>0 || dynamic_cast<osg::OccluderNode*>(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) { osg::Node* child = itr->get(); const osg::Transform* transform = child->asTransform(); if (!transform || transform->getReferenceFrame()==osg::Transform::RELATIVE_RF) { osg::Drawable* drawable = child->asDrawable(); if (drawable) { bb.expandBy(drawable->getBoundingBox()); } else { const osg::BoundingSphere& bs = child->getBound(); bb.expandBy(bs); } } } if (!bb.valid()) { return bsphere; } bsphere._center = bb.center(); bsphere._radius = 0.0f; for(itr=_children.begin(); itr!=_children.end(); ++itr) { osg::Node* child = itr->get(); const osg::Transform* transform = child->asTransform(); if (!transform || transform->getReferenceFrame()==osg::Transform::RELATIVE_RF) { const BoundingSphere& bs = child->getBound(); bsphere.expandRadiusBy(bs); } } 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); } }