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
00044 #include <OSGMaterialMergeGraphOp.h>
00045
00046 OSG_USING_NAMESPACE
00047
00048
00049
00050
00051
00058 MaterialMergeGraphOp::MaterialMergeGraphOp(const char* name)
00059 : GraphOp(name)
00060 {
00061 }
00062
00063 GraphOp* MaterialMergeGraphOp::create()
00064 {
00065 return new MaterialMergeGraphOp();
00066 }
00067
00068
00069
00070
00071 template<typename T>
00072 T next(T t) {
00073 ++t;
00074 return t;
00075 }
00076
00077
00078 bool isEqual(const osg::FieldContainerPtr& a, const osg::FieldContainerPtr& b)
00079 {
00080 using std::string;
00081
00082
00083 if(a == b)
00084 return true;
00085
00086 if(a == NullFC || b == NullFC)
00087 return false;
00088
00089 if(a->getType() != b->getType())
00090 return false;
00091
00092
00093
00094 const FieldContainerType &type = a->getType();
00095 UInt32 fcount = type.getNumFieldDescs();
00096
00097 for(UInt32 i=1;i <= fcount;++i)
00098 {
00099 const FieldDescription* fdesc = type.getFieldDescription(i);
00100
00101 if(fdesc->isInternal())
00102 continue;
00103
00104
00105 if(strcmp(fdesc->getCName(), "attachments") == 0)
00106 continue;
00107
00108 Field *a_field = a->getField(i);
00109 Field *b_field = b->getField(i);
00110
00111 const FieldType &a_ftype = a_field->getType();
00112 const FieldType &b_ftype = b_field->getType();
00113
00114
00115
00116 if(a_ftype != b_ftype)
00117 return false;
00118
00119 if(strstr(a_ftype.getCName(), "Ptr") == NULL)
00120 {
00121
00122
00123
00124
00125
00126 string av, bv;
00127 a_field->getValueByStr(av);
00128 b_field->getValueByStr(bv);
00129 if(av != bv)
00130 return false;
00131 }
00132 else
00133 {
00134 if(a_field->getCardinality() == FieldType::SINGLE_FIELD)
00135 {
00136 if(!isEqual(((SFFieldContainerPtr *) a_field)->getValue(),
00137 ((SFFieldContainerPtr *) b_field)->getValue()))
00138 return false;
00139 }
00140 else if(a_field->getCardinality() == FieldType::MULTI_FIELD)
00141 {
00142 if(((MFFieldContainerPtr*)a_field)->size() !=
00143 ((MFFieldContainerPtr*)b_field)->size())
00144 return false;
00145
00146 for(UInt32 j=0;j < ((MFFieldContainerPtr*)a_field)->size();++j)
00147 {
00148 if(!isEqual((*(((MFFieldContainerPtr *)a_field)))[j],
00149 (*(((MFFieldContainerPtr *)b_field)))[j]))
00150 return false;
00151 }
00152 }
00153 }
00154 }
00155 return true;
00156 }
00157
00158
00159 bool equal(MaterialPtr a, MaterialPtr b) {
00160
00161
00162 return isEqual(a, b);
00163 }
00164
00165
00166 bool MaterialMergeGraphOp::traverse(NodePtr& node)
00167 {
00168
00169 if (!GraphOp::traverse(node)) {
00170 return false;
00171 }
00172
00173 SINFO << "Number of materials before merge: " << _materialObjects.size() << std::endl;
00174
00175
00176 MaterialObjectMap::iterator itr = _materialObjects.begin();
00177 for (; itr != _materialObjects.end(); ++itr)
00178 {
00179 MaterialPtr current = itr->first;
00180 MaterialObjectList& currentList = itr->second;
00181
00182 MaterialObjectMap::iterator walker = next(itr);
00183 while (walker != _materialObjects.end()) {
00184
00185
00186 MaterialObjectMap::iterator nextStep = next(walker);
00187
00188 if (equal(current, walker->first)) {
00189
00190
00191 MaterialObjectList::iterator i = walker->second.begin();
00192 for (; i != walker->second.end(); ++i) {
00193 i->setMaterial(current);
00194 currentList.push_back(*i);
00195 }
00196 _materialObjects.erase(walker);
00197 }
00198
00199 walker = nextStep;
00200 }
00201 }
00202
00203 SINFO << "Number of materials after merge: " << _materialObjects.size() << std::endl;
00204 return true;
00205 }
00206
00207
00208 void MaterialMergeGraphOp::setParams(const std::string params)
00209 {
00210 ParamSet ps(params);
00211
00212 std::string out = ps.getUnusedParams();
00213 if(out.length())
00214 {
00215 FWARNING(("MaterialMergeGraphOp doesn't have parameters '%s'.\n",
00216 out.c_str()));
00217 }
00218 }
00219
00220 std::string MaterialMergeGraphOp::usage(void)
00221 {
00222 return
00223 "MaterialMerge: merge Materials in given subtree\n"
00224 " Tries to find and merge equiavlent Materials to reduce the number\n"
00225 " of Materials used.\n"
00226 ;
00227 }
00228
00229 Action::ResultE MaterialMergeGraphOp::traverseEnter(NodePtr& node)
00230 {
00231 GeometryPtr geo = GeometryPtr::dcast(node->getCore());
00232 if (geo != NullFC)
00233 {
00234 addObject(MaterialObject(geo));
00235 return Action::Continue;
00236 }
00237
00238 MaterialGroupPtr mg = MaterialGroupPtr::dcast(node->getCore());
00239 if (mg != NullFC)
00240 {
00241 addObject(MaterialObject(mg));
00242 return Action::Continue;
00243 }
00244
00245
00246 return Action::Continue;
00247 }
00248
00249 Action::ResultE MaterialMergeGraphOp::traverseLeave(NodePtr& node, Action::ResultE res)
00250 {
00251 return res;
00252 }
00253
00254 void MaterialMergeGraphOp::addObject(MaterialObject m)
00255 {
00256 MaterialPtr mat = m.getMaterial();
00257 if (mat == osg::NullFC)
00258 return;
00259
00260 _materialObjects[mat].push_back(m);
00261 }