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 <wrap/io_trimesh/additionalinfo.h>
00028 #include <vcg/complex/trimesh/update/normal.h>
00029 #include <vcg/complex/trimesh/update/position.h>
00030 #include <vcg/complex/trimesh/append.h>
00031 #include <vcg/complex/trimesh/allocate.h>
00032
00033 #include <wrap/io_trimesh/io_mask.h>
00034
00035 #include <QtXml/QDomDocument>
00036 #include <QtCore/QFile>
00037 #include <QtXml/QXmlStreamWriter>
00038 #include <QtCore/QStringList>
00039 #include <QtCore/QMap>
00040
00041 #include <vcg/space/point3.h>
00042 #include <vcg/space/texcoord2.h>
00043 #include <vcg/space/color4.h>
00044 #include <vcg/space/texcoord2.h>
00045 #include <wrap/callback.h>
00046
00047 #include <vector>
00048
00049 #include <wrap/gl/glu_tesselator.h>
00050
00051 namespace vcg {
00052 namespace tri {
00053 namespace io {
00054 class InfoDAE : public AdditionalInfo
00055 {
00056 public:
00057
00058 InfoDAE() :AdditionalInfo(){
00059 doc = NULL;
00060 textureIdMap.clear();
00061 }
00062
00063 ~InfoDAE(){
00064 if(doc!=NULL) delete doc;
00065 }
00066
00067 QDomDocument* doc;
00068 QMap<QString,int> textureIdMap;
00069 };
00070
00071 class UtilDAE
00072 {
00073 public:
00074 enum DAEError
00075 {
00076 E_NOERROR,
00077 E_CANTOPEN,
00078 E_NOGEOMETRYLIBRARY,
00079 E_NOMESH,
00080 E_NOVERTEXPOSITION,
00081 E_NO3DVERTEXPOSITION,
00082 E_NO3DSCENE,
00083 E_INCOMPATIBLECOLLADA141FORMAT,
00084 E_UNREFERENCEBLEDCOLLADAATTRIBUTE,
00085 E_NOPOLYGONALMESH,
00086 E_CANTSAVE
00087 };
00088
00089
00090
00091
00092
00093 template<typename VERTEX_TYPE>
00094 class MyPolygon
00095 {
00096 public:
00097 typedef VERTEX_TYPE BaseVertexType;
00098
00099 int _nvert;
00100 std::vector<VERTEX_TYPE*> _pv;
00101 std::vector< vcg::TexCoord2<float> > _txc;
00102
00103
00104 MyPolygon(int n)
00105 :_nvert(n),_pv(_nvert),_txc(_nvert)
00106 {
00107 }
00108 };
00109
00110 template<typename POLYGONAL_TYPE>
00111 class PolygonalMesh
00112 {
00113 public:
00114 typedef POLYGONAL_TYPE FaceType;
00115
00116 enum PERWEDGEATTRIBUTETYPE {NONE = 0,NORMAL = 1,MULTITEXTURECOORD = 2,MULTICOLOR = 4};
00117
00118 typedef typename FaceType::BaseVertexType VertexType;
00119 typedef VertexType* VertexPointer;
00120 typedef typename std::vector<VertexType>::iterator VertexIterator;
00121 typedef typename std::vector<FaceType>::iterator PolygonIterator;
00122
00123 vcg::Box3<float> bbox;
00124
00125 std::vector<VertexType> vert;
00126 std::vector<FaceType> _pols;
00127
00128 void generatePointsVector(std::vector<std::vector<vcg::Point3f> >& v)
00129 {
00130 for(typename PolygonalMesh::PolygonIterator itp = _pols.begin();itp != _pols.end();++itp)
00131 {
00132 v.push_back(std::vector<vcg::Point3f>());
00133 for(typename std::vector<VertexPointer>::iterator itv = itp->_pv.begin();itv != itp->_pv.end();++itv)
00134 {
00135 v[v.size() - 1].push_back((*itv)->P());
00136 }
00137 }
00138 }
00139
00140 void usePerWedgeAttributes(PERWEDGEATTRIBUTETYPE att,const unsigned int multitexture = 1,const unsigned int multicolor = 1)
00141 {
00142 if (att != NONE)
00143 {
00144 for(PolygonIterator itp = _pols.begin();itp != _pols.end();++itp)
00145 {
00146 if (att & MULTICOLOR) itp->usePerWedgeColor(multicolor);
00147 if (att & MULTITEXTURECOORD) itp->usePerWedgeMultiTexture(multitexture);
00148 if (att & NORMAL) itp->usePerWedgeNormal();
00149 }
00150 }
00151 }
00152
00153 template<class TRIMESH>
00154 void triangulate(TRIMESH& mesh)
00155 {
00156 std::vector<std::vector<vcg::Point3f> > pl;
00157 mesh.vert.resize(vert.size());
00158 int multicoor = 0;
00159
00160 for(size_t jj = 0;jj < mesh.vert.size();++jj)
00161 mesh.vert[jj].P() = vert[jj].P();
00162
00163 bool texen = mesh.face.IsWedgeTexEnabled();
00164 unsigned int totaltri = 0;
00165 for(size_t ii = 0;ii < _pols.size();++ii)
00166 totaltri += _pols[ii]._nvert - 2;
00167
00168 mesh.face.resize(totaltri);
00169
00170
00171 generatePointsVector(pl);
00172
00173
00174 int trioff = 0;
00175
00176 for(size_t ii = 0;ii < pl.size();++ii)
00177 {
00178 std::vector<int> tx;
00179 std::vector<std::vector<vcg::Point3f> > pl2(1);
00180 pl2[0] = pl[ii];
00181
00182 vcg::glu_tesselator::tesselate(pl2,tx);
00183 size_t ntri = tx.size() / 3;
00184 assert(tx.size() % 3 == 0);
00185
00186
00187 int polvert = 0;
00188
00189 for(size_t tr = 0;tr < ntri;++tr)
00190 {
00191
00192
00193
00194
00195 for(unsigned int tt = 0;tt < 3; ++tt)
00196 {
00197 mesh.face[trioff + tr].V(tt) = &(mesh.vert[_pols[ii]._pv[tx[3 * tr + tt]] - &(vert[0])]);
00198
00199 if (texen)
00200 {
00201
00202
00203
00204
00205 }
00206 polvert = (polvert + 1) % _pols[ii]._nvert;
00207 }
00208
00209 }
00210 trioff += ntri;
00211 }
00212 assert(trioff == totaltri);
00213 }
00214 };
00215
00216 static const char *ErrorMsg(int error)
00217 {
00218 static const char * dae_error_msg[] =
00219 {
00220 "No errors",
00221 "Can't open file",
00222 "File without a geometry library",
00223 "There isn't mesh in file",
00224 "The meshes in file haven't the vertex position attribute",
00225 "The importer assumes that the OpenMeshType uses a 3D point for the vertex position",
00226 "There isn't any scene in Collada file",
00227 "The input file is not compatible with COLLADA 1.41 standard format",
00228 "Collada file is trying to referece an attribute that is not in the file",
00229 "This version of Collada Importer support only triangular and polygonal mesh file"
00230 };
00231
00232 if(error>9 || error<0) return "Unknown error";
00233 else return dae_error_msg[error];
00234 };
00235 protected:
00236
00237
00238
00239
00240
00241
00242 inline static void referenceToANodeAttribute(const QDomNode n,const QString& attr,QString& url_st)
00243 {
00244 url_st = n.toElement().attribute(attr);
00245 int sz = url_st.size() - 1;
00246 url_st = url_st.right(sz);
00247 assert(url_st.size() != 0);
00248 }
00249
00250 inline static QDomNode findNodeBySpecificAttributeValue(const QDomNodeList& ndl,const QString& attrname,const QString& attrvalue)
00251 {
00252 int ndl_size = ndl.size();
00253 int ind = 0;
00254 while(ind < ndl_size)
00255 {
00256 QString st = ndl.at(ind).toElement().attribute(attrname);
00257 if (st == attrvalue)
00258 return ndl.at(ind);
00259 ++ind;
00260 }
00261 return QDomNode();
00262 }
00263
00264 inline static QDomNode findNodeBySpecificAttributeValue(const QDomNode n,const QString& tag,const QString& attrname,const QString& attrvalue)
00265 {
00266 return findNodeBySpecificAttributeValue(n.toElement().elementsByTagName(tag),attrname,attrvalue);
00267 }
00268
00269 inline static QDomNode findNodeBySpecificAttributeValue(const QDomDocument n,const QString& tag,const QString& attrname,const QString& attrvalue)
00270 {
00271 return findNodeBySpecificAttributeValue(n.elementsByTagName(tag),attrname,attrvalue);
00272 }
00273
00274 inline static bool isThereTag(const QDomNodeList& list)
00275 {
00276 return ((list.size() > 0) ? true : false);
00277 }
00278
00279 inline static bool isThereTag(const QDomNode n,const QString& tagname)
00280 {
00281 return isThereTag(n.toElement().elementsByTagName(tagname));
00282 }
00283
00284 inline static bool isThereTag(const QDomDocument n,const QString& tagname)
00285 {
00286 return isThereTag(n.elementsByTagName(tagname));
00287 }
00288
00289
00290 inline static QDomNode attributeSourcePerSimplex(const QDomNode n,const QDomDocument startpoint,const QString& sem)
00291 {
00292 QDomNodeList vertattr = n.toElement().elementsByTagName("input");
00293 for(int ind = 0;ind < vertattr.size();++ind)
00294 {
00295 if (vertattr.at(ind).toElement().attribute("semantic") == sem)
00296 {
00297 QString url;
00298 referenceToANodeAttribute(vertattr.at(ind),"source",url);
00299 return findNodeBySpecificAttributeValue(startpoint,"source","id",url);
00300 }
00301 }
00302 return QDomNode();
00303 }
00304
00305
00306 inline static void valueStringList(QStringList& res,const QDomNode srcnode,const QString& tag)
00307 {
00308 QDomNodeList list = srcnode.toElement().elementsByTagName(tag);
00309 assert(list.size() == 1);
00310 QString nd = list.at(0).firstChild().nodeValue();
00311 res = nd.simplified().split(" ",QString::SkipEmptyParts);
00312 if(res.empty())
00313 {
00314 qDebug("Warning valueStringList returned and emtpy list. nothing inside element with tag '%s'", qPrintable(tag));
00315 return;
00316 }
00317 if (res.last() == "")
00318 res.removeLast();
00319
00320
00321
00322
00323
00324
00325 }
00326
00327
00328
00329 inline static bool removeChildNodeList(QDomNodeList& nodelst,const QString& tag = "", const QString& attribname = "", const QString& attribvalue = "")
00330 {
00331 for(int jj = 0;jj < nodelst.size();++jj)
00332 {
00333 removeChildNode(nodelst.at(jj),tag,attribname,attribvalue);
00334 }
00335 return true;
00336 }
00337
00338
00339 inline static bool removeChildNode(QDomNode node,const QString& tag = "", const QString& attribname = "", const QString& attribvalue = "")
00340 {
00341 QDomNodeList clst = node.childNodes();
00342 for(int ii = 0;ii < clst.size();++ii)
00343 {
00344 QDomNode oldchild = node.childNodes().at(ii);
00345 if (tag != "")
00346 {
00347 if ((attribname != "") && (attribvalue != ""))
00348 {
00349 if (clst.at(ii).toElement().attribute(attribname) == attribvalue)
00350 node.removeChild(oldchild);
00351 }
00352 else
00353 {
00354 QString nm = clst.at(ii).nodeName();
00355 if (clst.at(ii).nodeName() == tag)
00356 {
00357 node.removeChild(oldchild);
00358 }
00359 }
00360 }
00361 else node.removeChild(oldchild);
00362 }
00363 return true;
00364 }
00365
00366 static void ParseRotationMatrix(vcg::Matrix44f& m,const std::vector<QDomNode>& t)
00367 {
00368 vcg::Matrix44f rotTmp;
00369 vcg::Matrix44f tmp;
00370 rotTmp.SetIdentity();
00371 tmp.SetIdentity();
00372 for(unsigned int ii = 0;ii < t.size();++ii)
00373 {
00374 QString rt = t[ii].firstChild().nodeValue();
00375 QStringList rtl = rt.split(" ");
00376 if (rtl.last() == "") rtl.removeLast();
00377 assert(rtl.size() == 4);
00378 tmp.SetRotateDeg(rtl.at(3).toFloat(),vcg::Point3f(rtl.at(0).toFloat(),rtl.at(1).toFloat(),rtl.at(2).toFloat()));
00379 rotTmp = rotTmp*tmp;
00380 }
00381 m = m * rotTmp;
00382 }
00383
00384 static void ParseTranslation(vcg::Matrix44f& m,const QDomNode t)
00385 {
00386 assert(t.toElement().tagName() == "translate");
00387 QDomNode tr = t.firstChild();
00388 QString coord = tr.nodeValue();
00389 QStringList coordlist = coord.split(" ");
00390 if (coordlist.last() == "")
00391 coordlist.removeLast();
00392 assert(coordlist.size() == 3);
00393 m[0][0] = 1.0f;
00394 m[1][1] = 1.0f;
00395 m[2][2] = 1.0f;
00396 m[3][3] = 1.0f;
00397 m[0][3] = coordlist.at(0).toFloat();
00398 m[1][3] = coordlist.at(1).toFloat();
00399 m[2][3] = coordlist.at(2).toFloat();
00400 }
00401
00402 static void ParseMatrixNode(vcg::Matrix44f& m,const QDomNode t)
00403 {
00404 assert(t.toElement().tagName() == "matrix");
00405 QDomNode tr = t.firstChild();
00406 QString coord = tr.nodeValue().simplified();
00407 qDebug("Parsing matrix node; text value is '%s'",qPrintable(coord));
00408 QStringList coordlist = coord.split(" ");
00409 if (coordlist.last() == "")
00410 coordlist.removeLast();
00411 assert(coordlist.size() == 16);
00412 for(int i=0;i<4;++i)
00413 {
00414 m[i][0] = coordlist.at(i*4+0).toFloat();
00415 m[i][1] = coordlist.at(i*4+1).toFloat();
00416 m[i][2] = coordlist.at(i*4+2).toFloat();
00417 m[i][3] = coordlist.at(i*4+3).toFloat();
00418 }
00419 }
00420
00421 static void TransfMatrix(const QDomNode parentnode,const QDomNode presentnode,vcg::Matrix44f& m)
00422 {
00423 if (presentnode == parentnode) return;
00424 else
00425 {
00426 QDomNode par = presentnode.parentNode();
00427 std::vector<QDomNode> rotlist;
00428 QDomNode trans;
00429 for(int ch = 0;ch < par.childNodes().size();++ch)
00430 {
00431 if (par.childNodes().at(ch).nodeName() == "rotate")
00432 rotlist.push_back(par.childNodes().at(ch));
00433 else if (par.childNodes().at(ch).nodeName() == "translate")
00434 {
00435 trans = par.childNodes().at(ch);
00436 }
00437 }
00438 vcg::Matrix44f tmp;
00439 tmp.SetIdentity();
00440 if (!trans.isNull()) ParseTranslation(tmp,trans);
00441 ParseRotationMatrix(tmp,rotlist);
00442 m = m * tmp;
00443 TransfMatrix(parentnode,par,m);
00444 }
00445 }
00446
00447 inline static int findOffSetForASingleSimplex(QDomNode node)
00448 {
00449 QDomNodeList wedatts = node.toElement().elementsByTagName("input");
00450 int max = 0;
00451 if (wedatts.size() == 0) return -1;
00452 else
00453 {
00454 for(int ii = 0;ii < wedatts.size();++ii)
00455 {
00456 int tmp = wedatts.at(ii).toElement().attribute("offset").toInt();
00457 if (tmp > max) max = tmp;
00458 }
00459 }
00460 return max + 1;
00461 }
00462
00463 inline static int findStringListAttribute(QStringList& list,const QDomNode node,const QDomNode poly,const QDomDocument startpoint,const char* token)
00464 {
00465 int offset = 0;
00466 if (!node.isNull())
00467 {
00468 offset = node.toElement().attribute("offset").toInt();
00469 QDomNode st = attributeSourcePerSimplex(poly,startpoint,token);
00470 valueStringList(list,st,"float_array");
00471 }
00472 return offset;
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484 inline static QDomNode textureFinder(QString& boundMaterialName, QString &textureFileName, const QDomDocument doc)
00485 {
00486 boundMaterialName.remove('#');
00487
00488 QDomNodeList lib_mat = doc.elementsByTagName("library_materials");
00489 if (lib_mat.size() != 1)
00490 return QDomNode();
00491 QDomNode material = findNodeBySpecificAttributeValue(lib_mat.at(0),QString("material"),QString("id"),boundMaterialName);
00492 if (material.isNull())
00493 return QDomNode();
00494 QDomNodeList in_eff = material.toElement().elementsByTagName("instance_effect");
00495 if (in_eff.size() == 0)
00496 return QDomNode();
00497 QString url = in_eff.at(0).toElement().attribute("url");
00498 if ((url.isNull()) || (url == ""))
00499 return QDomNode();
00500 url = url.remove('#');
00501 qDebug("====== searching among library_effects the effect with id '%s' ",qPrintable(url));
00502
00503 QDomNodeList lib_eff = doc.elementsByTagName("library_effects");
00504 if (lib_eff.size() != 1)
00505 return QDomNode();
00506 QDomNode effect = findNodeBySpecificAttributeValue(lib_eff.at(0),QString("effect"),QString("id"),url);
00507 if (effect.isNull())
00508 return QDomNode();
00509 QDomNodeList init_from = effect.toElement().elementsByTagName("init_from");
00510 if (init_from.size() == 0)
00511 return QDomNode();
00512 QString img_id = init_from.at(0).toElement().text();
00513 if ((img_id.isNull()) || (img_id == ""))
00514 return QDomNode();
00515
00516
00517 QDomNodeList libraryImageNodeList = doc.elementsByTagName("library_images");
00518 qDebug("====== searching among library_images the effect with id '%s' ",qPrintable(img_id));
00519 if (libraryImageNodeList.size() != 1)
00520 return QDomNode();
00521 QDomNode imageNode = findNodeBySpecificAttributeValue(libraryImageNodeList.at(0),QString("image"),QString("id"),img_id);
00522 QDomNodeList initfromNode = imageNode.toElement().elementsByTagName("init_from");
00523 textureFileName= initfromNode.at(0).firstChild().nodeValue();
00524 qDebug("====== the image '%s' has a %i init_from nodes text '%s'",qPrintable(img_id),initfromNode.size(),qPrintable(textureFileName));
00525
00526 return imageNode;
00527 }
00528
00529 static int indexTextureByImgNode(const QDomDocument doc,const QDomNode node)
00530 {
00531 QDomNodeList libim = doc.elementsByTagName(QString("library_images"));
00532 if (libim.size() != 1)
00533 return -1;
00534 QDomNodeList imgs = libim.at(0).toElement().elementsByTagName("image");
00535
00536 int ii = 0;
00537 bool found = false;
00538 while((ii < imgs.size()) && (!found))
00539 {
00540 if (imgs.at(ii) == node)
00541 found = true;
00542 else ++ii;
00543 }
00544 if (found)
00545 return ii;
00546 else
00547 return -1;
00548 }
00549
00550 struct WedgeAttribute
00551 {
00552 QDomNode wnsrc;
00553 QStringList wn;
00554 int offnm;
00555
00556 QDomNode wtsrc;
00557 QStringList wt;
00558 int stride;
00559 int offtx;
00560
00561 QDomNode wcsrc;
00562 QStringList wc;
00563 int offcl;
00564 };
00565 };
00566 }
00567 }
00568 }
00569
00570 #endif