Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

OSGSharePtrGraphOp.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002 *                                OpenSG                                     *
00003 *                                                                           *
00004 *                                                                           *
00005 *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
00006 *                                                                           *
00007 *                            www.opensg.org                                 *
00008 *                                                                           *
00009 *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010 *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013 *                                License                                    *
00014 *                                                                           *
00015 * This library is free software; you can redistribute it and/or modify it   *
00016 * under the terms of the GNU Library General Public License as published    *
00017 * by the Free Software Foundation, version 2.                               *
00018 *                                                                           *
00019 * This library is distributed in the hope that it will be useful, but       *
00020 * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022 * Library General Public License for more details.                          *
00023 *                                                                           *
00024 * You should have received a copy of the GNU Library General Public         *
00025 * License along with this library; if not, write to the Free Software       *
00026 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027 *                                                                           *
00028 \*---------------------------------------------------------------------------*/
00029 /*---------------------------------------------------------------------------*\
00030 *                                Changes                                    *
00031 *                                                                           *
00032 *                                                                           *
00033 *                                                                           *
00034 *                                                                           *
00035 *                                                                           *
00036 *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038 
00039 /***************************************************************************\
00040 *                             Includes                                    *
00041 \***************************************************************************/
00042 
00043 #include "OSGSharePtrGraphOp.h"
00044 
00045 #include <functional>
00046 #include <algorithm>
00047 
00048 #include <OSGLog.h>
00049 #include <OSGGeometry.h>
00050 #include <OSGGeoFunctions.h>
00051 #include <OSGVector.h>
00052 
00053 OSG_USING_NAMESPACE
00054 
00055 /***************************************************************************\
00056  *                            Description                                  *
00057 \***************************************************************************/
00058 
00066 /***************************************************************************\
00067  *                           Class variables                               *
00068 \***************************************************************************/
00069 
00070 std::set<FieldContainerPtr> SharePtrGraphOp::_added_cores;
00071 
00072 /***************************************************************************\
00073  *                           Instance methods                              *
00074 \***************************************************************************/
00075 
00076 /*-------------------------------------------------------------------------*\
00077  -  public                                                                 -
00078 \*-------------------------------------------------------------------------*/
00079 
00080 
00081 /*------------- constructors & destructors --------------------------------*/
00082 
00083 SharePtrGraphOp::SharePtrGraphOp(const char* name): 
00084     GraphOp(name),
00085     _fctypes(),
00086     _includes(),
00087     _excludes(),
00088     _share_counter(0)
00089 {
00090 }
00091 
00092 SharePtrGraphOp::~SharePtrGraphOp(void)
00093 {
00094 }
00095 
00096 GraphOp *SharePtrGraphOp::create()
00097 {
00098     return new SharePtrGraphOp();
00099 }
00100 
00101 bool SharePtrGraphOp::traverse(NodePtr& root)
00102 {
00103     if(!_includes.empty() && !_excludes.empty())
00104     {
00105         FFATAL(("SharePtrGraphOp : Setting both the includes and excludes"
00106                 "is not allowed!\n"));
00107         return false;
00108     }
00109     
00110     _fctypes.clear();
00111     _share_counter = 0;
00112 
00113     bool result = true;
00114     compareFCs(root);
00115     // HACK but doing it directly in compareFCs() leads to crash while destroying the
00116     // scenegraph and this only with one special geometry file ...
00117     fillAttachmentParents(root);
00118 
00119     FINFO(("Shared %u ptrs with types", _share_counter));
00120 
00121     for(fcsMap::iterator i = _fctypes.begin();i != _fctypes.end();++i)
00122         FINFO((" '%s'", (*i).first.c_str()));
00123     FINFO(("\n"));
00124 
00125     return result;
00126 }
00127 
00128 void SharePtrGraphOp::setParams(const std::string params)
00129 {
00130     ParamSet ps(params);   
00131     std::string incl, excl;
00132     
00133     ps("includes",  incl);
00134     ps("excludes",  excl);
00135     
00136     if(incl.length() && excl.length())
00137     {
00138         FWARNING(("SharePtrGraphOp: can't set includes and excludes\n"));
00139     }
00140     else
00141     {
00142         setIncludes(incl);
00143         setExcludes(excl);
00144     }
00145     
00146     std::string out = ps.getUnusedParams();
00147     if(out.length())
00148     {
00149         FWARNING(("SharePtrGraphOp doesn't have parameters '%s'.\n",
00150                 out.c_str()));
00151     }
00152 }
00153 
00154 std::string SharePtrGraphOp::usage(void)
00155 {
00156     return 
00157     "SharePtr: try to share FieldContainers in a subtree\n"
00158     "  Compares the values of all referenced FieldContainers in the\n"
00159     "  subtree and shares them if possible. Primarily useful for\n"
00160     "  Geometries and Materials, but works for everything.\n"
00161     "Params: name (type, default)\n"
00162     "  includes (string, ""): comma-separated list of types to share\n"
00163     "  excludes (string, ""): comma-separated list of types not to share\n"
00164     "  (Only one of the two can be used, not both at the same time)\n"
00165     ;
00166 }
00167 
00168 void SharePtrGraphOp::setIncludes(const std::string &includes)
00169 {
00170     _includes.clear();
00171     // parse comma separated names.
00172     std::string::const_iterator nextComma;
00173     std::string::const_iterator curPos = includes.begin();
00174     while(curPos < includes.end())
00175     {
00176         nextComma = std::find(curPos, includes.end(), ',');
00177         // strip leading spaces
00178         curPos = std::find_if(curPos, nextComma,
00179                               std::not1(std::ptr_fun(isspace)));
00180         _includes.push_back(std::string(curPos, nextComma));
00181         curPos = ++nextComma;
00182     }
00183 }
00184 
00185 void SharePtrGraphOp::setExcludes(const std::string &excludes)
00186 {
00187     _excludes.clear();
00188     // parse comma separated names.
00189     std::string::const_iterator nextComma;
00190     std::string::const_iterator curPos = excludes.begin();
00191     while(curPos < excludes.end())
00192     {
00193         nextComma = std::find(curPos, excludes.end(), ',');
00194         // strip leading spaces
00195         curPos = std::find_if(curPos, nextComma,
00196                               std::not1(std::ptr_fun(isspace)));
00197         _excludes.push_back(std::string(curPos, nextComma));
00198         curPos = ++nextComma;
00199     }
00200 }
00201 
00202 Action::ResultE SharePtrGraphOp::traverseEnter(NodePtr &/*node*/)
00203 {
00204     return Action::Continue;
00205 }
00206 
00207 Action::ResultE SharePtrGraphOp::traverseLeave(NodePtr &/*node*/,
00208                                                Action::ResultE /*res*/)
00209 {
00210     return Action::Continue;
00211 }
00212 
00213 /*-------------------------------------------------------------------------*\
00214  -  private                                                                -
00215 \*-------------------------------------------------------------------------*/
00216 
00217 bool SharePtrGraphOp::isInList(const std::vector<std::string> &tlist,
00218                                const FieldContainerPtr &fc)
00219 {
00220     for(UInt32 k=0;k<tlist.size();++k)
00221     {
00222         FieldContainerType *fct = FieldContainerFactory::the()
00223                                         ->findType(tlist[k].c_str());
00224         if(fct == NULL)
00225         {
00226             FWARNING(("SharePtrGraphOp: Unknown type '%s'!\n", tlist[k].c_str()));
00227             break;
00228         }
00229 
00230         if(fc->getType().isDerivedFrom(*fct))
00231             return true;
00232     }
00233 
00234     return false;
00235 }
00236 
00237 FieldContainerPtr SharePtrGraphOp::compareFCs(const FieldContainerPtr &fc)
00238 {
00239     if(fc == NullFC)
00240         return fc;
00241 
00242     const FieldContainerType &type = fc->getType();
00243     UInt32 fcount = type.getNumFieldDescs();
00244 
00245     for(UInt32 i=1;i <= fcount;++i)
00246     {
00247         const FieldDescription* fdesc = type.getFieldDescription(i);
00248     
00249         if(fdesc->isInternal())
00250             continue;
00251         
00252         // ignore attachments
00253         if(strcmp(fdesc->getCName(), "attachments") == 0)
00254             continue;
00255 
00256         BitVector mask = fdesc->getFieldMask();
00257 
00258         Field *fc_field = fc->getField(i);
00259         const FieldType &ftype = fc_field->getType();
00260         std::string fieldType = ftype.getName().str();
00261         
00262         // field
00263         if(strstr(ftype.getCName(), "Ptr") != NULL)
00264         {
00265             if(fc_field->getCardinality() == FieldType::SINGLE_FIELD)
00266             {
00267                 FieldContainerPtr ffc = ((SFFieldContainerPtr *) fc_field)
00268                                         ->getValue();
00269                 
00270                 FieldContainerPtr nffc = compareFCs(ffc);
00271                 
00272                 if(nffc != ffc)
00273                 {
00274                     addRefCP(nffc);
00275                     beginEditCP(fc, mask);
00276                         ((SFFieldContainerPtr *) fc_field)->setValue(nffc);
00277                     endEditCP(fc, mask);
00278 #if 0
00279                     // for attachments we need to update the parents field!
00280                     AttachmentPtr attachment = AttachmentPtr::dcast(nffc);
00281                     if(attachment != NullFC)
00282                     {
00283                         AttachmentPtr attorg = AttachmentPtr::dcast(ffc);
00284                         beginEditCP(attorg, Attachment::ParentsFieldMask);
00285                             attorg->subParent(fc);
00286                         endEditCP(attorg, Attachment::ParentsFieldMask);
00287 
00288                         FieldContainerPtr fcb = fc;
00289                         fcb.setParentFieldPos(fdesc->getFieldId());
00290                         beginEditCP(attachment, Attachment::ParentsFieldMask);
00291                             attachment->addParent(fc);
00292                             //attachment->getParents().clear();
00293                         endEditCP(attachment, Attachment::ParentsFieldMask);
00294                     }
00295 #endif
00296                     subRefCP(ffc);
00297                 }
00298             }
00299             else if(fc_field->getCardinality() == FieldType::MULTI_FIELD)
00300             {
00301                 beginEditCP(fc, mask);
00302                 for(UInt32 j=0;j < ((MFFieldContainerPtr*)fc_field)->size();++j)
00303                 {
00304                     FieldContainerPtr ffc = (*(((MFFieldContainerPtr *)fc_field)))[j];
00305                     
00306                     FieldContainerPtr nffc = compareFCs(ffc);
00307                     
00308                     if(nffc != ffc)
00309                     {
00310                         addRefCP(nffc);
00311                         (*(((MFFieldContainerPtr *)fc_field)))[j] = nffc;
00312 #if 0
00313                         // for attachments we need to update the parents field!
00314                         AttachmentPtr attachment = AttachmentPtr::dcast(nffc);
00315                         if(attachment != NullFC)
00316                         {
00317                             AttachmentPtr attorg = AttachmentPtr::dcast(ffc);
00318                             beginEditCP(attorg, Attachment::ParentsFieldMask);
00319                                 attorg->subParent(fc);
00320                             endEditCP(attorg, Attachment::ParentsFieldMask);
00321 
00322                             FieldContainerPtr fcb = fc;
00323                             fcb.setParentFieldPos(fdesc->getFieldId());
00324                             beginEditCP(attachment, Attachment::ParentsFieldMask);
00325                                 attachment->addParent(fc);
00326                             endEditCP(attachment, Attachment::ParentsFieldMask);
00327                         }
00328 #endif
00329                         subRefCP(ffc);
00330                     }
00331                 }
00332                 endEditCP(fc, mask);
00333             }
00334         }
00335     }
00336 
00337     std::string typestr = fc->getType().getCName();
00338     
00339     if(!_includes.empty())
00340     {
00341         if(!isInList(_includes, fc))
00342             return fc;
00343     }
00344     
00345     if(!_excludes.empty())
00346     {
00347         if(isInList(_excludes, fc))
00348             return fc;
00349     }
00350 
00351     fcsMap::iterator fi = _fctypes.find(typestr);
00352     
00353     if(fi == _fctypes.end())
00354     {
00355         fcsSet fcs;
00356         _fctypes[typestr] = fcs;
00357         fi = _fctypes.find(typestr);
00358     }
00359 
00360     fcsSet &fcs = (*fi).second;
00361     
00362     // already shared?
00363     if(fcs.count(fc))
00364         return fc;
00365     
00366     for(fcsSet::iterator i=fcs.begin();i!=fcs.end();++i)
00367     {
00368         if(isEqual(*i, fc))
00369         {
00370             if(*i != fc)
00371             {
00372                 ++_share_counter;
00373                 FDEBUG(("Shared %u ptrs.\r", _share_counter));
00374             }
00375             return *i;
00376         }
00377     }
00378     
00379     fcs.insert(fc);
00380 
00381     return fc;
00382 }
00383 
00384 
00385 template <typename T>
00386 static bool compareMField(Field *a, Field *b)
00387 {
00388     MField<T> *mfa = dynamic_cast<MField<T> *>(a);
00389     MField<T> *mfb = dynamic_cast<MField<T> *>(b);
00390 
00391     if(mfa == NULL && mfb == NULL)
00392         return true;
00393 
00394     if(mfa == NULL || mfb == NULL)
00395         return false;
00396     
00397     if(mfa->size() != mfb->size())
00398         return false;
00399 
00400     for(UInt32 j=0;j<mfa->size();++j)
00401     {
00402         if((*mfa)[j] != (*mfb)[j])
00403         {
00404             return false;
00405         }
00406     }
00407 
00408     return true;
00409 }
00410 
00411 
00418 bool SharePtrGraphOp::isEqual(const osg::FieldContainerPtr &a,
00419                               const osg::FieldContainerPtr &b)
00420 {
00421     // Compare the pointers.
00422     if(a == b)
00423         return true;
00424 
00425     if(a == NullFC || b == NullFC)
00426         return false;
00427 
00428     if(a->getType() != b->getType())
00429         return false;
00430     
00431     //printf("comparing: %s\n", a->getType().getName().str());
00432     
00433     const FieldContainerType &type = a->getType();
00434     //UInt32 fcount = type.getNumFieldDescs();
00435     // ignore dynamic fields.
00436     UInt32 fcount = osgMin(type.getNumFieldDescs(), b->getType().getNumFieldDescs());
00437     
00438     for(UInt32 i=1;i <= fcount;++i)
00439     {
00440         const FieldDescription* fdesc = type.getFieldDescription(i);
00441     
00442         if(fdesc->isInternal())
00443             continue;
00444     
00445         // ignore attachments
00446         if(strcmp(fdesc->getCName(), "attachments") == 0)
00447             continue;
00448     
00449         Field *a_field = a->getField(i);
00450         Field *b_field = b->getField(i);
00451     
00452         const FieldType &a_ftype = a_field->getType();
00453         const FieldType &b_ftype = b_field->getType();
00454 
00455         //printf("comparing field %s\n", a_ftype.getCName());
00456 
00457         if(a_ftype != b_ftype)
00458             return false;
00459     
00460         if(strstr(a_ftype.getCName(), "Ptr") == NULL)
00461         {
00462             // some speedup.
00463             // This is a HACK this will be changed in near future.
00464             if(a_field->getCardinality() == FieldType::MULTI_FIELD)
00465             {
00466                 if(dynamic_cast<MField<UInt8> *>(a_field) != NULL)
00467                 {
00468                     if(!compareMField<UInt8>(a_field, b_field))
00469                         return false;
00470                 }
00471                 else if(dynamic_cast<MField<Int32> *>(a_field) != NULL)
00472                 {
00473                     if(!compareMField<Int32>(a_field, b_field))
00474                         return false;
00475                 }
00476                 else if(dynamic_cast<MField<UInt32> *>(a_field) != NULL)
00477                 {
00478                     if(!compareMField<UInt32>(a_field, b_field))
00479                         return false;
00480                 }
00481                 else if(dynamic_cast<MField<Real32> *>(a_field) != NULL)
00482                 {
00483                     if(!compareMField<Real32>(a_field, b_field))
00484                         return false;
00485                 }
00486                 else if(dynamic_cast<MField<Vec2f> *>(a_field) != NULL)
00487                 {
00488                     if(!compareMField<Vec2f>(a_field, b_field))
00489                         return false;
00490                 }
00491                 else if(dynamic_cast<MField<Vec3f> *>(a_field) != NULL)
00492                 {
00493                     if(!compareMField<Vec3f>(a_field, b_field))
00494                         return false;
00495                 }
00496                 else if(dynamic_cast<MField<Pnt3f> *>(a_field) != NULL)
00497                 {
00498                     if(!compareMField<Pnt3f>(a_field, b_field))
00499                         return false;
00500                 }
00501                 else if(dynamic_cast<MField<Color3f> *>(a_field) != NULL)
00502                 {
00503                     if(!compareMField<Color3f>(a_field, b_field))
00504                         return false;
00505                 }
00506                 else if(dynamic_cast<MField<Color4f> *>(a_field) != NULL)
00507                 {
00508                     if(!compareMField<Color4f>(a_field, b_field))
00509                         return false;
00510                 }
00511                 else
00512                 {
00513                     FINFO(("Slow multi field string compare for '%s'!\n",
00514                           a_ftype.getCName()));
00515                     std::string av, bv;
00516                     a_field->getValueByStr(av);
00517                     b_field->getValueByStr(bv);
00518                     if(av != bv)
00519                         return false;
00520                 }
00521             }
00522             else
00523             {
00524                 // This is very slow with multi fields!!!!
00525                 std::string av, bv;
00526                 a_field->getValueByStr(av);
00527                 b_field->getValueByStr(bv);
00528                 if(av != bv)
00529                     return false;
00530             }
00531         }
00532         else
00533         {
00534             if(a_field->getCardinality() == FieldType::SINGLE_FIELD)
00535             {
00536                 if(!isEqual(((SFFieldContainerPtr *) a_field)->getValue(),
00537                             ((SFFieldContainerPtr *) b_field)->getValue()))
00538                     return false;
00539             }
00540             else if(a_field->getCardinality() == FieldType::MULTI_FIELD)
00541             {
00542                 if(((MFFieldContainerPtr*)a_field)->size() !=
00543                    ((MFFieldContainerPtr*)b_field)->size())
00544                    return false;
00545     
00546                 for(UInt32 j=0;j < ((MFFieldContainerPtr*)a_field)->size();++j)
00547                 {
00548                     if(!isEqual((*(((MFFieldContainerPtr *)a_field)))[j],
00549                                 (*(((MFFieldContainerPtr *)b_field)))[j]))
00550                         return false;
00551                 }
00552             }
00553         }
00554     }
00555     return true;
00556 }
00557 
00558 Action::ResultE SharePtrGraphOp::clearAttachmentParent(NodePtr &node)
00559 {
00560     if(node == NullFC)
00561         return Action::Continue;
00562 
00563     FieldContainerPtr fc = node->getCore();
00564 
00565     if(fc == NullFC)
00566         return Action::Continue;
00567 
00568     // the core could be shared this would lead to duplicated parent entries.
00569     if(_added_cores.count(fc) == 1)
00570         return Action::Continue;
00571 
00572     _added_cores.insert(fc);
00573 
00574     FieldContainerType  &fcType = fc->getType();
00575 
00576     //go through all fields
00577     for(UInt32 i = 1; i <= fcType.getNumFieldDescs(); ++i)
00578     {
00579         FieldDescription    *fDesc = fcType.getFieldDescription(i);
00580         Field               *fieldPtr = fc->getField(i);
00581         const FieldType     &fType = fieldPtr->getType();
00582         std::string         fieldType = fType.getCName();
00583         BitVector           mask = fDesc->getFieldMask();
00584 
00585         if(fDesc->isInternal())
00586         {
00587             continue;
00588         }
00589 
00590         if(strstr(fieldType.c_str(), "Ptr") != NULL)
00591         {
00592             if(fieldType[0] == 'S' && fieldType[1] == 'F') // single field
00593             {
00594                 AttachmentPtr attachment =
00595                     AttachmentPtr::dcast(((SFFieldContainerPtr *) fieldPtr)
00596                     ->getValue());
00597                 if(attachment != NullFC)
00598                 {
00599                     fc.setParentFieldPos(fDesc->getFieldId());
00600                     beginEditCP(attachment, Attachment::ParentsFieldMask);
00601                         attachment->getParents().clear();
00602                     endEditCP(attachment, Attachment::ParentsFieldMask);
00603                 }
00604             }
00605             else if(fieldType[0] == 'M' && fieldType[1] == 'F') // multi field
00606             {
00607                 MFFieldContainerPtr *mfield = (MFFieldContainerPtr *) fieldPtr;
00608                 UInt32 noe = mfield->size();
00609                 for(UInt32 j = 0; j < noe; ++j)
00610                 {
00611                     AttachmentPtr attachment =
00612                         AttachmentPtr::dcast((*(mfield))[j]);
00613                     if(attachment != NullFC)
00614                     {
00615                         fc.setParentFieldPos(fDesc->getFieldId());
00616                         beginEditCP(attachment, Attachment::ParentsFieldMask);
00617                             attachment->getParents().clear();
00618                         endEditCP(attachment, Attachment::ParentsFieldMask);
00619                     }
00620                 }
00621             }
00622         }
00623     }
00624 
00625     return Action::Continue;
00626 }
00627 
00628 Action::ResultE SharePtrGraphOp::addAttachmentParent(NodePtr &node)
00629 {
00630     if(node == NullFC)
00631         return Action::Continue;
00632 
00633     FieldContainerPtr fc = node->getCore();
00634 
00635     if(fc == NullFC)
00636         return Action::Continue;
00637 
00638     // the core could be shared this would lead to duplicated parent entries.
00639     if(_added_cores.count(fc) == 1)
00640         return Action::Continue;
00641 
00642     _added_cores.insert(fc);
00643 
00644     FieldContainerType  &fcType = fc->getType();
00645 
00646     //go through all fields
00647     for(UInt32 i = 1; i <= fcType.getNumFieldDescs(); ++i)
00648     {
00649         FieldDescription    *fDesc = fcType.getFieldDescription(i);
00650         Field               *fieldPtr = fc->getField(i);
00651         const FieldType     &fType = fieldPtr->getType();
00652         std::string         fieldType = fType.getCName();
00653         BitVector           mask = fDesc->getFieldMask();
00654 
00655         if(fDesc->isInternal())
00656         {
00657             continue;
00658         }
00659 
00660         if(strstr(fieldType.c_str(), "Ptr") != NULL)
00661         {
00662             if(fieldType[0] == 'S' && fieldType[1] == 'F') // single field
00663             {
00664                 AttachmentPtr attachment =
00665                     AttachmentPtr::dcast(((SFFieldContainerPtr *) fieldPtr)
00666                     ->getValue());
00667                 if(attachment != NullFC)
00668                 {
00669                     fc.setParentFieldPos(fDesc->getFieldId());
00670                     beginEditCP(attachment, Attachment::ParentsFieldMask);
00671                         attachment->addParent(fc);
00672                     endEditCP(attachment, Attachment::ParentsFieldMask);
00673                 }
00674             }
00675             else if(fieldType[0] == 'M' && fieldType[1] == 'F') // multi field
00676             {
00677                 MFFieldContainerPtr *mfield = (MFFieldContainerPtr *) fieldPtr;
00678                 UInt32 noe = mfield->size();
00679                 for(UInt32 j = 0; j < noe; ++j)
00680                 {
00681                     AttachmentPtr attachment =
00682                         AttachmentPtr::dcast((*(mfield))[j]);
00683                     if(attachment != NullFC)
00684                     {
00685                         fc.setParentFieldPos(fDesc->getFieldId());
00686                         beginEditCP(attachment, Attachment::ParentsFieldMask);
00687                             attachment->addParent(fc);
00688                         endEditCP(attachment, Attachment::ParentsFieldMask);
00689                     }
00690                 }
00691             }
00692         }
00693     }
00694 
00695     return Action::Continue;
00696 }
00697 
00698 void SharePtrGraphOp::fillAttachmentParents(const NodePtr &node)
00699 {
00700     if(node == NullFC)
00701         return;
00702 
00703     _added_cores.clear();
00704     OSG::traverse(node, osgTypedFunctionFunctor1CPtrRef<Action::ResultE,
00705                      NodePtr>(clearAttachmentParent));
00706     _added_cores.clear();
00707     OSG::traverse(node, osgTypedFunctionFunctor1CPtrRef<Action::ResultE,
00708                      NodePtr>(addAttachmentParent));
00709     _added_cores.clear();
00710 }

Generated on Thu Aug 25 04:09:52 2005 for OpenSG by  doxygen 1.4.3