1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
40 /***************************************************************************\
42 \***************************************************************************/
44 #include <boost/bind.hpp>
46 #include "OSGMergeGraphOp.h"
47 #include "OSGDirectionalLight.h"
48 #include "OSGSpotLight.h"
50 #include "OSGPointLight.h"
51 #include "OSGSwitch.h"
52 #include "OSGDistanceLOD.h"
53 #include "OSGBillboard.h"
54 #include "OSGMaterialGroup.h"
55 #include "OSGComponentTransform.h"
56 #include "OSGPrimitiveIterator.h"
57 #include "OSGGeometry.h"
58 #include "OSGGeoFunctions.h"
59 #include "OSGGraphOpFactory.h"
61 // need to implement the merge methods amz
62 #define OSG2_MERGE_MISSING
66 /***************************************************************************\
68 \***************************************************************************/
70 /*! \class OSG::MergeGraphOp
71 \ingroup GrpSystemNodeCoresDrawablesGeometry
73 A class used to optimize geometries a bit.
77 //! Register the GraphOp with the factory
78 static bool registerOp(void)
80 GraphOpRefPtr newOp
= MergeGraphOp::create();
82 GraphOpFactory::the()->registerOp(newOp
);
85 static OSG::StaticInitFuncWrapper
registerOpWrapper(registerOp
);
87 /***************************************************************************\
89 \***************************************************************************/
91 /*-------------------------------------------------------------------------*\
93 \*-------------------------------------------------------------------------*/
96 /*------------- constructors & destructors --------------------------------*/
98 MergeGraphOp::MergeGraphOp(const char* name
) :
100 _color_is_vector (false),
101 _secondary_color_is_vector(false),
102 _texcoord0_is_vector (false),
103 _texcoord1_is_vector (false),
104 _texcoord2_is_vector (false),
105 _texcoord3_is_vector (false)
109 MergeGraphOp::~MergeGraphOp(void)
113 MergeGraphOpTransitPtr
114 MergeGraphOp::create(void)
116 return MergeGraphOpTransitPtr(new MergeGraphOp
);
119 GraphOpTransitPtr
MergeGraphOp::clone(void)
121 return GraphOpTransitPtr(new MergeGraphOp
);
124 UInt32
countNodes(Node
* const node
)
130 for (UInt32 i
= 0; i
< node
->getNChildren(); ++i
)
131 total
+= countNodes(node
->getChild(i
));
135 bool MergeGraphOp::traverse(Node
* node
)
137 // This is a hack and should be treated as such.
138 // The fact that it helps means there is something wrong with
139 // the merger. FIXME!!!
140 UInt32 next
= countNodes(node
);
141 SINFO
<< "MergeGraphOp::traverse: Number of nodes before merge: "
147 result
&= mergeOnce(node
);
150 next
= countNodes(node
);
151 } while (next
< current
);
153 SINFO
<< "MergeGraphOp::traverse: Number of nodes after merge: "
154 << current
<< endLog
;
159 void MergeGraphOp::setParams(const std::string params
)
163 ps("color_is_vector", _color_is_vector
);
164 ps("secondary_color_is_vector", _secondary_color_is_vector
);
165 ps("texcoord_is_vector", _texcoord0_is_vector
);
166 ps("texcoord0_is_vector", _texcoord0_is_vector
);
167 ps("texcoord1_is_vector", _texcoord1_is_vector
);
168 ps("texcoord2_is_vector", _texcoord2_is_vector
);
169 ps("texcoord3_is_vector", _texcoord3_is_vector
);
171 std::string out
= ps
.getUnusedParams();
174 FWARNING(("MergeGraphOp doesn't have parameters '%s'.\n",
179 std::string
MergeGraphOp::usage(void)
182 "Merge: merge all geometries in a subtree\n"
183 " Tries to merge all Geometries in a subtree into the minimal number.\n"
184 " of Nodes. Flattens Transformations and transforms indices on the way.\n"
185 "Params: name (type, default)\n"
186 " (The following params are useful for transforming tangent space vectors.)\n"
187 " color_is_vector (bool, false): transform color as if it were a normal\n"
188 " secondary_color_is_vector (bool, false): transform secondary color as if it were a normal\n"
189 " texcoord_is_vector (bool, false): transform texcoord0 as if it were a normal\n"
190 " texcoord0_is_vector (bool, false): transform texcoord0 as if it were a normal\n"
191 " texcoord1_is_vector (bool, false): transform texcoord1 as if it were a normal\n"
192 " texcoord2_is_vector (bool, false): transform texcoord2 as if it were a normal\n"
193 " texcoord3_is_vector (bool, false): transform texcoord3 as if it were a normal\n"
197 /*-------------------------------------------------------------------------*\
199 \*-------------------------------------------------------------------------*/
201 bool MergeGraphOp::mergeOnce(Node
* node
)
203 std::list
<Node
const *> tempList
;
205 tempList
.splice(tempList
.end(),_excludeListNodes
);
206 makeExcludeList(node
);
207 bool result
= GraphOp::traverse(node
);
208 _excludeListNodes
.clear();
209 _excludeListNodes
.splice(_excludeListNodes
.end(),tempList
);
213 void MergeGraphOp::makeExcludeList(Node
* node
)
217 osgTypedMethodFunctor1ObjPtrCPtrRef<Action::ResultE,
219 NodePtr>(this,&MergeGraphOp::excludeListEnter),
220 osgTypedMethodFunctor2ObjPtrCPtrRef<Action::ResultE,
223 Action::ResultE>(this,&MergeGraphOp::excludeListLeave));
226 boost::bind(&MergeGraphOp::excludeListEnter
, this, _1
),
227 boost::bind(&MergeGraphOp::excludeListLeave
, this, _1
, _2
) );
231 Action::ResultE
MergeGraphOp::excludeListEnter(Node
* const node
)
233 // if (node==NULL) ; else ;
234 return Action::Continue
;
237 Action::ResultE
MergeGraphOp::excludeListLeave(Node
* const node
, Action::ResultE res
)
239 DirectionalLight
*dlight
= dynamic_cast<DirectionalLight
*>(node
->getCore());
241 addToExcludeList(dlight
->getBeacon());
243 Light
*light
= dynamic_cast<Light
*>(node
->getCore());
245 addToExcludeList(light
->getBeacon());
247 PointLight
*plight
= dynamic_cast<PointLight
*>(node
->getCore());
249 addToExcludeList(plight
->getBeacon());
251 SpotLight
*slight
= dynamic_cast<SpotLight
*>(node
->getCore());
253 addToExcludeList(slight
->getBeacon());
258 Action::ResultE
MergeGraphOp::traverseEnter(Node
* const node
)
260 Switch
*switch_
= dynamic_cast<Switch
*>(node
->getCore());
261 if (switch_
!=NULL
) return Action::Skip
;
263 DistanceLOD
*dlod
= dynamic_cast<DistanceLOD
*>(node
->getCore());
264 if (dlod
!=NULL
) return Action::Skip
;
266 //leaf, don't enter, cause no job here
267 if (isLeaf(node
)) return Action::Skip
;
269 return Action::Continue
;
272 Action::ResultE
MergeGraphOp::traverseLeave(Node
* const node
, Action::ResultE res
)
275 processTransformations(node
);
276 processGeometries(node
);
280 bool MergeGraphOp::isLeaf(Node
* const node
)
282 if (node
->getMFChildren()->begin() ==
283 node
->getMFChildren()->end ()) return true;
287 /*! checks whether a node is a group and nothing else
289 bool MergeGraphOp::isGroup(Node
* const node
)
291 if( node
->getCore()->getType().isDerivedFrom( Group::getClassType() ) &&
292 !node
->getCore()->getType().isDerivedFrom( Transform::getClassType() ) &&
293 !node
->getCore()->getType().isDerivedFrom( ComponentTransform::getClassType() ) &&
294 !node
->getCore()->getType().isDerivedFrom( Switch::getClassType() ) &&
295 !node
->getCore()->getType().isDerivedFrom( MaterialGroup::getClassType() ) &&
296 !node
->getCore()->getType().isDerivedFrom( DistanceLOD::getClassType() ) &&
297 !node
->getCore()->getType().isDerivedFrom( Billboard::getClassType() ))
302 void MergeGraphOp::processGroups(Node
* const node
)
304 MFUnrecChildNodePtr::const_iterator mfit
= node
->getMFChildren()->begin();
305 MFUnrecChildNodePtr::const_iterator mfen
= node
->getMFChildren()->end ();
306 std::vector
<Node
*> toAdd
;
307 std::vector
<Node
*> toSub
;
309 for ( ; mfit
!= mfen
; ++mfit
)
311 bool special
=isInExcludeList(*mfit
);
312 bool leaf
=isLeaf(*mfit
);
316 if (!leaf
&& !special
)
318 MFUnrecChildNodePtr::const_iterator it2
=
319 (*mfit
)->getMFChildren()->begin();
320 MFUnrecChildNodePtr::const_iterator en2
=
321 (*mfit
)->getMFChildren()->end ();
323 for ( ; it2
!= en2
; ++it2
)
325 toAdd
.push_back(*it2
);
331 toSub
.push_back(*mfit
);
339 if (!leaf
&& special
)
345 else if ((*mfit
)->getCore()->getType().isDerivedFrom(
346 MaterialGroup::getClassType() ))
349 dynamic_cast<MaterialGroup
*>((*mfit
)->getCore());
351 MFUnrecChildNodePtr::const_iterator it2
=
352 (*mfit
)->getMFChildren()->begin();
353 MFUnrecChildNodePtr::const_iterator en2
=
354 (*mfit
)->getMFChildren()->end ();
358 for ( ; it2
!= en2
; ++it2
)
360 if (!isInExcludeList(*it2
))
363 if ((*it2
)->getCore()->getType().isDerivedFrom(
364 Geometry::getClassType()))
373 //it is a leaf geometry, so apply the transformation
375 dynamic_cast<Geometry
*>((*it2
)->getCore());
377 geo
->setMaterial(mg
->getMaterial());
379 toAdd
.push_back(*it2
);
394 toSub
.push_back(*mfit
);
398 std::vector
<Node
*>::const_iterator vit
= toAdd
.begin();
399 std::vector
<Node
*>::const_iterator ven
= toAdd
.end ();
401 for ( ; vit
!= ven
; ++vit
)
403 node
->addChild(*vit
);
409 for ( ; vit
!= ven
; ++vit
)
411 node
->subChild(*vit
);
415 void MergeGraphOp::processTransformations(Node
* const node
)
417 MFUnrecChildNodePtr::const_iterator mfit
= node
->getMFChildren()->begin();
418 MFUnrecChildNodePtr::const_iterator mfen
= node
->getMFChildren()->end ();
419 std::vector
<Node
*> toAdd
;
420 std::vector
<Node
*> toSub
;
422 for ( ; mfit
!= mfen
; ++mfit
)
424 bool special
=isInExcludeList(*mfit
);
425 bool leaf
=isLeaf(*mfit
);
428 //if a transformation:
429 if ((*mfit
)->getCore()->getType().isDerivedFrom(
430 Transform::getClassType()))
432 if (!leaf
&& !special
)
434 //try to apply it to children geometries
435 //move all "moveable" children one level up
436 //if empty after that, delete it
437 MFUnrecChildNodePtr::const_iterator it2
=
438 (*mfit
)->getMFChildren()->begin();
439 MFUnrecChildNodePtr::const_iterator en2
=
440 (*mfit
)->getMFChildren()->end ();
442 for ( ; it2
!= en2
; ++it2
)
444 if (!isInExcludeList(*it2
))
447 if ((*it2
)->getCore()->getType().isDerivedFrom(
448 Geometry::getClassType()))
457 //it is a leaf geometry, so apply the transformation
459 dynamic_cast<Geometry
*>(
461 //GeometryPtr geo = geo_old->clone();
462 GeometryUnrecPtr geo
=
463 dynamic_pointer_cast
<Geometry
>(
464 OSG::deepClone(geo_old
, "Material"));
467 dynamic_cast<Transform
*>(
470 GeoPnt3fProperty
*pos
= dynamic_cast<GeoPnt3fProperty
*>(geo
->getPositions());
471 GeoVec3fProperty
*norm
= dynamic_cast<GeoVec3fProperty
*>(geo
->getNormals());
472 GeoColor3fProperty
*color
= dynamic_cast<GeoColor3fProperty
*>(geo
->getColors());
473 GeoColor3fProperty
*scolor
= dynamic_cast<GeoColor3fProperty
*>(geo
->getSecondaryColors());
474 GeoVec3fProperty
*texcoord0
= dynamic_cast<GeoVec3fProperty
*>(geo
->getTexCoords());
475 GeoVec3fProperty
*texcoord1
= dynamic_cast<GeoVec3fProperty
*>(geo
->getTexCoords1());
476 GeoVec3fProperty
*texcoord2
= dynamic_cast<GeoVec3fProperty
*>(geo
->getTexCoords2());
477 GeoVec3fProperty
* texcoord3
= dynamic_cast<GeoVec3fProperty
*>(geo
->getTexCoords3());
479 Matrix m
=t
->getMatrix();
483 for(UInt32 i
= 0; i
< pos
->size(); ++i
)
485 Pnt3f p
=pos
->getValue(i
);
493 for(UInt32 i
= 0; i
< norm
->size(); ++i
)
495 Vec3f n
=norm
->getValue(i
);
502 if(color
!= NULL
&& _color_is_vector
)
504 for(UInt32 i
= 0; i
< color
->size(); ++i
)
506 Color3f c
= color
->getValue(i
);
508 v
.setValue(c
.getValuesRGB());
511 c
.setValuesRGB(v
[0], v
[1], v
[2]);
512 color
->setValue(c
,i
);
516 if(scolor
!= NULL
&& _secondary_color_is_vector
)
518 for(UInt32 i
= 0; i
< scolor
->size(); ++i
)
520 Color3f c
= scolor
->getValue(i
);
522 v
.setValue(c
.getValuesRGB());
525 c
.setValuesRGB(v
[0], v
[1], v
[2]);
526 scolor
->setValue(c
,i
);
530 if(texcoord0
!= NULL
&& _texcoord0_is_vector
)
532 for(UInt32 i
= 0; i
< texcoord0
->size(); ++i
)
534 Vec3f v
= texcoord0
->getValue(i
);
537 texcoord0
->setValue(v
,i
);
541 if(texcoord1
!= NULL
&& _texcoord1_is_vector
)
543 for(UInt32 i
= 0; i
< texcoord1
->size(); ++i
)
545 Vec3f v
= texcoord1
->getValue(i
);
548 texcoord1
->setValue(v
,i
);
552 if(texcoord2
!= NULL
&& _texcoord2_is_vector
)
554 for(UInt32 i
= 0; i
< texcoord2
->size(); ++i
)
556 Vec3f v
= texcoord2
->getValue(i
);
559 texcoord2
->setValue(v
,i
);
563 if (texcoord3
!= NULL
&& _texcoord3_is_vector
)
565 for(UInt32 i
= 0; i
< texcoord3
->size(); i
++)
567 Vec3f v
= texcoord3
->getValue(i
);
570 texcoord3
->setValue(v
,i
);
573 (*it2
)->setCore(geo
);
574 toAdd
.push_back(*it2
);
581 //now check whether we have to remove it
582 if ((empty
||leaf
) && !special
)
584 toSub
.push_back(*mfit
);
592 if (!leaf
&& special
)
600 std::vector
<Node
*>::const_iterator vit
= toAdd
.begin();
601 std::vector
<Node
*>::const_iterator ven
= toAdd
.end ();
603 for ( ; vit
!= ven
; ++vit
)
605 node
->addChild(*vit
);
611 for ( ; vit
!= ven
; ++vit
)
613 node
->subChild(*vit
);
617 void MergeGraphOp::processGeometries(Node
* const node
)
619 MFUnrecChildNodePtr::const_iterator mfit
= node
->getMFChildren()->begin();
620 MFUnrecChildNodePtr::const_iterator mfen
= node
->getMFChildren()->end ();
622 std::vector
<Node
*> toSub
;
623 std::vector
<NodeUnrecPtr
> toAdd
;
625 for ( ; mfit
!= mfen
; ++mfit
)
627 bool special
=isInExcludeList(*mfit
);
629 if ((*mfit
)->getCore()->getType().isDerivedFrom(
630 Geometry::getClassType()))
632 #ifndef OSG2_MERGE_MISSING
633 Geometry
*geo
= dynamic_cast<Geometry
*>((*mfit
)->getCore());
635 //if a geometry, try to merge it in another geometry
636 //if successfull, delete it.
637 //check also if it is added for exclusion
639 bool inSubList
=false;
641 std::vector
<Node
*>::const_iterator it3
=toSub
.begin();
642 std::vector
<Node
*>::const_iterator en3
=toSub
.end();
644 for ( ; it3
!= en3
; ++it3
)
645 if (*it3
==*mfit
) { inSubList
=true; break; }
647 if (!special
&& !inSubList
)
650 MFUnrecChildNodePtr::const_iterator it2
=mfit
+1;
651 Geometry
*new_geo
=NULL
;
652 for ( ; it2
!=mfen
; ++it2
)
654 if (!isInExcludeList(*it2
) && (*it2
)->getCore()->getType().isDerivedFrom(Geometry::getClassType()))
656 #ifndef OSG2_MERGE_MISSING
657 Geometry
*geo2
= dynamic_cast<Geometry
*>((*it2
)->getCore());
658 if (geo
->isMergeable(geo2
))
660 // HACK merge crashes when indices == NULL!
661 if(geo
->getIndices() == NULL
)
662 OSG::createSharedIndex(geo
);
663 if(geo2
->getIndices() == NULL
)
664 OSG::createSharedIndex(geo2
);
667 new_geo
=Geometry::create();
668 if (new_geo
->merge(geo
))
669 toSub
.push_back(*it
);
670 else FWARNING(("MergeGraphOp: processGeometries problem 1\n"));
672 if (new_geo
->merge(geo2
))
673 toSub
.push_back(*it2
);
674 else FWARNING(("MergeGraphOp: processGeometries problem 2\n"));
678 if (new_geo
->merge(geo2
))
679 toSub
.push_back(*it2
);
687 NodeUnrecPtr new_node
=Node::create();
688 new_node
->setCore(new_geo
);
690 toAdd
.push_back(new_node
);
695 //hmm...have to skip it
700 std::vector
<NodeUnrecPtr
>::const_iterator ait
= toAdd
.begin();
701 std::vector
<NodeUnrecPtr
>::const_iterator aen
= toAdd
.end ();
703 for ( ; ait
!= aen
; ++ait
)
705 node
->addChild(*ait
);
708 std::vector
<Node
*>::const_iterator sit
= toSub
.begin();
709 std::vector
<Node
*>::const_iterator sen
= toSub
.end ();
711 for ( ; sit
!= sen
; ++sit
)
713 node
->subChild(*sit
);