417 lines
12 KiB
C++
417 lines
12 KiB
C++
/* -*-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/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
|
|
|
|
if (child)
|
|
{
|
|
// note ref_ptr<> 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<osg::OccluderNode*>(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())
|
|
{
|
|
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)
|
|
{
|
|
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);
|
|
}
|
|
}
|