fixed: compile issue
[opensg.git] / Source / System / GraphOp / OSGMergeGraphOp.cpp
blobf38db7abd4761cee140b2459eae9d54ee546a3b0
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
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. *
18 * *
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. *
23 * *
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. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
40 /***************************************************************************\
41 * Includes *
42 \***************************************************************************/
44 #include <boost/bind.hpp>
46 #include "OSGMergeGraphOp.h"
47 #include "OSGDirectionalLight.h"
48 #include "OSGSpotLight.h"
49 #include "OSGLight.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
64 OSG_USING_NAMESPACE
66 /***************************************************************************\
67 * Description *
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);
83 return true;
85 static OSG::StaticInitFuncWrapper registerOpWrapper(registerOp);
87 /***************************************************************************\
88 * Instance methods *
89 \***************************************************************************/
91 /*-------------------------------------------------------------------------*\
92 - public -
93 \*-------------------------------------------------------------------------*/
96 /*------------- constructors & destructors --------------------------------*/
98 MergeGraphOp::MergeGraphOp(const char* name) :
99 GraphOp (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)
126 if (node == NULL)
127 return 0;
129 UInt32 total = 1;
130 for (UInt32 i = 0; i < node->getNChildren(); ++i)
131 total += countNodes(node->getChild(i));
132 return total;
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: "
142 << next << endLog;
143 bool result = true;
144 UInt32 current;
145 do {
146 current = next;
147 result &= mergeOnce(node);
148 if (!result)
149 break;
150 next = countNodes(node);
151 } while (next < current);
153 SINFO << "MergeGraphOp::traverse: Number of nodes after merge: "
154 << current << endLog;
156 return result;
159 void MergeGraphOp::setParams(const std::string params)
161 ParamSet ps(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();
172 if(out.length())
174 FWARNING(("MergeGraphOp doesn't have parameters '%s'.\n",
175 out.c_str()));
179 std::string MergeGraphOp::usage(void)
181 return
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 /*-------------------------------------------------------------------------*\
198 - private -
199 \*-------------------------------------------------------------------------*/
201 bool MergeGraphOp::mergeOnce(Node * node)
203 std::list<Node const *> tempList;
204 tempList.clear();
205 tempList.splice(tempList.end(),_excludeListNodes);
206 makeExcludeList(node);
207 bool result = GraphOp::traverse(node);
208 _excludeListNodes.clear();
209 _excludeListNodes.splice(_excludeListNodes.end(),tempList);
210 return result;
213 void MergeGraphOp::makeExcludeList(Node * node)
216 ::traverse(node,
217 osgTypedMethodFunctor1ObjPtrCPtrRef<Action::ResultE,
218 MergeGraphOp,
219 NodePtr>(this,&MergeGraphOp::excludeListEnter),
220 osgTypedMethodFunctor2ObjPtrCPtrRef<Action::ResultE,
221 MergeGraphOp,
222 NodePtr,
223 Action::ResultE>(this,&MergeGraphOp::excludeListLeave));
225 ::traverse(node,
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());
240 if (dlight!=NULL)
241 addToExcludeList(dlight->getBeacon());
243 Light *light = dynamic_cast<Light *>(node->getCore());
244 if (light!=NULL)
245 addToExcludeList(light->getBeacon());
247 PointLight *plight = dynamic_cast<PointLight *>(node->getCore());
248 if (plight!=NULL)
249 addToExcludeList(plight->getBeacon());
251 SpotLight *slight = dynamic_cast<SpotLight *>(node->getCore());
252 if (slight!=NULL)
253 addToExcludeList(slight->getBeacon());
255 return res;
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)
274 processGroups(node);
275 processTransformations(node);
276 processGeometries(node);
277 return res;
280 bool MergeGraphOp::isLeaf(Node * const node)
282 if (node->getMFChildren()->begin() ==
283 node->getMFChildren()->end ()) return true;
284 else return false;
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() ))
298 return true;
299 else return false;
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);
314 if (isGroup(*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);
329 if (!special)
331 toSub.push_back(*mfit);
332 continue;
335 if (leaf && special)
337 //what to do?
339 if (!leaf && special)
341 //what to do?
343 continue;
345 else if ((*mfit)->getCore()->getType().isDerivedFrom(
346 MaterialGroup::getClassType() ))
348 MaterialGroup *mg =
349 dynamic_cast<MaterialGroup *>((*mfit)->getCore());
351 MFUnrecChildNodePtr::const_iterator it2 =
352 (*mfit)->getMFChildren()->begin();
353 MFUnrecChildNodePtr::const_iterator en2 =
354 (*mfit)->getMFChildren()->end ();
356 bool empty=true;
358 for ( ; it2 != en2; ++it2 )
360 if (!isInExcludeList(*it2))
362 //check if geometry
363 if ((*it2)->getCore()->getType().isDerivedFrom(
364 Geometry::getClassType()))
366 if(!isLeaf(*it2))
368 //hmm...bad tree...
369 empty=false;
371 else
373 //it is a leaf geometry, so apply the transformation
374 Geometry *geo =
375 dynamic_cast<Geometry *>((*it2)->getCore());
377 geo->setMaterial(mg->getMaterial());
379 toAdd.push_back(*it2);
382 else
384 empty=false;
387 else
389 empty=false;
393 if (empty)
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);
406 vit = toSub.begin();
407 ven = toSub.end ();
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);
426 bool empty=true;
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))
446 //check if geometry
447 if ((*it2)->getCore()->getType().isDerivedFrom(
448 Geometry::getClassType()))
450 if(!isLeaf(*it2))
452 //hmm...bad tree...
453 empty=false;
455 else
457 //it is a leaf geometry, so apply the transformation
458 Geometry *geo_old =
459 dynamic_cast<Geometry *>(
460 (*it2)->getCore());
461 //GeometryPtr geo = geo_old->clone();
462 GeometryUnrecPtr geo =
463 dynamic_pointer_cast<Geometry>(
464 OSG::deepClone(geo_old, "Material"));
466 Transform *t =
467 dynamic_cast<Transform *>(
468 (*mfit)->getCore());
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();
481 if(pos!=NULL)
483 for(UInt32 i = 0; i < pos->size(); ++i)
485 Pnt3f p=pos->getValue(i);
486 m.multFull(p, p);
487 pos->setValue(p,i);
491 if(norm!=NULL)
493 for(UInt32 i = 0; i < norm->size(); ++i)
495 Vec3f n=norm->getValue(i);
496 m.mult(n, n);
497 n.normalize();
498 norm->setValue(n,i);
502 if(color != NULL && _color_is_vector)
504 for(UInt32 i = 0; i < color->size(); ++i)
506 Color3f c = color->getValue(i);
507 Vec3f v;
508 v.setValue(c.getValuesRGB());
509 m.mult(v, v);
510 v.normalize();
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);
521 Vec3f v;
522 v.setValue(c.getValuesRGB());
523 m.mult(v, v);
524 v.normalize();
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);
535 m.mult(v, v);
536 v.normalize();
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);
546 m.mult(v, v);
547 v.normalize();
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);
557 m.mult(v, v);
558 v.normalize();
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);
568 m.mult(v, v);
569 v.normalize();
570 texcoord3->setValue(v,i);
573 (*it2)->setCore(geo);
574 toAdd.push_back(*it2);
576 } else empty=false;
577 } else empty=false;
581 //now check whether we have to remove it
582 if ((empty||leaf) && !special)
584 toSub.push_back(*mfit);
585 continue;
588 if (leaf && special)
590 //what to do?
592 if (!leaf && special)
594 //what to do?
596 continue;
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);
608 vit = toSub.begin();
609 ven = toSub.end ();
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());
634 #endif
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)
649 //ok, try
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);
665 if (new_geo==NULL)
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"));
676 else
678 if (new_geo->merge(geo2))
679 toSub.push_back(*it2);
682 #endif
685 if (new_geo!=NULL)
687 NodeUnrecPtr new_node=Node::create();
688 new_node->setCore(new_geo);
690 toAdd.push_back(new_node);
693 else
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);