00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef __VCGLIB_UTILDAE
00024 #define __VCGLIB_UTILDAE
00025
00026
00027 #include <vcg/complex/append.h>
00028 #include <wrap/io_trimesh/additionalinfo.h>
00029 #include <vcg/complex/algorithms/update/normal.h>
00030 #include <vcg/complex/algorithms/update/position.h>
00031
00032 #include <wrap/io_trimesh/io_mask.h>
00033
00034 #include <QDomDocument>
00035 #include <QFile>
00036 #include <QXmlStreamWriter>
00037 #include <QStringList>
00038 #include <QMap>
00039
00040 #include <vcg/space/point3.h>
00041 #include <vcg/space/texcoord2.h>
00042 #include <vcg/space/color4.h>
00043 #include <vcg/space/texcoord2.h>
00044 #include <wrap/callback.h>
00045
00046 #include <vector>
00047
00048 namespace vcg {
00049 namespace tri {
00050 namespace io {
00051 class InfoDAE : public AdditionalInfo
00052 {
00053 public:
00054
00055 InfoDAE() :AdditionalInfo(){
00056 doc = NULL;
00057 textureIdMap.clear();
00058 }
00059
00060 ~InfoDAE(){
00061 if(doc!=NULL) delete doc;
00062 }
00063
00064 QDomDocument* doc;
00065 QMap<QString,int> textureIdMap;
00066 };
00067
00068 class UtilDAE
00069 {
00070 public:
00071 enum DAEError
00072 {
00073 E_NOERROR,
00074 E_CANTOPEN,
00075 E_NOGEOMETRYLIBRARY,
00076 E_NOMESH,
00077 E_NOVERTEXPOSITION,
00078 E_NO3DVERTEXPOSITION,
00079 E_NO3DSCENE,
00080 E_INCOMPATIBLECOLLADA141FORMAT,
00081 E_UNREFERENCEBLEDCOLLADAATTRIBUTE,
00082 E_NOPOLYGONALMESH,
00083 E_CANTSAVE,
00084 E_NOACCESSORELEMENT
00085 };
00086
00087
00088 static const char *ErrorMsg(int error)
00089 {
00090 static const char * dae_error_msg[] =
00091 {
00092 "No errors",
00093 "Can't open file",
00094 "File without a geometry library",
00095 "There isn't mesh in file",
00096 "The meshes in file haven't the vertex position attribute",
00097 "The importer assumes that the OpenMeshType uses a 3D point for the vertex position",
00098 "There isn't any scene in Collada file",
00099 "The input file is not compatible with COLLADA 1.41 standard format",
00100 "Collada file is trying to referece an attribute that is not in the file",
00101 "This version of Collada Importer support only triangular and polygonal mesh file"
00102 };
00103
00104 if(error>9 || error<0) return "Unknown error";
00105 else return dae_error_msg[error];
00106 };
00107 protected:
00108
00109
00110
00111
00112
00113
00114 inline static void referenceToANodeAttribute(const QDomNode n,const QString& attr,QString& url_st)
00115 {
00116 url_st = n.toElement().attribute(attr);
00117 int sz = url_st.size() - 1;
00118 url_st = url_st.right(sz);
00119 assert(url_st.size() != 0);
00120 }
00121
00122 inline static QDomNode findNodeBySpecificAttributeValue(const QDomNodeList& ndl,const QString& attrname,const QString& attrvalue)
00123 {
00124 int ndl_size = ndl.size();
00125 int ind = 0;
00126 while(ind < ndl_size)
00127 {
00128 QString st = ndl.at(ind).toElement().attribute(attrname);
00129 if (st == attrvalue)
00130 return ndl.at(ind);
00131 ++ind;
00132 }
00133 return QDomNode();
00134 }
00135
00136 inline static QDomNode findNodeBySpecificAttributeValue(const QDomNode n,const QString& tag,const QString& attrname,const QString& attrvalue)
00137 {
00138 return findNodeBySpecificAttributeValue(n.toElement().elementsByTagName(tag),attrname,attrvalue);
00139 }
00140
00141 inline static QDomNode findNodeBySpecificAttributeValue(const QDomDocument n,const QString& tag,const QString& attrname,const QString& attrvalue)
00142 {
00143 return findNodeBySpecificAttributeValue(n.elementsByTagName(tag),attrname,attrvalue);
00144 }
00145
00146 inline static bool isThereTag(const QDomNodeList& list)
00147 {
00148 return ((list.size() > 0) ? true : false);
00149 }
00150
00151 inline static bool isThereTag(const QDomNode n,const QString& tagname)
00152 {
00153 return isThereTag(n.toElement().elementsByTagName(tagname));
00154 }
00155
00156 inline static bool isThereTag(const QDomDocument n,const QString& tagname)
00157 {
00158 return isThereTag(n.elementsByTagName(tagname));
00159 }
00160
00161
00162 inline static QDomNode attributeSourcePerSimplex(const QDomNode n,const QDomDocument startpoint,const QString& sem)
00163 {
00164 QDomNodeList vertattr = n.toElement().elementsByTagName("input");
00165 for(int ind = 0;ind < vertattr.size();++ind)
00166 {
00167 if (vertattr.at(ind).toElement().attribute("semantic") == sem)
00168 {
00169 QString url;
00170 referenceToANodeAttribute(vertattr.at(ind),"source",url);
00171 return findNodeBySpecificAttributeValue(startpoint,"source","id",url);
00172 }
00173 }
00174 return QDomNode();
00175 }
00176
00177
00178 inline static void valueStringList(QStringList& res,const QDomNode srcnode,const QString& tag)
00179 {
00180 QDomNodeList list = srcnode.toElement().elementsByTagName(tag);
00181
00182 QString nd = list.at(0).firstChild().nodeValue();
00183 res = nd.simplified().split(" ",QString::SkipEmptyParts);
00184 if(res.empty())
00185 {
00186 qDebug("Warning valueStringList returned and emtpy list. nothing inside element with tag '%s'", qPrintable(tag));
00187 return;
00188 }
00189 if (res.last() == "")
00190 res.removeLast();
00191
00192
00193
00194
00195
00196
00197 }
00198
00199
00200
00201 inline static bool removeChildNodeList(QDomNodeList& nodelst,const QString& tag = "", const QString& attribname = "", const QString& attribvalue = "")
00202 {
00203 for(int jj = 0;jj < nodelst.size();++jj)
00204 {
00205 removeChildNode(nodelst.at(jj),tag,attribname,attribvalue);
00206 }
00207 return true;
00208 }
00209
00210
00211 inline static bool removeChildNode(QDomNode node,const QString& tag = "", const QString& attribname = "", const QString& attribvalue = "")
00212 {
00213 QDomNodeList clst = node.childNodes();
00214 for(int ii = 0;ii < clst.size();++ii)
00215 {
00216 QDomNode oldchild = node.childNodes().at(ii);
00217 if (tag != "")
00218 {
00219 if ((attribname != "") && (attribvalue != ""))
00220 {
00221 if (clst.at(ii).toElement().attribute(attribname) == attribvalue)
00222 node.removeChild(oldchild);
00223 }
00224 else
00225 {
00226 QString nm = clst.at(ii).nodeName();
00227 if (clst.at(ii).nodeName() == tag)
00228 {
00229 node.removeChild(oldchild);
00230 }
00231 }
00232 }
00233 else node.removeChild(oldchild);
00234 }
00235 return true;
00236 }
00237
00238 static void ParseRotationMatrix(vcg::Matrix44f& m,const std::vector<QDomNode>& t)
00239 {
00240 vcg::Matrix44f rotTmp;
00241 vcg::Matrix44f tmp;
00242 rotTmp.SetIdentity();
00243 tmp.SetIdentity();
00244 for(unsigned int ii = 0;ii < t.size();++ii)
00245 {
00246 QString rt = t[ii].firstChild().nodeValue();
00247 QStringList rtl = rt.split(" ");
00248 if (rtl.last() == "") rtl.removeLast();
00249 assert(rtl.size() == 4);
00250 tmp.SetRotateDeg(rtl.at(3).toFloat(),vcg::Point3f(rtl.at(0).toFloat(),rtl.at(1).toFloat(),rtl.at(2).toFloat()));
00251 rotTmp = rotTmp*tmp;
00252 }
00253 m = m * rotTmp;
00254 }
00255
00256 static void ParseTranslation(vcg::Matrix44f& m,const QDomNode t)
00257 {
00258 assert(t.toElement().tagName() == "translate");
00259 QDomNode tr = t.firstChild();
00260 QString coord = tr.nodeValue();
00261 QStringList coordlist = coord.split(" ");
00262 if (coordlist.last() == "")
00263 coordlist.removeLast();
00264 assert(coordlist.size() == 3);
00265 m[0][0] = 1.0f;
00266 m[1][1] = 1.0f;
00267 m[2][2] = 1.0f;
00268 m[3][3] = 1.0f;
00269 m[0][3] = coordlist.at(0).toFloat();
00270 m[1][3] = coordlist.at(1).toFloat();
00271 m[2][3] = coordlist.at(2).toFloat();
00272 }
00273
00274 static void ParseMatrixNode(vcg::Matrix44f& m,const QDomNode t)
00275 {
00276 assert(t.toElement().tagName() == "matrix");
00277 QDomNode tr = t.firstChild();
00278 QString coord = tr.nodeValue().simplified();
00279 qDebug("Parsing matrix node; text value is '%s'",qPrintable(coord));
00280 QStringList coordlist = coord.split(" ");
00281 if (coordlist.last() == "")
00282 coordlist.removeLast();
00283 assert(coordlist.size() == 16);
00284 for(int i=0;i<4;++i)
00285 {
00286 m[i][0] = coordlist.at(i*4+0).toFloat();
00287 m[i][1] = coordlist.at(i*4+1).toFloat();
00288 m[i][2] = coordlist.at(i*4+2).toFloat();
00289 m[i][3] = coordlist.at(i*4+3).toFloat();
00290 }
00291 }
00292
00293 static void TransfMatrix(const QDomNode parentnode,const QDomNode presentnode,vcg::Matrix44f& m)
00294 {
00295 if (presentnode == parentnode) return;
00296 else
00297 {
00298 QDomNode par = presentnode.parentNode();
00299 std::vector<QDomNode> rotlist;
00300 QDomNode trans;
00301 for(int ch = 0;ch < par.childNodes().size();++ch)
00302 {
00303 if (par.childNodes().at(ch).nodeName() == "rotate")
00304 rotlist.push_back(par.childNodes().at(ch));
00305 else if (par.childNodes().at(ch).nodeName() == "translate")
00306 {
00307 trans = par.childNodes().at(ch);
00308 }
00309 }
00310 vcg::Matrix44f tmp;
00311 tmp.SetIdentity();
00312 if (!trans.isNull()) ParseTranslation(tmp,trans);
00313 ParseRotationMatrix(tmp,rotlist);
00314 m = m * tmp;
00315 TransfMatrix(parentnode,par,m);
00316 }
00317 }
00318
00319 inline static int findOffSetForASingleSimplex(QDomNode node)
00320 {
00321 QDomNodeList wedatts = node.toElement().elementsByTagName("input");
00322 int max = 0;
00323 if (wedatts.size() == 0) return -1;
00324 else
00325 {
00326 for(int ii = 0;ii < wedatts.size();++ii)
00327 {
00328 int tmp = wedatts.at(ii).toElement().attribute("offset").toInt();
00329 if (tmp > max) max = tmp;
00330 }
00331 }
00332 return max + 1;
00333 }
00334
00335 inline static int findStringListAttribute(QStringList& list,const QDomNode node,const QDomNode poly,const QDomDocument startpoint,const char* token)
00336 {
00337 int offset = 0;
00338 if (!node.isNull())
00339 {
00340 offset = node.toElement().attribute("offset").toInt();
00341 QDomNode st = attributeSourcePerSimplex(poly,startpoint,token);
00342 valueStringList(list,st,"float_array");
00343 }
00344 return offset;
00345 }
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356 inline static QDomNode textureFinder(QString& boundMaterialName, QString &textureFileName, const QDomDocument doc)
00357 {
00358 boundMaterialName.remove('#');
00359
00360 QDomNodeList lib_mat = doc.elementsByTagName("library_materials");
00361 if (lib_mat.size() != 1)
00362 return QDomNode();
00363 QDomNode material = findNodeBySpecificAttributeValue(lib_mat.at(0),QString("material"),QString("id"),boundMaterialName);
00364 if (material.isNull())
00365 return QDomNode();
00366 QDomNodeList in_eff = material.toElement().elementsByTagName("instance_effect");
00367 if (in_eff.size() == 0)
00368 return QDomNode();
00369 QString url = in_eff.at(0).toElement().attribute("url");
00370 if ((url.isNull()) || (url == ""))
00371 return QDomNode();
00372 url = url.remove('#');
00373 qDebug("====== searching among library_effects the effect with id '%s' ",qPrintable(url));
00374
00375 QDomNodeList lib_eff = doc.elementsByTagName("library_effects");
00376 if (lib_eff.size() != 1)
00377 return QDomNode();
00378 QDomNode effect = findNodeBySpecificAttributeValue(lib_eff.at(0),QString("effect"),QString("id"),url);
00379 if (effect.isNull())
00380 return QDomNode();
00381 QDomNodeList init_from = effect.toElement().elementsByTagName("init_from");
00382 if (init_from.size() == 0)
00383 return QDomNode();
00384 QString img_id = init_from.at(0).toElement().text();
00385 if ((img_id.isNull()) || (img_id == ""))
00386 return QDomNode();
00387
00388
00389 QDomNodeList libraryImageNodeList = doc.elementsByTagName("library_images");
00390 qDebug("====== searching among library_images the effect with id '%s' ",qPrintable(img_id));
00391 if (libraryImageNodeList.size() != 1)
00392 return QDomNode();
00393 QDomNode imageNode = findNodeBySpecificAttributeValue(libraryImageNodeList.at(0),QString("image"),QString("id"),img_id);
00394 QDomNodeList initfromNode = imageNode.toElement().elementsByTagName("init_from");
00395 textureFileName= initfromNode.at(0).firstChild().nodeValue();
00396 qDebug("====== the image '%s' has a %i init_from nodes text '%s'",qPrintable(img_id),initfromNode.size(),qPrintable(textureFileName));
00397
00398 return imageNode;
00399 }
00400
00401 static int indexTextureByImgNode(const QDomDocument doc,const QDomNode node)
00402 {
00403 QDomNodeList libim = doc.elementsByTagName(QString("library_images"));
00404 if (libim.size() != 1)
00405 return -1;
00406 QDomNodeList imgs = libim.at(0).toElement().elementsByTagName("image");
00407
00408 int ii = 0;
00409 bool found = false;
00410 while((ii < imgs.size()) && (!found))
00411 {
00412 if (imgs.at(ii) == node)
00413 found = true;
00414 else ++ii;
00415 }
00416 if (found)
00417 return ii;
00418 else
00419 return -1;
00420 }
00421
00422 struct WedgeAttribute
00423 {
00424 QDomNode wnsrc;
00425 QStringList wn;
00426 int offnm;
00427
00428 QDomNode wtsrc;
00429 QStringList wt;
00430 int stridetx;
00431 int offtx;
00432
00433 QDomNode wcsrc;
00434 QStringList wc;
00435 int stridecl;
00436 int offcl;
00437 };
00438 };
00439 }
00440 }
00441 }
00442
00443 #endif