From d43938a94bb95ae47fb3d3fb4eb0710c8ed0210d Mon Sep 17 00:00:00 2001 From: Gianpaolo Palma gianpaolopalma Date: Fri, 8 Feb 2008 17:04:32 +0000 Subject: [PATCH] Added methods to reduce loading time of X3D scene from the file --- src/fgt/io_x3d/import_x3d.h | 431 ++++++++++++++++++++++++++---------- 1 file changed, 317 insertions(+), 114 deletions(-) diff --git a/src/fgt/io_x3d/import_x3d.h b/src/fgt/io_x3d/import_x3d.h index 33e15bd9f..32adbb15c 100644 --- a/src/fgt/io_x3d/import_x3d.h +++ b/src/fgt/io_x3d/import_x3d.h @@ -24,6 +24,9 @@ History $Log$ + Revision 1.6 2008/02/08 17:04:32 gianpaolopalma + Added methods to reduce loading time of X3D scene from the file + Revision 1.5 2008/02/06 16:52:58 gianpaolopalma Added comments @@ -51,6 +54,7 @@ #include #include +#include #include #include @@ -65,6 +69,7 @@ namespace io { { private: + //search all Switch nodes and replace everyone with the child marked in the whichChoice attribute static void ManageSwitchNode(QDomDocument* doc) { @@ -548,9 +553,55 @@ namespace io { return E_NOERROR; } + + + //Check if the geometry defined in the 'root' is already parsed + inline static bool loadSubMesh(QDomElement& root, OpenMeshType& m, const std::map subMeshMap, const vcg::Matrix44f matrix, AdditionalInfoX3D* info, CallBackPos *cb) + { + static int random = 0; + if (root.isNull()) return false; + QString def = root.attribute("DEF", ""); + if (def == "") + { + //Add attribute DEF + QString defValue = "AutoGenDef#%1"; + root.setAttribute("DEF", defValue.arg(random++)); + return true; + } + std::map::const_iterator iter = subMeshMap.find(def); + if (iter != subMeshMap.end()) + { + //The geometry is already parsed + OpenMeshType* subMesh = iter->second; + int offsetVertex = m.vert.size(); + int offsetFace = m.face.size(); + //Append subMesh of the geometry to main mesh + vcg::tri::Append::Mesh(m, *subMesh); + //Trasform vertex and normal per vertex + for (size_t i = offsetVertex; i < m.vert.size(); i++) + { + vcg::Point4f vertex = matrix * vcg::Point4f(m.vert[i].P().X(), m.vert[i].P().Y(), m.vert[i].P().Z(), 1); + m.vert[i].P() = vcg::Point3f(vertex.X(), vertex.Y(), vertex.Z()); + if (m.HasPerVertexNormal()) + transformNormal(m.vert[i].N(), matrix, m.vert[i].N()); + } + //Trasform normal per wedge and per face + for (size_t i = offsetFace; i < m.face.size(); i++) + { + for (int tt = 0; tt < 3 && m.HasPerWedgeNormal(); tt++) + transformNormal(m.face[i].WN(tt), matrix, m.face[i].WN(tt)); + if (m.HasPerFaceNormal()) + transformNormal(m.face[i].N(), matrix, m.face[i].N()); + } + info->numvert++; + if ((cb !=NULL) && (info->numvert % 10)==0) (*cb)(10 + 80*info->numvert/info->numface, "Loading X3D Object..."); + return false; + } + return true; + } - + //Load default value of color and texture coordinate in the vertex inline static void loadDefaultValuePerVertex(typename OpenMeshType::VertexPointer vertex, const OpenMeshType m, int mask) { @@ -671,7 +722,6 @@ namespace io { findAndParseAttribute(coordIndex, geometry, "index", ""); if (!coordIndex.isEmpty()) { - info->numface++; if (!color.isNull()) bHasPerVertexColor = true; if (textureSup) bHasPerVertexText = true; @@ -688,7 +738,6 @@ namespace io { } else if (tagName == "TriangleFanSet" || tagName == "TriangleSet" || tagName == "TriangleStripSet" || tagName == "QuadSet") { - info->numface++; if (!color.isNull()) bHasPerWedgeColor = true; if (textureSup) bHasPerWedgeTexCoord = true; @@ -711,7 +760,6 @@ namespace io { findAndParseAttribute(coordIndex, geometry, "coordIndex", ""); if (!coordIndex.isEmpty()) { - info->numface++; if (textureSup) { if (!texCoordIndex.isEmpty()) @@ -746,7 +794,6 @@ namespace io { int xDimension = geometry.attribute("xDimension", "0").toInt(); int zDimension = geometry.attribute("zDimension", "0").toInt(); info->numvert += xDimension * zDimension; - info->numface++; if (textureSup) bHasPerVertexText = true; else @@ -768,7 +815,6 @@ namespace io { } else if (tagName == "PointSet" && !color.isNull()) { - info->numface++; bHasPerVertexColor = true; copyTextureFile = false; } @@ -780,12 +826,12 @@ namespace io { info->textureFile.push_back(textureFile.at(i)); } } - else if (tagName == "TriangleSet2D" || tagName == "Polypoint2D") - info->numface++; geometry = geometry.nextSiblingElement(); } } + std::map defUse; + info->numface = countObject(doc->firstChildElement(), defUse); //set mask if (bHasPerWedgeTexCoord) info->mask |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD; @@ -807,6 +853,33 @@ namespace io { } + + //Return the number of x3d object in the scene + static int countObject(const QDomElement& root, std::map& defUse) + { + if (root.isNull()) return 0; + int n = 0; + if (root.tagName() == "Shape") + return ++n; + if (root.attribute("DEF") != "") + defUse[root.attribute("DEF")] = root; + else if (root.attribute("USE") != "") + { + std::map::const_iterator iter = defUse.find(root.attribute("USE")); + if (iter != defUse.end()) + { + n += countObject(iter->second, defUse); + return n; + } + } + QDomElement child = root.firstChildElement(); + while(!child.isNull()) + { + n += countObject(child, defUse); + child = child.nextSiblingElement(); + } + return n; + } //Load in the mesh the geometry defined in the nodes TriangleSet, TriangleFanSet, TriangleStripSet, and QuadSet static int LoadSet(QDomElement geometry, @@ -817,11 +890,10 @@ namespace io { const QStringList& colorList, const QStringList& normalList, int colorComponent, + OpenMeshType* subMesh, AdditionalInfoX3D* info, - CallBackPos *cb=0) + CallBackPos *cb) { - info->numvert++; - if ((cb !=NULL) && (info->numvert % 5)==0) (*cb)(20 + 60*(info->numvert)/max(info->numface, info->numvert), "Loading X3D Object..."); QString normalPerVertex = geometry.attribute("normalPerVertex", "true"); std::vector vertexSet; int index = 0; @@ -851,19 +923,27 @@ namespace io { //Load vertexs in the mesh int offset = m.vert.size(); vcg::tri::Allocator::AddVertices(m, vertexSet.size()); + vcg::tri::Allocator::AddVertices(*subMesh, vertexSet.size()); + std::vector remap(m.vert.size(), -1); for (size_t vv = 0; vv < vertexSet.size(); vv++) { vcg::Point4f tmp = tMatrix * vertexSet.at(vv); m.vert[offset + vv].P() = vcg::Point3f(tmp.X(),tmp.Y(),tmp.Z()); - loadDefaultValuePerVertex(&(m.vert[offset + vv]), m, info->mask); + loadDefaultValuePerVertex(&(m.vert[offset + vv]), m, info->mask); + //Load vertex in the subMesh + vcg::tri::Append::ImportVertex(subMesh->vert[vv], m.vert[offset + vv]); + (*subMesh).vert[vv].P() = vcg::Point3f(vertexSet.at(vv).X(), vertexSet.at(vv).Y(), vertexSet.at(vv).Z()); + remap[offset + vv] = vv; } //Load faces in the mesh int offsetFace = m.face.size(); int nFace = 0; + vcg::Point3f normals[3]; if (geometry.tagName() == "TriangleSet") { nFace = vertexFaceIndex.size()/3; vcg::tri::Allocator::AddFaces(m, nFace); + vcg::tri::Allocator::AddFaces(*subMesh, nFace); for (int ff = 0; ff < nFace; ff++) { int faceIndex = ff + offsetFace; @@ -873,7 +953,10 @@ namespace io { m.face[faceIndex].V(tt) = &(m.vert[vertexFaceIndex.at(tt + ff*3) + offset]); //Load normal per wedge if (m.HasPerWedgeNormal() && normalPerVertex == "true" && !normalList.isEmpty()) - getNormal(normalList, (tt + ff*3)*3, m.face[faceIndex].WN(tt), tMatrix); + { + getNormal(normalList, (tt + ff*3)*3, normals[tt], vcg::Matrix44f::Identity()); + transformNormal(normals[tt], tMatrix, m.face[faceIndex].WN(tt)); + } //Load color per wedge if (m.HasPerWedgeColor() && !colorList.isEmpty()) getColor(colorList, colorComponent, (tt + ff*3)*colorComponent, m.face[faceIndex].WC(tt)); @@ -883,7 +966,18 @@ namespace io { } //Load normal per face if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) - getNormal(normalList, ff*3, m.face[faceIndex].N(), tMatrix); + { + getNormal(normalList, ff*3, normals[0], vcg::Matrix44f::Identity()); + transformNormal(normals[0], tMatrix, m.face[faceIndex].N()); + } + //Copy face in the subMesh + vcg::tri::Append::ImportFace((*subMesh), m, subMesh->face[ff], m.face[ff + offsetFace], remap); + for (int i = 0; i < 3; i++) + if (m.HasPerWedgeNormal() && normalPerVertex == "true" && !normalList.isEmpty()) + subMesh->face[ff].WN(i) = normals[i]; + + if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) + subMesh->face[ff].N() = normals[0]; } } else if (geometry.tagName() == "TriangleFanSet" || geometry.tagName() == "TriangleStripSet") @@ -916,7 +1010,8 @@ namespace io { } } } - vcg::tri::Allocator::AddFaces(m, nFace); + vcg::tri::Allocator::AddFaces(m, nFace); + vcg::tri::Allocator::AddFaces(*subMesh, nFace); int index = 0; int ff = 0; //For each fan or strip @@ -929,8 +1024,8 @@ namespace io { vcg::Point3f firstNormal, secondNormal; if (normalPerVertex == "true" && !normalList.isEmpty()) { - getNormal(normalList, index*3, firstNormal, tMatrix); - getNormal(normalList, index*3 + 3, secondNormal, tMatrix); + getNormal(normalList, index*3, firstNormal, vcg::Matrix44f::Identity()); + getNormal(normalList, index*3 + 3, secondNormal, vcg::Matrix44f::Identity()); } vcg::Color4b firstColor, secondColor; if (!colorList.isEmpty()) @@ -950,8 +1045,10 @@ namespace io { m.face[faceIndex].V(1) = &(m.vert[secondVertexIndex]); if (m.HasPerWedgeNormal() && normalPerVertex == "true" && !normalList.isEmpty()) { - m.face[faceIndex].WN(0) = firstNormal; - m.face[faceIndex].WN(1) = secondNormal; + transformNormal(firstNormal, tMatrix, m.face[faceIndex].WN(0)); + transformNormal(secondNormal, tMatrix, m.face[faceIndex].WN(1)); + normals[0] = firstNormal; + normals[1] = secondNormal; } if (m.HasPerWedgeColor() && !colorList.isEmpty()) { @@ -970,9 +1067,15 @@ namespace io { if (!normalList.isEmpty()) { if (normalPerVertex == "true" && m.HasPerWedgeNormal()) - getNormal(normalList, (index + vi)*3, m.face[faceIndex].WN(2), tMatrix); + { + getNormal(normalList, (index + vi)*3, normals[2], vcg::Matrix44f::Identity()); + transformNormal(normals[2], tMatrix, m.face[faceIndex].WN(2)); + } if (normalPerVertex == "false" && m.HasPerFaceNormal()) - getNormal(normalList, ff*3, m.face[faceIndex].N(), tMatrix); + { + getNormal(normalList, ff*3, normals[0], vcg::Matrix44f::Identity()); + transformNormal(normals[0], tMatrix, m.face[faceIndex].N()); + } } if (!colorList.isEmpty() && m.HasPerWedgeColor()) getColor(colorList, colorComponent, (index + vi)*colorComponent, m.face[faceIndex].WC(2)); @@ -1000,6 +1103,14 @@ namespace io { secondTextCoord = m.face[faceIndex].WT(2); validSecond = valid; } + + //Copy face in the subMesh + vcg::tri::Append::ImportFace((*subMesh), m, subMesh->face[ff], m.face[faceIndex], remap); + if (m.HasPerWedgeNormal() && normalPerVertex == "true" && !normalList.isEmpty()) + for (int i = 0; i < 3; i++) + subMesh->face[ff].WN(i) = normals[i]; + if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) + subMesh->face[ff].N() = normals[0]; ff++; } index += numVertex; @@ -1009,6 +1120,7 @@ namespace io { { nFace = vertexFaceIndex.size()/4; vcg::tri::Allocator::AddFaces(m, nFace * 2); + vcg::tri::Allocator::AddFaces(*subMesh, nFace * 2); for (int ff = 0; ff < nFace; ff++) { //Tesselate the quadrangular face @@ -1031,7 +1143,10 @@ namespace io { m.face[faceIndex].V(tt) = &(m.vert[vertexFaceIndex.at(indexVertex) + offset]); //Load normal per wedge if (m.HasPerWedgeNormal() && normalPerVertex == "true" && !normalList.isEmpty()) - getNormal(normalList, indexVertex*3, m.face[faceIndex].WN(tt), tMatrix); + { + getNormal(normalList, indexVertex*3, normals[tt], vcg::Matrix44f::Identity()); + transformNormal(normals[tt], tMatrix, m.face[faceIndex].WN(tt)); + } //Load color per wedge if (m.HasPerWedgeColor() && !colorList.isEmpty()) getColor(colorList, colorComponent, indexVertex*colorComponent, m.face[faceIndex].WC(tt)); @@ -1042,11 +1157,24 @@ namespace io { } //Load normal per face if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) - getNormal(normalList, ff*3, m.face[faceIndex].N(), tMatrix); + { + getNormal(normalList, ff*3, normals[0], vcg::Matrix44f::Identity()); + transformNormal(normals[0], tMatrix, m.face[faceIndex].N()); + } + + //Copy face in the subMesh + vcg::tri::Append::ImportFace((*subMesh), m, subMesh->face[faceIndex - offsetFace], m.face[faceIndex], remap); + if (m.HasPerWedgeNormal() && normalPerVertex == "true" && !normalList.isEmpty()) + for (int i = 0; i < 3; i++) + subMesh->face[faceIndex - offsetFace].WN(i) = normals[i]; + if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) + subMesh->face[faceIndex - offsetFace].N() = normals[0]; faceIndex++; } } } + info->numvert++; + if ((cb !=NULL) && (info->numvert % 10)==0) (*cb)(10 + 80*info->numvert/info->numface, "Loading X3D Object..."); return E_NOERROR; } @@ -1061,11 +1189,10 @@ namespace io { const QStringList& colorList, const QStringList& normalList, int colorComponent, + OpenMeshType* subMesh, AdditionalInfoX3D* info, - CallBackPos *cb=0) + CallBackPos *cb) { - info->numvert++; - if ((cb !=NULL) && (info->numvert % 5)==0) (*cb)(20 + 60*(info->numvert)/max(info->numface, info->numvert), "Loading X3D Object..."); QStringList indexList; findAndParseAttribute(indexList, geometry, "index", ""); if (!indexList.isEmpty()) @@ -1075,6 +1202,8 @@ namespace io { int offset = m.vert.size(); int nVertex = coordList.size()/3; vcg::tri::Allocator::AddVertices(m, nVertex); + vcg::tri::Allocator::AddVertices(*subMesh, nVertex); + std::vector remap(m.vert.size(), -1); for (int vv = 0; vv < nVertex; vv++) { vcg::Point4f tmp = tMatrix * vcg::Point4f(coordList.at(vv*3).toFloat(), coordList.at(vv*3 + 1).toFloat(), coordList.at(vv*3 + 2).toFloat(), 1.0); @@ -1089,6 +1218,12 @@ namespace io { //Load texture coordinate per vertex if (m.HasPerVertexTexCoord()) getTextureCoord(texture, vv*2, m.vert[offset + vv].cP(), m.vert[offset + vv].T(), tMatrix); + //Load vertex in the subMesh + vcg::tri::Append::ImportVertex(subMesh->vert[vv], m.vert[offset + vv]); + (*subMesh).vert[vv].P() = vcg::Point3f(coordList.at(vv*3).toFloat(), coordList.at(vv*3 + 1).toFloat(), coordList.at(vv*3 + 2).toFloat()); + if (m.HasPerVertexNormal() && normalPerVertex == "true" && !normalList.isEmpty()) + getNormal(normalList, vv*3, subMesh->vert[vv].N(), vcg::Matrix44f::Identity()); + remap[offset + vv] = vv; } //Load face in the mesh int offsetFace = m.face.size(); @@ -1097,6 +1232,7 @@ namespace io { { nFace = indexList.size()/3; vcg::tri::Allocator::AddFaces(m, nFace); + vcg::tri::Allocator::AddFaces(*subMesh, nFace); for (int ff = 0; ff < nFace; ff++) { int faceIndex = ff + offsetFace; @@ -1117,6 +1253,11 @@ namespace io { //Load normal per face if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) getNormal(normalList, ff*3, m.face[faceIndex].N(), tMatrix); + + //Copy face in the subMesh + vcg::tri::Append::ImportFace((*subMesh), m, subMesh->face[ff], m.face[ff + offsetFace], remap); + if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) + getNormal(normalList, ff*3, subMesh->face[ff].N(), vcg::Matrix44f::Identity()); } } else if (geometry.tagName() == "IndexedTriangleFanSet" || geometry.tagName() == "IndexedTriangleStripSet") @@ -1142,6 +1283,7 @@ namespace io { sub++; nFace = indexList.size() - 2*count - sub; vcg::tri::Allocator::AddFaces(m, nFace); + vcg::tri::Allocator::AddFaces(*subMesh, nFace); int ff = 0; int firstVertexIndex; int secondVertexIndex; @@ -1187,13 +1329,18 @@ namespace io { } m.face[faceIndex].V(2) = &(m.vert[vertIndex]); //Load normal per face - if (!normalList.isEmpty() && normalPerVertex == "false") + if (m.HasPerFaceNormal() && !normalList.isEmpty() && normalPerVertex == "false") getNormal(normalList, ff*3, m.face[faceIndex].N(), tMatrix); if(!m.HasPerVertexTexCoord() && m.HasPerWedgeTexCoord() && (info->mask & MeshModel::IOM_WEDGTEXCOORD)) - getTextureCoord(texture, (vertIndex - offset)*2, m.vert[vertIndex].cP(), m.face[faceIndex].WT(2), tMatrix); + getTextureCoord(texture, (vertIndex - offset)*2, m.vert[vertIndex].cP(), m.face[faceIndex].WT(2), tMatrix); if (geometry.tagName() == "IndexedTriangleStripSet") firstVertexIndex = secondVertexIndex; secondVertexIndex = vertIndex; + + //Copy face in the subMesh + vcg::tri::Append::ImportFace((*subMesh), m, subMesh->face[ff], m.face[faceIndex], remap); + if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) + getNormal(normalList, ff*3, subMesh->face[ff].N(), vcg::Matrix44f::Identity()); ff++; } } @@ -1201,6 +1348,7 @@ namespace io { { nFace = indexList.size()/4; vcg::tri::Allocator::AddFaces(m, nFace * 2); + vcg::tri::Allocator::AddFaces(*subMesh, nFace * 2); for (int ff = 0; ff < nFace; ff++) { //Tessellate the quadrangular face @@ -1237,11 +1385,17 @@ namespace io { //Load normal per face if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) getNormal(normalList, ff*3, m.face[faceIndex].N(), tMatrix); + //Load face in the subMesh + vcg::tri::Append::ImportFace((*subMesh), m, subMesh->face[faceIndex - offsetFace], m.face[faceIndex], remap); + if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) + getNormal(normalList, ff*3, subMesh->face[faceIndex - offsetFace].N(), vcg::Matrix44f::Identity()); faceIndex++; } } } } + info->numvert++; + if ((cb !=NULL) && (info->numvert % 10)==0) (*cb)(10 + 80*info->numvert/info->numface, "Loading X3D Object..."); return E_NOERROR; } @@ -1256,10 +1410,8 @@ namespace io { const QStringList& normalList, int colorComponent, AdditionalInfoX3D* info, - CallBackPos *cb=0) + CallBackPos *cb) { - info->numvert++; - if ((cb !=NULL) && (info->numvert % 5)==0) (*cb)(20 + 60*(info->numvert)/max(info->numface, info->numvert), "Loading X3D Object..."); QString colorPerVertex = geometry.attribute("colorPerVertex", "true"); QString normalPerVertex = geometry.attribute("normalPerVertex", "true"); int xDimension = geometry.attribute("xDimension", "0").toInt(); @@ -1309,46 +1461,36 @@ namespace io { { for (int j = 0; j < xDimension - 1; j++) { - //Load first face index = 2 * (i * (xDimension - 1) + j); - loadDefaultValuePerFace(&(m.face[index + offsetFace]), m, info->mask); - m.face[index + offsetFace].V(0) = &(m.vert[i * xDimension + j + offsetVertex]); - m.face[index + offsetFace].V(1) = &(m.vert[(i + 1) * xDimension + j + 1 + offsetVertex]); - m.face[index + offsetFace].V(2) = &(m.vert[i * xDimension + j + 1 + offsetVertex]); - //Load color per face - if (m.HasPerFaceColor() && colorPerVertex == "false" && !colorList.isEmpty()) - getColor(colorList, colorComponent, index * colorComponent, m.face[index +offsetFace].C()); - //Load normal per face - if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) - getNormal(normalList, index * 3, m.face[index + offsetFace].N(), tMatrix); - //Load texture coordinate per wedge - if (!m.HasPerVertexTexCoord() && m.HasPerWedgeTexCoord() && (info->mask & MeshModel::IOM_WEDGTEXCOORD)) + //Load first face + for (int ff = 0; ff < 2; ff++) { - getTextureCoord(texture, (i * xDimension + j)*2, m.vert[i * xDimension + j + offsetVertex].cP(), m.face[index + offsetFace].WT(0), tMatrix); - getTextureCoord(texture, ((i + 1) * xDimension + j + 1)*2, m.vert[(i + 1) * xDimension + j + 1 + offsetVertex].cP(), m.face[index + offsetFace].WT(1), tMatrix); - getTextureCoord(texture, (i * xDimension + j + 1)*2, m.vert[i * xDimension + j + 1 + offsetVertex].cP(), m.face[index + offsetFace].WT(2), tMatrix); - } - //Load second face - index++; - loadDefaultValuePerFace(&(m.face[index + offsetFace]), m, info->mask); - m.face[index + offsetFace].V(0) = &(m.vert[i * xDimension + j + offsetVertex]); - m.face[index + offsetFace].V(1) = &(m.vert[(i + 1) * xDimension + j + offsetVertex]); - m.face[index + offsetFace].V(2) = &(m.vert[(i + 1) * xDimension + j + 1 + offsetVertex]); - //Load color per face - if (m.HasPerFaceColor() && colorPerVertex == "false" && !colorList.isEmpty()) - getColor(colorList, colorComponent, index * colorComponent, m.face[index +offsetFace].C()); - //Load normal per face - if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) - getNormal(normalList, index * 3, m.face[index + offsetFace].N(), tMatrix); - //Load texture coordinate per wedge - if (!m.HasPerVertexTexCoord() && m.HasPerWedgeTexCoord() && (info->mask & MeshModel::IOM_WEDGTEXCOORD)) - { - getTextureCoord(texture, (i * xDimension + j)*2, m.vert[i * xDimension + j + offsetVertex].cP(), m.face[index + offsetFace].WT(0), tMatrix); - getTextureCoord(texture, ((i + 1) * xDimension + j)*2, m.vert[(i + 1) * xDimension + j + offsetVertex].cP(), m.face[index + offsetFace].WT(1), tMatrix); - getTextureCoord(texture, ((i + 1) * xDimension + j + 1)*2, m.vert[(i + 1) * xDimension + j + 1 + offsetVertex].cP(), m.face[index + offsetFace].WT(2), tMatrix); + int val[3][2] = {{i, j}, {i+1, j+1}, {i, j+1}}; + if (ff == 1) + { + val[1][1] = j; + val[2][0] = i+1; + } + loadDefaultValuePerFace(&(m.face[index + offsetFace]), m, info->mask); + for (int tt = 0; tt < 3; tt++) + { + m.face[index + offsetFace].V(tt) = &(m.vert[val[tt][0] * xDimension + val[tt][1] + offsetVertex]); + //Load texture coordinate per wedge + if (!m.HasPerVertexTexCoord() && m.HasPerWedgeTexCoord() && (info->mask & MeshModel::IOM_WEDGTEXCOORD)) + getTextureCoord(texture, (val[tt][0] * xDimension + val[tt][1])*2, m.vert[val[tt][0] * xDimension + val[tt][1] + offsetVertex].cP(), m.face[index + offsetFace].WT(0), tMatrix); + } + //Load color per face + if (m.HasPerFaceColor() && colorPerVertex == "false" && !colorList.isEmpty()) + getColor(colorList, colorComponent, (index + ff) * colorComponent, m.face[index + offsetFace].C()); + //Load normal per face + if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) + getNormal(normalList, (index + ff) * 3, m.face[index + offsetFace].N(), tMatrix); + index++; } } } + info->numvert++; + if ((cb !=NULL) && (info->numvert % 10)==0) (*cb)(10 + 80*info->numvert/info->numface, "Loading X3D Object..."); return E_NOERROR; } @@ -1363,11 +1505,10 @@ namespace io { const QStringList& colorList, const QStringList& normalList, int colorComponent, + OpenMeshType* subMesh, AdditionalInfoX3D* info, - CallBackPos *cb=0) + CallBackPos *cb) { - info->numvert++; - if ((cb !=NULL) && (info->numvert % 5)==0) (*cb)(20 + 60*(info->numvert)/max(info->numface, info->numvert), "Loading X3D Object..."); QStringList coordIndex; findAndParseAttribute(coordIndex, geometry, "coordIndex", ""); if (!coordIndex.isEmpty()) @@ -1382,6 +1523,8 @@ namespace io { int nVertex = coordList.size()/3; //Load vertex in the mesh vcg::tri::Allocator::AddVertices(m, nVertex); + vcg::tri::Allocator::AddVertices(*subMesh, nVertex); + std::vector remap(m.vert.size(), -1); for (int vv = 0; vv < nVertex; vv++) { vcg::Point4f tmp = tMatrix * vcg::Point4f(coordList.at(vv*3).toFloat(), coordList.at(vv*3 + 1).toFloat(), coordList.at(vv*3 + 2).toFloat(), 1.0); @@ -1396,10 +1539,17 @@ namespace io { //Load texture coordinate per vertex if (m.HasPerVertexTexCoord() && texCoordIndex.isEmpty()) getTextureCoord(texture, vv * 2, m.vert[offset + vv].cP(), m.vert[offset + vv].T(), tMatrix); + //Load vertex in the subMesh + vcg::tri::Append::ImportVertex(subMesh->vert[vv], m.vert[offset + vv]); + (*subMesh).vert[vv].P() = vcg::Point3f(coordList.at(vv*3).toFloat(), coordList.at(vv*3 + 1).toFloat(), coordList.at(vv*3 + 2).toFloat()); + if (m.HasPerVertexNormal() && normalPerVertex == "true" && !normalList.isEmpty() && normalIndex.isEmpty()) + getNormal(normalList, vv*3, subMesh->vert[vv].N(), vcg::Matrix44f::Identity()); + remap[offset + vv] = vv; } int ci = 0; int initPolygon; int nPolygon = 0; + int smFaceIndex = 0; //For each polygon while(ci < coordIndex.size()) { @@ -1427,11 +1577,20 @@ namespace io { //Tesselate polygon polygonVect.push_back(polygon); std::vector indexVect; - vcg::glu_tesselator::tesselate(polygonVect, indexVect); + if (polygonVect.size() == 3) + { + indexVect.push_back(0); + indexVect.push_back(1); + indexVect.push_back(2); + } + else + vcg::glu_tesselator::tesselate(polygonVect, indexVect); //Load the face obtained by tessellation int nFace = indexVect.size()/3; int offsetFace = m.face.size(); vcg::tri::Allocator::AddFaces(m, nFace); + vcg::tri::Allocator::AddFaces((*subMesh), nFace); + vcg::Point3f normals[3]; for (int ff = 0; ff < nFace; ff++) { loadDefaultValuePerFace(&(m.face[ff + offsetFace]), m, info->mask); @@ -1440,16 +1599,13 @@ namespace io { int index = coordIndex.at(indexVect.at(tt + ff*3) + initPolygon).toInt(); m.face[ff + offsetFace].V(tt) = &(m.vert[index + offset]); //Load per wedge color - if (m.HasPerWedgeColor() && colorPerVertex == "true" && !colorList.isEmpty() && !colorIndex.isEmpty()) - { - if (!colorIndex.isEmpty() && index < colorIndex.size()) + if (m.HasPerWedgeColor() && colorPerVertex == "true" && !colorList.isEmpty() && !colorIndex.isEmpty() && index < colorIndex.size()) getColor(colorList, colorComponent, colorIndex.at(indexVect.at(tt + ff*3) + initPolygon).toInt() * colorComponent, m.face[ff + offsetFace].WC(tt)); - } //Load per wedge normal - if (m.HasPerWedgeNormal() && normalPerVertex == "true" && !normalList.isEmpty()) + if (m.HasPerWedgeNormal() && normalPerVertex == "true" && !normalList.isEmpty() && !normalIndex.isEmpty() && index < normalIndex.size()) { - if (!normalIndex.isEmpty() && index < normalIndex.size()) - getNormal(normalList, normalIndex.at(indexVect.at(tt + ff*3) + initPolygon).toInt() * 3, m.face[ff + offsetFace].WN(tt), tMatrix); + getNormal(normalList, normalIndex.at(indexVect.at(tt + ff*3) + initPolygon).toInt() * 3, normals[tt], vcg::Matrix44f::Identity()); + transformNormal(normals[tt], tMatrix, m.face[ff + offsetFace].WN(tt)); } //Load per wegde texture coordinate if(m.HasPerWedgeTexCoord() && (info->mask & MeshModel::IOM_WEDGTEXCOORD)) @@ -1464,9 +1620,10 @@ namespace io { if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) { if (!normalIndex.isEmpty() && ff < normalIndex.size() && normalIndex.at(ff).toInt() > -1) - getNormal(normalList, normalIndex.at(nPolygon).toInt() * 3, m.face[ff + offsetFace].N(), tMatrix); + getNormal(normalList, normalIndex.at(nPolygon).toInt() * 3, normals[0], vcg::Matrix44f::Identity()); else - getNormal(normalList, nPolygon*3, m.face[ff + offsetFace].N(), tMatrix); + getNormal(normalList, nPolygon*3, normals[0], vcg::Matrix44f::Identity()); + transformNormal(normals[0], tMatrix, m.face[ff + offsetFace].N()); } //Load per face color if(m.HasPerFaceColor() && colorPerVertex == "false" && !colorList.isEmpty()) @@ -1476,10 +1633,20 @@ namespace io { else getColor(colorList, colorComponent, nPolygon*colorComponent, m.face[ff + offsetFace].C()); } + //Copy face in the subMesh + vcg::tri::Append::ImportFace((*subMesh), m, subMesh->face[smFaceIndex], m.face[ff + offsetFace], remap); + if (m.HasPerWedgeNormal() && normalPerVertex == "true" && !normalList.isEmpty() && !normalIndex.isEmpty()) + for (int i = 0; i < 3; i++) + subMesh->face[smFaceIndex].WN(i) = normals[i]; + if (m.HasPerFaceNormal() && normalPerVertex == "false" && !normalList.isEmpty()) + subMesh->face[smFaceIndex].N() = normals[0]; + smFaceIndex++; } nPolygon++; } } + info->numvert++; + if (cb !=NULL) (*cb)(10 + 80*info->numvert/info->numface, "Loading X3D Object..."); return E_NOERROR; } @@ -1493,10 +1660,8 @@ namespace io { const QStringList& colorList, int colorComponent, AdditionalInfoX3D* info, - CallBackPos *cb=0) + CallBackPos *cb) { - info->numvert++; - if ((cb !=NULL) && (info->numvert % 5)==0) (*cb)(20 + 60*(info->numvert)/max(info->numface, info->numvert), "Loading X3D Object..."); //Load vertex in the mesh int offset = m.vert.size(); int nVertex = coordList.size()/3; @@ -1511,6 +1676,8 @@ namespace io { if (m.HasPerVertexColor() && !colorList.isEmpty()) getColor(colorList, colorComponent, vv*colorComponent, m.vert[vv + offset].C()); } + info->numvert++; + if ((cb !=NULL) && (info->numvert % 10)==0) (*cb)(10 + 80*info->numvert/info->numface, "Loading X3D Object..."); return E_NOERROR; } @@ -1520,10 +1687,8 @@ namespace io { OpenMeshType& m, const vcg::Matrix44f tMatrix, AdditionalInfoX3D* info, - CallBackPos *cb=0) + CallBackPos *cb) { - info->numvert++; - if ((cb !=NULL) && (info->numvert % 5)==0) (*cb)(20 + 60*(info->numvert)/max(info->numface, info->numvert), "Loading X3D Object..."); //Load vertex in the mesh int offset = m.vert.size(); QStringList pointList; @@ -1540,6 +1705,8 @@ namespace io { loadDefaultValuePerVertex(&(m.vert[vv + offset]), m, info->mask); } } + info->numvert++; + if ((cb !=NULL) && (info->numvert % 10)==0) (*cb)(10 + 80*info->numvert/info->numface, "Loading X3D Object..."); return E_NOERROR; } @@ -1550,10 +1717,8 @@ namespace io { OpenMeshType& m, const vcg::Matrix44f tMatrix, AdditionalInfoX3D* info, - CallBackPos *cb=0) + CallBackPos *cb) { - info->numvert++; - if ((cb !=NULL) && (info->numvert % 5)==0) (*cb)(20 + 60*(info->numvert)/max(info->numface, info->numvert), "Loading X3D Object..."); QStringList vertices; findAndParseAttribute(vertices, geometry, "vertices", ""); if (!vertices.isEmpty()) @@ -1604,6 +1769,8 @@ namespace io { m.face[faceIndex].V(tt) = &(m.vert[vertexFaceIndex.at(tt + ff*3) + offsetVertex]); } } + info->numvert++; + if ((cb !=NULL) && (info->numvert % 10)==0) (*cb)(10 + 80*info->numvert/info->numface, "Loading X3D Object..."); return E_NOERROR; } @@ -1688,13 +1855,13 @@ namespace io { vcg::Matrix33f matrix, tmp; matrix.SetIdentity(); QStringList coordList, center; - findAndParseAttribute(center, elem, "center", "0 0"); + findAndParseAttribute(center, elem, "center", ""); if (center.size() == 2) { matrix[0][2] = -center.at(0).toFloat(); matrix[1][2] = -center.at(1).toFloat(); } - findAndParseAttribute(coordList, elem, "scale", "1 1"); + findAndParseAttribute(coordList, elem, "scale", ""); if(coordList.size() == 2) { tmp.SetIdentity(); @@ -1702,7 +1869,7 @@ namespace io { tmp[1][1] = coordList.at(1).toFloat(); matrix *= tmp; } - findAndParseAttribute(coordList, elem, "rotation", "0"); + findAndParseAttribute(coordList, elem, "rotation", ""); if(coordList.size() == 1) { tmp.Rotate(math::ToDeg(coordList.at(0).toFloat()), vcg::Point3f(0, 0, 1)); @@ -1715,7 +1882,7 @@ namespace io { tmp[1][2] = center.at(1).toFloat(); matrix *= tmp; } - findAndParseAttribute(coordList, elem, "traslation", "0 0"); + findAndParseAttribute(coordList, elem, "traslation", ""); if(coordList.size() == 2) { tmp.SetIdentity(); @@ -1733,28 +1900,28 @@ namespace io { vcg::Matrix44f t, tmp; t.SetIdentity(); QStringList coordList, center, scale; - findAndParseAttribute(coordList, root, "translation", "0 0 0"); + findAndParseAttribute(coordList, root, "translation", ""); if(coordList.size() == 3) t.SetTranslate(coordList.at(0).toFloat(), coordList.at(1).toFloat(), coordList.at(2).toFloat()); - findAndParseAttribute(center, root, "center", "0 0 0"); + findAndParseAttribute(center, root, "center", ""); if(center.size() == 3) { tmp.SetTranslate(center.at(0).toFloat(), center.at(1).toFloat(), center.at(2).toFloat()); t *= tmp; } - findAndParseAttribute(coordList, root, "rotation", "0 0 1 0"); + findAndParseAttribute(coordList, root, "rotation", ""); if(coordList.size() == 4) { tmp.SetRotate(coordList.at(3).toFloat(), vcg::Point3f(coordList.at(0).toFloat(), coordList.at(1).toFloat(), coordList.at(2).toFloat())); t *= tmp; } - findAndParseAttribute(scale, root, "scaleOrientation", "0 0 1 0"); + findAndParseAttribute(scale, root, "scaleOrientation", ""); if(scale.size() == 4) { tmp.SetRotate(scale.at(3).toFloat(), vcg::Point3f(scale.at(0).toFloat(), scale.at(1).toFloat(), scale.at(2).toFloat())); t *= tmp; } - findAndParseAttribute(coordList, root, "scale", "1 1 1"); + findAndParseAttribute(coordList, root, "scale", ""); if(coordList.size() == 3) { tmp.SetScale(coordList.at(0).toFloat(), coordList.at(1).toFloat(), coordList.at(2).toFloat()); @@ -1780,8 +1947,9 @@ namespace io { static int NavigateInline(OpenMeshType& m, QDomElement root, const vcg::Matrix44f tMatrix, + std::map& subMeshMap, AdditionalInfoX3D* info, - CallBackPos *cb=0) + CallBackPos *cb) { QString load = root.attribute("load", "true"); if (load != "true") return E_NOERROR; @@ -1814,7 +1982,7 @@ namespace io { QDomElement first = iter->second->firstChildElement("X3D"); std::map newDefMap; std::map newProtoDeclMap; - int result = NavigateScene(m, first, tMatrix, newDefMap, newProtoDeclMap, info, cb); + int result = NavigateScene(m, first, tMatrix, newDefMap, newProtoDeclMap, subMeshMap, info, cb); if (result != E_NOERROR) return result; info->filenameStack.pop_back(); @@ -1888,8 +2056,9 @@ namespace io { const vcg::Matrix44f tMatrix, std::map& defMap, std::map& protoDeclareMap, + std::map& subMeshMap, AdditionalInfoX3D* info, - CallBackPos *cb=0) + CallBackPos *cb) { QString name = root.attribute("name"); std::map fields; @@ -1941,7 +2110,7 @@ namespace io { QDomElement body = protoInstance.firstChildElement("ProtoBody"); std::map newDefMap; std::map newProtoDeclMap; - result = NavigateScene(m, body, tMatrix, newDefMap, newProtoDeclMap, info, cb); + result = NavigateScene(m, body, tMatrix, newDefMap, newProtoDeclMap, subMeshMap, info, cb); if (result != E_NOERROR) return result; if (filename != "") @@ -1949,6 +2118,22 @@ namespace io { return E_NOERROR; } + //Transform the input normal + inline static void transformNormal(const vcg::Point3f& normal, const vcg::Matrix44f& tMatrix, vcg::Point3f& dest) + { + vcg::Matrix44f intr44 = vcg::Inverse(tMatrix); + vcg::Transpose(intr44); + Matrix33f intr33; + for(unsigned int rr = 0; rr < 2; ++rr) + { + for(unsigned int cc = 0;cc < 2;++cc) + intr33[rr][cc] = intr44[rr][cc]; + } + dest = intr33 * normal; + dest.Normalize(); + } + + //If the index is valid, return the normal of index 'index' inline static void getNormal(const QStringList& list, int index, vcg::Point3f& dest, const vcg::Matrix44f& tMatrix) @@ -1956,7 +2141,8 @@ namespace io { if(!list.isEmpty() && (index + 2) < list.size()) { vcg::Point3f normal(list.at(index).toFloat(), list.at(index + 1).toFloat(), list.at( index+ 2).toFloat()); - vcg::Matrix44f intr44 = vcg::Inverse(tMatrix); + transformNormal(normal, tMatrix, dest); + /*vcg::Matrix44f intr44 = vcg::Inverse(tMatrix); vcg::Transpose(intr44); Matrix33f intr33; for(unsigned int rr = 0; rr < 2; ++rr) @@ -1965,7 +2151,7 @@ namespace io { intr33[rr][cc] = intr44[rr][cc]; } normal = intr33 * normal; - dest = normal.Normalize(); + dest = normal.Normalize();*/ } } @@ -2042,8 +2228,9 @@ namespace io { const vcg::Matrix44f tMatrix, std::map& defMap, std::map& protoDeclareMap, + std::map& subMeshMap, AdditionalInfoX3D* info, - CallBackPos *cb=0) + CallBackPos *cb) { if (root.isNull()) return E_NOERROR; int result = solveDefUse(root, defMap, root, info); @@ -2054,7 +2241,7 @@ namespace io { QDomElement child = root.firstChildElement(); while(!child.isNull()) { - int result = NavigateScene(m, child, t, defMap, protoDeclareMap, info, cb); + int result = NavigateScene(m, child, t, defMap, protoDeclareMap, subMeshMap, info, cb); if (result != E_NOERROR) return result; child = child.nextSiblingElement(); @@ -2063,7 +2250,7 @@ namespace io { } if (root.tagName() == "Inline") - return NavigateInline(m, root, tMatrix, info, cb); + return NavigateInline(m, root, tMatrix, subMeshMap, info, cb); if (root.tagName() == "ProtoDeclare") { @@ -2081,10 +2268,12 @@ namespace io { return NavigateExternProtoDeclare(root, tMatrix, protoDeclareMap, info); if (root.tagName() == "ProtoInstance") - return NavigateProtoInstance(m, root, tMatrix, defMap, protoDeclareMap, info, cb); + return NavigateProtoInstance(m, root, tMatrix, defMap, protoDeclareMap, subMeshMap, info, cb); if (root.tagName() == "Shape") { + if (!loadSubMesh(root, m, subMeshMap, tMatrix, info, cb)) return E_NOERROR; + QString def = root.attribute("DEF"); std::vector validTexture; std::vector textureInfo; QDomNodeList textureTransformList; @@ -2193,17 +2382,26 @@ namespace io { break; } } + OpenMeshType* subMesh = new OpenMeshType(); + if (info->mask & MeshModel::IOM_WEDGTEXCOORD) + (*subMesh).face.EnableWedgeTex(); + if (info->mask & MeshModel::IOM_FACECOLOR) + (*subMesh).face.EnableColor(); + result = -1; //Load geometry in the mesh if (geometry.tagName() == "TriangleSet" || geometry.tagName() == "TriangleFanSet" || geometry.tagName() == "TriangleStripSet" || geometry.tagName() == "QuadSet") - return LoadSet(geometry, m, tMatrix, texture, coordList, colorList, normalList, colorComponent, info, cb); + result = LoadSet(geometry, m, tMatrix, texture, coordList, colorList, normalList, colorComponent, subMesh, info, cb); else if (geometry.tagName() == "IndexedTriangleSet" || geometry.tagName() == "IndexedTriangleFanSet" || geometry.tagName() == "IndexedTriangleStripSet" || geometry.tagName() == "IndexedQuadSet") - return LoadIndexedSet(geometry, m, tMatrix, texture, coordList, colorList, normalList, colorComponent, info, cb); + result = LoadIndexedSet(geometry, m, tMatrix, texture, coordList, colorList, normalList, colorComponent, subMesh, info, cb); else if (geometry.tagName() == "ElevationGrid") return LoadElevationGrid(geometry, m, tMatrix, texture, colorList, normalList, colorComponent, info, cb); else if (geometry.tagName() == "IndexedFaceSet") - return LoadIndexedFaceSet(geometry, m, tMatrix, texture, coordList, colorList, normalList, colorComponent, info, cb); + result = LoadIndexedFaceSet(geometry, m, tMatrix, texture, coordList, colorList, normalList, colorComponent, subMesh, info, cb); else if (geometry.tagName() == "PointSet") return LoadPointSet(geometry, m, tMatrix, coordList, colorList, colorComponent, info, cb); + if (result == E_NOERROR && def != "") + subMeshMap[def] = subMesh; + if (result != -1) return result; } else if (geometry.tagName() == "Polypoint2D") return LoadPolypoint2D(geometry, m, tMatrix, info, cb); @@ -2217,7 +2415,7 @@ namespace io { QDomElement child = root.firstChildElement(); while(!child.isNull()) { - int result = NavigateScene(m, child, tMatrix, defMap, protoDeclareMap, info, cb); + int result = NavigateScene(m, child, tMatrix, defMap, protoDeclareMap, subMeshMap, info, cb); if (result != E_NOERROR) return result; child = child.nextSiblingElement(); @@ -2253,7 +2451,7 @@ namespace io { //merge all meshes in the x3d's file in the templeted mesh m - static int Open(OpenMeshType& m, const char* filename, AdditionalInfoX3D*& info, CallBackPos *cb=0) + static int Open(OpenMeshType& m, const char* filename, AdditionalInfoX3D*& info, CallBackPos *cb) { vcg::Matrix44f tMatrix; tMatrix.SetIdentity(); @@ -2261,15 +2459,20 @@ namespace io { matrixStack.push_back(tMatrix); std::map defMap; std::map protoDeclareMap; + std::map subMeshMap; QDomNodeList scene = info->doc->elementsByTagName("Scene"); info->filenameStack.clear(); info->filenameStack.push_back(QString(filename)); - if ((cb !=NULL) && (info->numvert % 5)==0) (*cb)(20, "Loading X3D Object..."); + if ((cb !=NULL) && (info->numvert % 5)==0) (*cb)(10, "Loading X3D Object..."); if (scene.size() == 0) return E_NO3DSCENE; if (scene.size() > 1) return E_MULTISCENE; - return NavigateScene(m, scene.at(0).toElement(), tMatrix, defMap, protoDeclareMap, info, cb); + int result = NavigateScene(m, scene.at(0).toElement(), tMatrix, defMap, protoDeclareMap, subMeshMap, info, cb); + std::map::const_iterator iter; + for(iter= subMeshMap.begin(); iter != subMeshMap.end(); iter++) + delete(iter->second); + return result; }