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