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