1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version.  The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * OpenSceneGraph Public License for more details.
12 */
13 
14 #include <osg/Group>
15 #include <osg/BoundingBox>
16 #include <osg/Transform>
17 #include <osg/OccluderNode>
18 #include <osg/Geometry>
19 #include <osg/Notify>
20 
21 #include <stdio.h>
22 #include <math.h>
23 
24 #include <algorithm>
25 
26 using namespace osg;
27 
Group()28 Group::Group()
29 {
30 }
31 
Group(const Group & group,const CopyOp & copyop)32 Group::Group(const Group& group,const CopyOp& copyop):
33     Node(group,copyop)
34 {
35     for(NodeList::const_iterator itr=group._children.begin();
36         itr!=group._children.end();
37         ++itr)
38     {
39         Node* child = copyop(itr->get());
40         if (child) addChild(child);
41     }
42 }
43 
~Group()44 Group::~Group()
45 {
46     // remove reference to this from children's parent lists.
47     for(NodeList::iterator itr=_children.begin();
48         itr!=_children.end();
49         ++itr)
50     {
51         (*itr)->removeParent(this);
52     }
53 
54 }
55 
56 
traverse(NodeVisitor & nv)57 void Group::traverse(NodeVisitor& nv)
58 {
59     for(NodeList::iterator itr=_children.begin();
60         itr!=_children.end();
61         ++itr)
62     {
63         (*itr)->accept(nv);
64     }
65 }
66 
67 
addChild(Node * child)68 bool Group::addChild( Node *child )
69 {
70     return Group::insertChild( _children.size(), child );
71 }
72 
insertChild(unsigned int index,Node * child)73 bool Group::insertChild( unsigned int index, Node *child )
74 {
75     if (!child) return false;
76 
77 #if ENSURE_CHILD_IS_UNIQUE
78     if (containsNode(child))
79     {
80         OSG_WARN<<"Adding non unique child to osg::Group, ignoring call"<<std::endl;
81         return false;
82     }
83 #endif
84 
85     // handle deprecated geometry configurations by calling fixDeprecatedData().
86     osg::Geometry* geometry = child->asGeometry();
87     if (geometry && geometry->containsDeprecatedData()) geometry->fixDeprecatedData();
88 
89 
90     // note ref_ptr<> automatically handles incrementing child's reference count.
91     if (index >= _children.size())
92     {
93         index = _children.size();      // set correct index value to be passed to the "childInserted" method
94         _children.push_back(child);
95     }
96     else
97     {
98         _children.insert(_children.begin()+index, child);
99     }
100 
101     // register as parent of child.
102     child->addParent(this);
103 
104     // tell any subclasses that a child has been inserted so that they can update themselves.
105     childInserted(index);
106 
107     dirtyBound();
108 
109     // could now require app traversal thanks to the new subgraph,
110     // so need to check and update if required.
111     if (child->getNumChildrenRequiringUpdateTraversal()>0 ||
112         child->getUpdateCallback())
113     {
114         setNumChildrenRequiringUpdateTraversal(
115             getNumChildrenRequiringUpdateTraversal()+1
116             );
117     }
118 
119     // could now require app traversal thanks to the new subgraph,
120     // so need to check and update if required.
121     if (child->getNumChildrenRequiringEventTraversal()>0 ||
122         child->getEventCallback())
123     {
124         setNumChildrenRequiringEventTraversal(
125             getNumChildrenRequiringEventTraversal()+1
126             );
127     }
128 
129     // could now require disabling of culling thanks to the new subgraph,
130     // so need to check and update if required.
131     if (child->getNumChildrenWithCullingDisabled()>0 ||
132         !child->getCullingActive())
133     {
134         setNumChildrenWithCullingDisabled(
135             getNumChildrenWithCullingDisabled()+1
136             );
137     }
138 
139     if (child->getNumChildrenWithOccluderNodes()>0 ||
140         dynamic_cast<osg::OccluderNode*>(child))
141     {
142         setNumChildrenWithOccluderNodes(
143             getNumChildrenWithOccluderNodes()+1
144             );
145     }
146 
147     return true;
148 }
149 
getNumChildren() const150 unsigned int Group::getNumChildren() const
151 {
152     return static_cast<unsigned int>(_children.size());
153 }
154 
155 
removeChild(Node * child)156 bool Group::removeChild( Node *child )
157 {
158     unsigned int pos = getChildIndex(child);
159     if (pos<_children.size()) return removeChildren(pos,1);
160     else return false;
161 }
162 
163 
removeChildren(unsigned int pos,unsigned int numChildrenToRemove)164 bool Group::removeChildren(unsigned int pos,unsigned int numChildrenToRemove)
165 {
166     if (pos<_children.size() && numChildrenToRemove>0)
167     {
168         unsigned int endOfRemoveRange = pos+numChildrenToRemove;
169         if (endOfRemoveRange>_children.size())
170         {
171             OSG_DEBUG<<"Warning: Group::removeChild(i,numChildrenToRemove) has been passed an excessive number"<<std::endl;
172             OSG_DEBUG<<"         of chilren to remove, trimming just to end of child list."<<std::endl;
173             endOfRemoveRange=_children.size();
174         }
175 
176         unsigned int updateCallbackRemoved = 0;
177         unsigned int eventCallbackRemoved = 0;
178         unsigned int numChildrenWithCullingDisabledRemoved = 0;
179         unsigned int numChildrenWithOccludersRemoved = 0;
180 
181         for(unsigned i=pos;i<endOfRemoveRange;++i)
182         {
183             osg::Node* child = _children[i].get();
184             // remove this Geode from the child parent list.
185             child->removeParent(this);
186 
187             if (child->getNumChildrenRequiringUpdateTraversal()>0 || child->getUpdateCallback()) ++updateCallbackRemoved;
188 
189             if (child->getNumChildrenRequiringEventTraversal()>0 || child->getEventCallback()) ++eventCallbackRemoved;
190 
191             if (child->getNumChildrenWithCullingDisabled()>0 || !child->getCullingActive()) ++numChildrenWithCullingDisabledRemoved;
192 
193             if (child->getNumChildrenWithOccluderNodes()>0 || dynamic_cast<osg::OccluderNode*>(child)) ++numChildrenWithOccludersRemoved;
194 
195         }
196 
197         childRemoved(pos,endOfRemoveRange-pos);
198 
199         _children.erase(_children.begin()+pos,_children.begin()+endOfRemoveRange);
200 
201         if (updateCallbackRemoved)
202         {
203             setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()-updateCallbackRemoved);
204         }
205 
206         if (eventCallbackRemoved)
207         {
208             setNumChildrenRequiringEventTraversal(getNumChildrenRequiringEventTraversal()-eventCallbackRemoved);
209         }
210 
211         if (numChildrenWithCullingDisabledRemoved)
212         {
213             setNumChildrenWithCullingDisabled(getNumChildrenWithCullingDisabled()-numChildrenWithCullingDisabledRemoved);
214         }
215 
216         if (numChildrenWithOccludersRemoved)
217         {
218             setNumChildrenWithOccluderNodes(getNumChildrenWithOccluderNodes()-numChildrenWithOccludersRemoved);
219         }
220 
221         dirtyBound();
222 
223         return true;
224     }
225     else return false;
226 }
227 
228 
replaceChild(Node * origNode,Node * newNode)229 bool Group::replaceChild( Node *origNode, Node *newNode )
230 {
231     if (newNode==NULL || origNode==newNode) return false;
232 
233     unsigned int pos = getChildIndex(origNode);
234     if (pos<_children.size())
235     {
236         return setChild(pos,newNode);
237     }
238     return false;
239 }
240 
241 
setChild(unsigned int i,Node * newNode)242 bool Group::setChild( unsigned  int i, Node* newNode )
243 {
244     if (i<_children.size() && newNode)
245     {
246 
247         ref_ptr<Node> origNode = _children[i];
248 
249         // first remove for origNode's parent list.
250         origNode->removeParent(this);
251 
252         // note ref_ptr<> automatically handles decrementing origNode's reference count,
253         // and inccrementing newNode's reference count.
254         _children[i] = newNode;
255 
256         // register as parent of child.
257         newNode->addParent(this);
258 
259         dirtyBound();
260 
261 
262         // could now require update traversal thanks to the new subgraph,
263         // so need to check and update if required.
264         int delta_numChildrenRequiringUpdateTraversal = 0;
265         if (origNode->getNumChildrenRequiringUpdateTraversal()>0 ||
266             origNode->getUpdateCallback())
267         {
268             --delta_numChildrenRequiringUpdateTraversal;
269         }
270         if (newNode->getNumChildrenRequiringUpdateTraversal()>0 ||
271             newNode->getUpdateCallback())
272         {
273             ++delta_numChildrenRequiringUpdateTraversal;
274         }
275 
276         if (delta_numChildrenRequiringUpdateTraversal!=0)
277         {
278             setNumChildrenRequiringUpdateTraversal(
279                 getNumChildrenRequiringUpdateTraversal()+delta_numChildrenRequiringUpdateTraversal
280                 );
281         }
282 
283         // could now require event traversal thanks to the new subgraph,
284         // so need to check and Event if required.
285         int delta_numChildrenRequiringEventTraversal = 0;
286         if (origNode->getNumChildrenRequiringEventTraversal()>0 ||
287             origNode->getEventCallback())
288         {
289             --delta_numChildrenRequiringEventTraversal;
290         }
291         if (newNode->getNumChildrenRequiringEventTraversal()>0 ||
292             newNode->getEventCallback())
293         {
294             ++delta_numChildrenRequiringEventTraversal;
295         }
296 
297         if (delta_numChildrenRequiringEventTraversal!=0)
298         {
299             setNumChildrenRequiringEventTraversal(
300                 getNumChildrenRequiringEventTraversal()+delta_numChildrenRequiringEventTraversal
301                 );
302         }
303 
304         // could now require disabling of culling thanks to the new subgraph,
305         // so need to check and update if required.
306         int delta_numChildrenWithCullingDisabled = 0;
307         if (origNode->getNumChildrenWithCullingDisabled()>0 ||
308             !origNode->getCullingActive())
309         {
310             --delta_numChildrenWithCullingDisabled;
311         }
312         if (newNode->getNumChildrenWithCullingDisabled()>0 ||
313             !newNode->getCullingActive())
314         {
315             ++delta_numChildrenWithCullingDisabled;
316         }
317 
318         if (delta_numChildrenWithCullingDisabled!=0)
319         {
320             setNumChildrenWithCullingDisabled(
321                 getNumChildrenWithCullingDisabled()+delta_numChildrenWithCullingDisabled
322                 );
323         }
324 
325         // could now require disabling of culling thanks to the new subgraph,
326         // so need to check and update if required.
327         int delta_numChildrenWithOccluderNodes = 0;
328         if (origNode->getNumChildrenWithOccluderNodes()>0 ||
329             dynamic_cast<osg::OccluderNode*>(origNode.get()))
330         {
331             --delta_numChildrenWithOccluderNodes;
332         }
333         if (newNode->getNumChildrenWithOccluderNodes()>0 ||
334             dynamic_cast<osg::OccluderNode*>(newNode))
335         {
336             ++delta_numChildrenWithOccluderNodes;
337         }
338 
339         if (delta_numChildrenWithOccluderNodes!=0)
340         {
341             setNumChildrenWithOccluderNodes(
342                 getNumChildrenWithOccluderNodes()+delta_numChildrenWithOccluderNodes
343                 );
344         }
345 
346         return true;
347     }
348     else return false;
349 
350 }
351 
computeBound() const352 BoundingSphere Group::computeBound() const
353 {
354     BoundingSphere bsphere;
355     if (_children.empty())
356     {
357         return bsphere;
358     }
359 
360     // note, special handling of the case when a child is an Transform,
361     // such that only Transforms which are relative to their parents coordinates frame (i.e this group)
362     // are handled, Transform relative to and absolute reference frame are ignored.
363 
364     BoundingBox bb;
365     bb.init();
366     NodeList::const_iterator itr;
367     for(itr=_children.begin();
368         itr!=_children.end();
369         ++itr)
370     {
371         osg::Node* child = itr->get();
372         const osg::Transform* transform = child->asTransform();
373         if (!transform || transform->getReferenceFrame()==osg::Transform::RELATIVE_RF)
374         {
375             osg::Drawable* drawable = child->asDrawable();
376             if (drawable)
377             {
378                 bb.expandBy(drawable->getBoundingBox());
379             }
380             else
381             {
382                 const osg::BoundingSphere& bs = child->getBound();
383                 bb.expandBy(bs);
384             }
385         }
386     }
387 
388     if (!bb.valid())
389     {
390         return bsphere;
391     }
392 
393     bsphere._center = bb.center();
394     bsphere._radius = 0.0f;
395     for(itr=_children.begin();
396         itr!=_children.end();
397         ++itr)
398     {
399         osg::Node* child = itr->get();
400         const osg::Transform* transform = child->asTransform();
401         if (!transform || transform->getReferenceFrame()==osg::Transform::RELATIVE_RF)
402         {
403             const BoundingSphere& bs = child->getBound();
404             bsphere.expandRadiusBy(bs);
405         }
406     }
407 
408     return bsphere;
409 }
410 
setThreadSafeRefUnref(bool threadSafe)411 void Group::setThreadSafeRefUnref(bool threadSafe)
412 {
413     Node::setThreadSafeRefUnref(threadSafe);
414 
415     for(NodeList::const_iterator itr=_children.begin();
416         itr!=_children.end();
417         ++itr)
418     {
419         (*itr)->setThreadSafeRefUnref(threadSafe);
420     }
421 }
422 
resizeGLObjectBuffers(unsigned int maxSize)423 void Group::resizeGLObjectBuffers(unsigned int maxSize)
424 {
425     Node::resizeGLObjectBuffers(maxSize);
426 
427     for(NodeList::const_iterator itr=_children.begin();
428         itr!=_children.end();
429         ++itr)
430     {
431         (*itr)->resizeGLObjectBuffers(maxSize);
432     }
433 }
434 
releaseGLObjects(osg::State * state) const435 void Group::releaseGLObjects(osg::State* state) const
436 {
437     Node::releaseGLObjects(state);
438 
439     for(NodeList::const_iterator itr=_children.begin();
440         itr!=_children.end();
441         ++itr)
442     {
443         (*itr)->releaseGLObjects(state);
444     }
445 }
446