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", _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
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
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
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
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 &)
00203 {
00204 return Action::Continue;
00205 }
00206
00207 Action::ResultE SharePtrGraphOp::traverseLeave(NodePtr &,
00208 Action::ResultE )
00209 {
00210 return Action::Continue;
00211 }
00212
00213
00214
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
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
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
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
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
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
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
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
00432
00433 const FieldContainerType &type = a->getType();
00434
00435
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
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
00456
00457 if(a_ftype != b_ftype)
00458 return false;
00459
00460 if(strstr(a_ftype.getCName(), "Ptr") == NULL)
00461 {
00462
00463
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
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
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
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')
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')
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
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
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')
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')
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 }