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 #ifndef __VCGLIB_IMPORT_OBJ
00026 #define __VCGLIB_IMPORT_OBJ
00027
00028 #include <wrap/callback.h>
00029 #include <wrap/io_trimesh/io_mask.h>
00030 #include <wrap/io_trimesh/io_material.h>
00031 #include <wrap/io_trimesh/io_fan_tessellator.h>
00032 #ifdef __gl_h_
00033 #include <wrap/gl/glu_tesselator.h>
00034 #endif
00035 #include <vcg/space/color4.h>
00036
00037
00038 #include <fstream>
00039 #include <string>
00040 #include <vector>
00041
00042
00043 namespace vcg {
00044 namespace tri {
00045 namespace io {
00046
00051 template <class OpenMeshType>
00052 class ImporterOBJ
00053 {
00054 public:
00055 static int &MRGBLineCount(){static int _MRGBLineCount=0; return _MRGBLineCount;}
00056
00057 typedef typename OpenMeshType::VertexPointer VertexPointer;
00058 typedef typename OpenMeshType::ScalarType ScalarType;
00059 typedef typename OpenMeshType::VertexType VertexType;
00060 typedef typename OpenMeshType::EdgeType EdgeType;
00061 typedef typename OpenMeshType::FaceType FaceType;
00062 typedef typename OpenMeshType::VertexIterator VertexIterator;
00063 typedef typename OpenMeshType::FaceIterator FaceIterator;
00064 typedef typename OpenMeshType::CoordType CoordType;
00065
00066 class Info
00067 {
00068 public:
00069
00070 Info()
00071 {
00072 mask = 0;
00073 cb = 0;
00074 numTexCoords=0;
00075 }
00076
00078 int mask;
00079
00081
00082 CallBackPos *cb;
00083
00085 int numVertices;
00087 int numEdges;
00090 int numFaces;
00092 int numTexCoords;
00094 int numNormals;
00095
00096 };
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 struct ObjIndexedFace
00108 {
00109 void set(const int & num){v.resize(num);n.resize(num); t.resize(num);}
00110 std::vector<int> v;
00111 std::vector<int> n;
00112 std::vector<int> t;
00113 int tInd;
00114 bool edge[3];
00115 Color4b c;
00116 };
00117
00118 struct ObjEdge
00119 {
00120 int v0;
00121 int v1;
00122 };
00123
00124 struct ObjTexCoord
00125 {
00126 float u;
00127 float v;
00128 };
00129
00130 enum OBJError {
00131
00132 E_NOERROR = 0*2+0,
00133
00134
00135 E_NON_CRITICAL_ERROR = 0*2+1,
00136 E_MATERIAL_FILE_NOT_FOUND = 1*2+1,
00137 E_MATERIAL_NOT_FOUND = 2*2+1,
00138 E_TEXTURE_NOT_FOUND = 3*2+1,
00139 E_VERTICES_WITH_SAME_IDX_IN_FACE = 4*2+1,
00140 E_LESS_THAN_3_VERT_IN_FACE = 5*2+1,
00141
00142
00143 E_CANTOPEN = 6*2+0,
00144 E_UNEXPECTED_EOF = 7*2+0,
00145 E_ABORTED = 8*2+0,
00146 E_NO_VERTEX = 9*2+0,
00147 E_NO_FACE =10*2+0,
00148 E_BAD_VERTEX_STATEMENT =11*2+0,
00149 E_BAD_VERT_TEX_STATEMENT =12*2+0,
00150 E_BAD_VERT_NORMAL_STATEMENT =13*2+0,
00151 E_BAD_VERT_INDEX =14*2+0,
00152 E_BAD_VERT_TEX_INDEX =15*2+0,
00153 E_BAD_VERT_NORMAL_INDEX =16*2+0,
00154 E_LESS_THAN_4_VERT_IN_QUAD =17*2+0
00155 };
00156
00157
00158 static bool ErrorCritical(int err)
00159 {
00160 if (err==0) return false;
00161 if (err&1) return false;
00162 return true;
00163 }
00164
00165 static const char* ErrorMsg(int error)
00166 {
00167 const int MAXST = 18;
00168 static const char* obj_error_msg[MAXST] =
00169 {
00170 "No errors",
00171
00172 "Material library file wrong or not found, a default white material is used",
00173 "Some materials definitions were not found, a default white material is used where no material was available",
00174 "Texture file not found",
00175 "Identical vertex indices found in the same faces -- faces ignored",
00176 "Faces with fewer than 3 vertices -- faces ignored",
00177
00178 "Can't open file",
00179 "Premature End of File. File truncated?",
00180 "Loading aborted by user",
00181 "No vertex found",
00182 "No face found",
00183 "Vertex statement with fewer than 3 coords",
00184 "Texture coords statement with fewer than 2 coords",
00185 "Vertex normal statement with fewer than 3 coords",
00186 "Bad vertex index in face",
00187 "Bad texture coords index in face",
00188 "Bad vertex normal index in face",
00189 "Quad faces with number of corners different from 4"
00190 };
00191
00192 error >>= 1;
00193
00194 if( (error>=MAXST) || (error<0) ) return "Unknown error";
00195 else return obj_error_msg[error];
00196 }
00197
00198
00199
00200
00201 static bool GoodObjIndex(int &index, const int maxVal)
00202 {
00203 if (index > maxVal) return false;
00204 if (index < 0)
00205 {
00206 index += maxVal+1;
00207 if (index<0 || index > maxVal) return false;
00208 }
00209 return true;
00210 }
00211
00212 static int Open(OpenMeshType &mesh, const char *filename, int &loadmask, CallBackPos *cb=0)
00213 {
00214 Info oi;
00215 oi.mask=0;
00216 oi.cb=cb;
00217 int ret=Open(mesh,filename,oi);
00218 loadmask=oi.mask;
00219 return ret;
00220 }
00221
00229 static int Open( OpenMeshType &m, const char * filename, Info &oi)
00230 {
00231 int result = E_NOERROR;
00232
00233 m.Clear();
00234 CallBackPos *cb = oi.cb;
00235
00236
00237 if (oi.mask == 0)
00238 LoadMask(filename, oi);
00239
00240 const int inputMask = oi.mask;
00241 Mask::ClampMask<OpenMeshType>(m,oi.mask);
00242
00243 if (oi.numVertices == 0)
00244 return E_NO_VERTEX;
00245
00246
00247
00248
00249
00250
00251 std::ifstream stream(filename);
00252 if (stream.fail())
00253 {
00254 stream.close();
00255 return E_CANTOPEN;
00256 }
00257 std::vector<Material> materials;
00258 std::vector<ObjTexCoord> texCoords;
00259 std::vector<CoordType> normals;
00260 std::vector<ObjIndexedFace> indexedFaces;
00261 std::vector< std::string > tokens;
00262 std::string header;
00263
00264 short currentMaterialIdx = 0;
00265 Color4b currentColor=Color4b::LightGray;
00266
00267
00268 Material defaultMaterial;
00269 materials.push_back(defaultMaterial);
00270
00271 int numVertices = 0;
00272 int numEdges = 0;
00273 int numTriangles = 0;
00274 int numTexCoords = 0;
00275 int numVNormals = 0;
00276
00277 int numVerticesPlusFaces = oi.numVertices + oi.numFaces;
00278 int extraTriangles=0;
00279
00280 VertexIterator vi = vcg::tri::Allocator<OpenMeshType>::AddVertices(m,oi.numVertices);
00281
00282
00283 std::vector<ObjEdge> ev;
00284 std::vector<Color4b> vertexColorVector;
00285 ObjIndexedFace ff;
00286 const char *loadingStr = "Loading";
00287 while (!stream.eof())
00288 {
00289 tokens.clear();
00290 TokenizeNextLine(stream, tokens,&vertexColorVector);
00291
00292 unsigned int numTokens = static_cast<unsigned int>(tokens.size());
00293 if (numTokens > 0)
00294 {
00295 header.clear();
00296 header = tokens[0];
00297
00298
00299 if ((cb !=NULL) && (((numTriangles + numVertices)%100)==0) && !(*cb)((100*(numTriangles + numVertices))/numVerticesPlusFaces, loadingStr))
00300 {
00301 stream.close();
00302 return E_ABORTED;
00303 }
00304 if (header.compare("v")==0)
00305 {
00306 loadingStr="Vertex Loading";
00307 if (numTokens < 4)
00308 {
00309 stream.close();
00310 return E_BAD_VERTEX_STATEMENT;
00311 }
00312 (*vi).P()[0] = (ScalarType) atof(tokens[1].c_str());
00313 (*vi).P()[1] = (ScalarType) atof(tokens[2].c_str());
00314 (*vi).P()[2] = (ScalarType) atof(tokens[3].c_str());
00315 ++numVertices;
00316
00317
00318
00319 if (((oi.mask & vcg::tri::io::Mask::IOM_VERTCOLOR) != 0) && (HasPerVertexColor(m)))
00320 {
00321 if(numTokens>=7)
00322 {
00323 ScalarType rf(atof(tokens[4].c_str())), gf(atof(tokens[5].c_str())), bf(atof(tokens[6].c_str()));
00324 ScalarType scaling = (rf<=1 && gf<=1 && bf<=1) ? 255. : 1;
00325
00326 unsigned char r = (unsigned char) ((ScalarType) atof(tokens[4].c_str()) * scaling);
00327 unsigned char g = (unsigned char) ((ScalarType) atof(tokens[5].c_str()) * scaling);
00328 unsigned char b = (unsigned char) ((ScalarType) atof(tokens[6].c_str()) * scaling);
00329 unsigned char alpha = (unsigned char) ((numTokens>=8 ? (ScalarType) atof(tokens[7].c_str()) : 1) * scaling);
00330 (*vi).C() = Color4b(r, g, b, alpha);
00331 }
00332 else
00333 {
00334 (*vi).C() = currentColor;
00335 }
00336 }
00337
00338 ++vi;
00339 }
00340 else if (header.compare("vt")==0)
00341 {
00342 loadingStr="Vertex Texture Loading";
00343
00344 if (numTokens < 3)
00345 {
00346 stream.close();
00347 return E_BAD_VERT_TEX_STATEMENT;
00348 }
00349 ObjTexCoord t;
00350 t.u = static_cast<float>(atof(tokens[1].c_str()));
00351 t.v = static_cast<float>(atof(tokens[2].c_str()));
00352 texCoords.push_back(t);
00353
00354 numTexCoords++;
00355 }
00356 else if (header.compare("vn")==0)
00357 {
00358 loadingStr="Vertex Normal Loading";
00359
00360 if (numTokens != 4)
00361 {
00362 stream.close();
00363 return E_BAD_VERT_NORMAL_STATEMENT;
00364 }
00365 CoordType n;
00366 n[0] = (ScalarType) atof(tokens[1].c_str());
00367 n[1] = (ScalarType) atof(tokens[2].c_str());
00368 n[2] = (ScalarType) atof(tokens[3].c_str());
00369 normals.push_back(n);
00370
00371 numVNormals++;
00372 }
00373 else if ( header.compare("l")==0 )
00374 {
00375 loadingStr = "Edge Loading";
00376
00377 if (numTokens < 3)
00378 {
00379 result = E_LESS_THAN_3_VERT_IN_FACE;
00380 continue;
00381 }
00382
00383 ObjEdge e = { (atoi(tokens[1].c_str()) - 1),
00384 (atoi(tokens[2].c_str()) - 1) };
00385 ev.push_back(e);
00386
00387 numEdges++;
00388 }
00389 else if( (header.compare("f")==0) || (header.compare("q")==0) )
00390 {
00391 loadingStr="Face Loading";
00392
00393 int vertexesPerFace = static_cast<int>(tokens.size()-1);
00394
00395 bool QuadFlag = false;
00396 if(header.compare("q")==0) {
00397 QuadFlag=true;
00398 if (vertexesPerFace != 4) {
00399 stream.close();
00400 return E_LESS_THAN_4_VERT_IN_QUAD;
00401 }
00402 }
00403
00404
00405 if (vertexesPerFace < 3) {
00406
00407 extraTriangles--;
00408 result = E_LESS_THAN_3_VERT_IN_FACE;
00409 continue;
00410 }
00411
00412
00413 if( (vertexesPerFace>3) && OpenMeshType::FaceType::HasPolyInfo() )
00414 {
00415
00416 ff.set(vertexesPerFace);
00417 for(int i=0;i<vertexesPerFace;++i) {
00418 SplitToken(tokens[i+1], ff.v[i], ff.n[i], ff.t[i], inputMask);
00419 if(QuadFlag) ff.v[i]++;
00420 }
00421 if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD )
00422 {
00423
00424 for(int i=0;i<vertexesPerFace;i++)
00425 if(!GoodObjIndex(ff.t[i],oi.numTexCoords))
00426 {
00427 stream.close();
00428 return E_BAD_VERT_TEX_INDEX;
00429 }
00430 ff.tInd=materials[currentMaterialIdx].index;
00431 }
00432
00433
00434 std::vector<int> tmp = ff.v;
00435 std::sort(tmp.begin(),tmp.end());
00436 std::unique(tmp.begin(),tmp.end());
00437 if(tmp.size() != ff.v.size()) {
00438 result = E_VERTICES_WITH_SAME_IDX_IN_FACE;
00439 extraTriangles--;
00440 continue;
00441 }
00442
00443 for(int i=0;i<vertexesPerFace;i++)
00444 if(!GoodObjIndex(ff.v[i],numVertices))
00445 {
00446 stream.close();
00447 return E_BAD_VERT_INDEX;
00448 }
00449
00450 if(( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) ||
00451 ( oi.mask & vcg::tri::io::Mask::IOM_VERTNORMAL ) )
00452 {
00453
00454 for(int i=0;i<vertexesPerFace;i++)
00455 if(!GoodObjIndex(ff.n[i],numVNormals))
00456 {
00457 stream.close();
00458 return E_BAD_VERT_NORMAL_INDEX;
00459 }
00460 }
00461
00462
00463 if( oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR)
00464 ff.c = currentColor;
00465
00466 ++numTriangles;
00467 indexedFaces.push_back(ff);
00468
00469
00470 }
00471 else
00472 {
00473
00474 std::vector<std::vector<vcg::Point3f> > polygonVect(1);
00475 polygonVect[0].resize(vertexesPerFace);
00476 std::vector<int> indexVVect(vertexesPerFace);
00477 std::vector<int> indexNVect(vertexesPerFace);
00478 std::vector<int> indexTVect(vertexesPerFace);
00479 std::vector<int> indexTriangulatedVect;
00480
00481 for(int pi=0;pi<vertexesPerFace;++pi)
00482 {
00483 SplitToken(tokens[pi+1], indexVVect[pi],indexNVect[pi],indexTVect[pi], inputMask);
00484 if(QuadFlag) indexVVect[pi]++;
00485 GoodObjIndex(indexVVect[pi],numVertices);
00486 GoodObjIndex(indexTVect[pi],oi.numTexCoords);
00487 polygonVect[0][pi].Import(m.vert[indexVVect[pi]].cP());
00488 }
00489 if(vertexesPerFace>3)
00490 oi.mask |= Mask::IOM_BITPOLYGONAL;
00491
00492 if(vertexesPerFace<5)
00493 FanTessellator(polygonVect, indexTriangulatedVect);
00494 else
00495 {
00496 #ifdef __gl_h_
00497
00498 vcg::glu_tesselator::tesselate<vcg::Point3f>(polygonVect, indexTriangulatedVect);
00499 if(indexTriangulatedVect.size()==0)
00500 FanTessellator(polygonVect, indexTriangulatedVect);
00501 #else
00502
00503 FanTessellator(polygonVect, indexTriangulatedVect);
00504 #endif
00505 }
00506 extraTriangles+=((indexTriangulatedVect.size()/3) -1);
00507 #ifdef QT_VERSION
00508 if( int(indexTriangulatedVect.size()/3) != vertexesPerFace-2)
00509 {
00510 qDebug("Warning there is a degenerate poligon of %i verteces that was triangulated into %i triangles",vertexesPerFace,int(indexTriangulatedVect.size()/3));
00511 for(size_t qq=0;qq<polygonVect[0].size();++qq)
00512 qDebug(" (%f %f %f)",polygonVect[0][qq][0],polygonVect[0][qq][1],polygonVect[0][qq][2]);
00513 for(size_t qq=0;qq<tokens.size();++qq) qDebug("<%s>",tokens[qq].c_str());
00514 }
00515 #endif
00516
00517
00518 for(size_t pi=0;pi<indexTriangulatedVect.size();pi+=3)
00519 {
00520 ff.set(3);
00521 int locInd[3];
00522 for(int iii=0;iii<3;++iii)
00523 {
00524 locInd[iii]=indexTriangulatedVect[pi+iii];
00525 ff.v[iii]=indexVVect[ locInd[iii] ];
00526 ff.n[iii]=indexNVect[ locInd[iii] ];
00527
00528 ff.t[iii]=indexTVect[ locInd[iii] ];
00529 }
00530
00531
00532 for(int iii=0;iii<3;++iii)
00533 {
00534 if( (locInd[iii]+1)%vertexesPerFace == locInd[(iii+1)%3]) ff.edge[iii]=false;
00535 else ff.edge[iii]=true;
00536 }
00537
00538 if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD )
00539 {
00540 bool invalid = false;
00541 for(int i=0;i<3;i++)
00542 if(!GoodObjIndex(ff.t[i],oi.numTexCoords))
00543 {
00544
00545 invalid = true;
00546 break;
00547 }
00548 if (invalid) continue;
00549 ff.tInd=materials[currentMaterialIdx].index;
00550 }
00551
00552
00553 if ((ff.v[0] == ff.v[1]) || (ff.v[0] == ff.v[2]) || (ff.v[1] == ff.v[2])) {
00554 result = E_VERTICES_WITH_SAME_IDX_IN_FACE;
00555 extraTriangles--;
00556 continue;
00557 }
00558
00559 {
00560 bool invalid = false;
00561 for(int i=0;i<3;i++)
00562 if(!GoodObjIndex(ff.v[i],numVertices))
00563 {
00564
00565 invalid = true;
00566 break;
00567 }
00568 if (invalid) continue;
00569 }
00570
00571
00572 if ( ( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL ) ||
00573 ( oi.mask & vcg::tri::io::Mask::IOM_VERTNORMAL ) )
00574 {
00575 bool invalid = false;
00576 for(int i=0;i<3;i++)
00577 if(!GoodObjIndex(ff.n[i],numVNormals))
00578 {
00579
00580 invalid = true;
00581 break;
00582 }
00583 if (invalid) continue;
00584 }
00585
00586
00587 if( oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR) ff.c = currentColor;
00588
00589 ++numTriangles;
00590 indexedFaces.push_back(ff);
00591 }
00592
00593 }
00594 }
00595 else if ((header.compare("mtllib")==0) && (tokens.size() > 1))
00596 {
00597
00598 std::string materialFileName = tokens[1];
00599 if (!LoadMaterials( materialFileName.c_str(), materials, m.textures))
00600 result = E_MATERIAL_FILE_NOT_FOUND;
00601 }
00602 else if ((header.compare("usemtl")==0) && (tokens.size() > 1))
00603 {
00604 std::string materialName = tokens[1];
00605 bool found = false;
00606 unsigned i = 0;
00607 while (!found && (i < materials.size()))
00608 {
00609 std::string currentMaterialName = materials[i].materialName;
00610 if (currentMaterialName == materialName)
00611 {
00612 currentMaterialIdx = i;
00613 Material &material = materials[currentMaterialIdx];
00614 Point3f diffuseColor = material.Kd;
00615 unsigned char r = (unsigned char) (diffuseColor[0] * 255.0);
00616 unsigned char g = (unsigned char) (diffuseColor[1] * 255.0);
00617 unsigned char b = (unsigned char) (diffuseColor[2] * 255.0);
00618 unsigned char alpha = (unsigned char) (material.Tr * 255.0);
00619 currentColor= Color4b(r, g, b, alpha);
00620 found = true;
00621 }
00622 ++i;
00623 }
00624
00625 if (!found)
00626 {
00627 currentMaterialIdx = 0;
00628 result = E_MATERIAL_NOT_FOUND;
00629 }
00630 }
00631
00632 }
00633 }
00634 assert((numTriangles +numVertices) == numVerticesPlusFaces+extraTriangles);
00635 vcg::tri::Allocator<OpenMeshType>::AddFaces(m,numTriangles);
00636
00637
00638 if (numEdges > 0)
00639 {
00640 vcg::tri::Allocator<OpenMeshType>::AddEdges(m,numEdges);
00641
00642 assert(m.edge.size() == size_t(m.en));
00643
00644 for(int i=0; i<numEdges; ++i)
00645 {
00646 ObjEdge & e = ev[i];
00647 EdgeType & edge = m.edge[i];
00648
00649 assert(e.v0 >= 0 && size_t(e.v0) < m.vert.size() &&
00650 e.v1 >= 0 && size_t(e.v1) < m.vert.size());
00651
00652
00653 edge.V(0) = &(m.vert[e.v0]);
00654 edge.V(1) = &(m.vert[e.v1]);
00655 }
00656 }
00657
00658
00659
00660
00661 for(int i=0; i<numTriangles; ++i)
00662 {
00663 assert(m.face.size() == size_t(m.fn));
00664 m.face[i].Alloc(indexedFaces[i].v.size());
00665
00666 for(unsigned int j=0;j<indexedFaces[i].v.size();++j)
00667 {
00668 m.face[i].V(j) = &(m.vert[indexedFaces[i].v[j]]);
00669
00670 if (((oi.mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD) != 0) && (HasPerWedgeTexCoord(m)))
00671 {
00672 ObjTexCoord t = texCoords[indexedFaces[i].t[j]];
00673 m.face[i].WT(j).u() = t.u;
00674 m.face[i].WT(j).v() = t.v;
00675 m.face[i].WT(j).n() = indexedFaces[i].tInd;
00676 }
00677 if ( oi.mask & vcg::tri::io::Mask::IOM_VERTTEXCOORD ) {
00678 ObjTexCoord t = texCoords[indexedFaces[i].t[j]];
00679 m.face[i].V(j)->T().u() = t.u;
00680 m.face[i].V(j)->T().v() = t.v;
00681 m.face[i].V(j)->T().n() = indexedFaces[i].tInd;
00682 }
00683 if ( oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL )
00684 {
00685 m.face[i].WN(j).Import(normals[indexedFaces[i].n[j]]);
00686 }
00687
00688 if ( oi.mask & vcg::tri::io::Mask::IOM_VERTNORMAL )
00689 {
00690
00691 m.face[i].V(j)->N().Import(normals[indexedFaces[i].n[j]]);
00692 }
00693
00694
00695 if (indexedFaces[i].edge[j]) m.face[i].SetF(j);
00696 else m.face[i].ClearF(j);
00697 }
00698
00699 if (HasPerFaceNormal(m))
00700 {
00701 if (((oi.mask & vcg::tri::io::Mask::IOM_FACECOLOR) != 0) && (HasPerFaceColor(m)))
00702 {
00703 m.face[i].C() = indexedFaces[i].c;
00704 }
00705
00706 if (((oi.mask & vcg::tri::io::Mask::IOM_WEDGNORMAL) != 0) && (HasPerWedgeNormal(m)))
00707 {
00708
00709 m.face[i].N().Import(m.face[i].WN(0)+m.face[i].WN(1)+m.face[i].WN(2));
00710 }
00711 else
00712 {
00713 m.face[i].N().Import(TriangleNormal(m.face[i]).Normalize());
00714 }
00715 }
00716 }
00717
00718 if(vertexColorVector.size()>0)
00719 {
00720
00721
00722
00723
00724 for(int i=0;i<m.vn;++i)
00725 {
00726 m.vert[i].C()=vertexColorVector[i];
00727 }
00728 }
00729 stream.close();
00730 return result;
00731 }
00732
00733
00740 inline static void TokenizeNextLine(std::ifstream &stream, std::vector< std::string > &tokens, std::vector<Color4b> *colVec)
00741 {
00742 if(stream.eof()) return;
00743 std::string line;
00744 do
00745 {
00746 std::getline(stream, line);
00747 const size_t len = line.length();
00748 if((len > 0) && colVec && line[0] == '#')
00749 {
00750
00751
00752 if((len >= 5) && line[1] == 'M' && line[2] == 'R' && line[3] == 'G' && line[4] == 'B')
00753 {
00754 MRGBLineCount()++;
00755 char buf[3]="00";
00756 Color4b cc(Color4b::Black);
00757 for(size_t i=6;(i+7)<len;i+=8)
00758 {
00759 for(size_t j=1;j<4;j++)
00760 {
00761 buf[0]=line[i+j*2+0];
00762 buf[1]=line[i+j*2+1];
00763 buf[2]=0;
00764 char *p;
00765 int val=strtoul(buf,&p,16);
00766 cc[j-1]= val;
00767 }
00768 colVec->push_back(cc);
00769 }
00770 }
00771 }
00772 }
00773 while (( line.length()==0 || line[0] == '#') && !stream.eof());
00774
00775 if ( (line.length() == 0)||(line[0] == '#') )
00776 return;
00777
00778 size_t from = 0;
00779 size_t to = 0;
00780 size_t length = line.size();
00781
00782 tokens.clear();
00783 do
00784 {
00785 while (from!=length && (line[from]==' ' || line[from]=='\t' || line[from]=='\r') )
00786 from++;
00787 if(from!=length)
00788 {
00789 to = from+1;
00790 while (to!=length && line[to]!=' ' && line[to] != '\t' && line[to]!='\r')
00791 to++;
00792 tokens.push_back(line.substr(from, to-from).c_str());
00793 from = to;
00794 }
00795 }
00796 while (from<length);
00797 }
00798
00799 inline static void SplitToken(const std::string & token, int & vId, int & nId, int & tId, int mask)
00800 {
00801 static const char delimiter = '/';
00802
00803 vId = nId = tId = 0;
00804 if (token.empty()) return;
00805
00806 size_t firstSep = token.find_first_of(delimiter);
00807 size_t secondSep = (firstSep == std::string::npos) ? (std::string::npos) : (token.find_first_of(delimiter, firstSep + 1));
00808
00809 const bool hasPosition = true;
00810 const bool hasTexcoord = (firstSep != std::string::npos) && ((firstSep + 1) < secondSep);
00811 const bool hasNormal = (secondSep != std::string::npos) || (mask & Mask::IOM_WEDGNORMAL) || (mask & Mask::IOM_VERTNORMAL);
00812
00813 if (hasPosition) vId = atoi(token.substr(0, firstSep).c_str()) - 1;
00814 if (hasTexcoord) tId = atoi(token.substr(firstSep + 1, secondSep - firstSep - 1).c_str()) - 1;
00815 if (hasNormal)
00816 nId = atoi(token.substr(secondSep + 1).c_str()) - 1;
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827 }
00828
00829 #if 0
00830
00831
00832
00833
00834
00835
00836 inline static void SplitToken(std::string token, int &vId, int &nId, int &tId, int mask)
00837 {
00838 std::string vertex;
00839 std::string texcoord;
00840 std::string normal;
00841
00842 if( ( mask & Mask::IOM_WEDGTEXCOORD ) && (mask & Mask::IOM_WEDGNORMAL) ) SplitVVTVNToken(token, vertex, texcoord, normal);
00843 if(!( mask & Mask::IOM_WEDGTEXCOORD ) && (mask & Mask::IOM_WEDGNORMAL) ) SplitVVNToken(token, vertex, normal);
00844 if( ( mask & Mask::IOM_WEDGTEXCOORD ) &&!(mask & Mask::IOM_WEDGNORMAL) ) SplitVVTToken(token, vertex, texcoord);
00845 if(!( mask & Mask::IOM_WEDGTEXCOORD ) &&!(mask & Mask::IOM_WEDGNORMAL) ) SplitVToken(token, vertex);
00846
00847 vId = atoi(vertex.c_str()) - 1;
00848 if(mask & Mask::IOM_WEDGTEXCOORD) tId = atoi(texcoord.c_str()) - 1;
00849 if(mask & Mask::IOM_WEDGNORMAL) nId = atoi(normal.c_str()) - 1;
00850 }
00851
00852 inline static void SplitVToken(std::string token, std::string &vertex)
00853 {
00854 vertex = token;
00855 }
00856
00857 inline static void SplitVVTToken(std::string token, std::string &vertex, std::string &texcoord)
00858 {
00859 vertex.clear();
00860 texcoord.clear();
00861
00862 size_t from = 0;
00863 size_t to = 0;
00864 size_t length = token.size();
00865
00866 if(from!=length)
00867 {
00868 char c = token[from];
00869 vertex.push_back(c);
00870
00871 to = from+1;
00872 while (to<length && ((c = token[to]) !='/'))
00873 {
00874 vertex.push_back(c);
00875 ++to;
00876 }
00877 ++to;
00878 while (to<length && ((c = token[to]) !=' '))
00879 {
00880 texcoord.push_back(c);
00881 ++to;
00882 }
00883 }
00884 }
00885
00886 inline static void SplitVVNToken(std::string token, std::string &vertex, std::string &normal)
00887 {
00888 vertex.clear();
00889 normal.clear();
00890
00891 size_t from = 0;
00892 size_t to = 0;
00893 size_t length = token.size();
00894
00895 if(from!=length)
00896 {
00897 char c = token[from];
00898 vertex.push_back(c);
00899
00900 to = from+1;
00901 while (to!=length && ((c = token[to]) !='/'))
00902 {
00903 vertex.push_back(c);
00904 ++to;
00905 }
00906 ++to;
00907 ++to;
00908 while (to!=length && ((c = token[to]) !=' '))
00909 {
00910 normal.push_back(c);
00911 ++to;
00912 }
00913 }
00914 }
00915
00916 inline static void SplitVVTVNToken(std::string token, std::string &vertex, std::string &texcoord, std::string &normal)
00917 {
00918 vertex.clear();
00919 texcoord.clear();
00920 normal.clear();
00921
00922 size_t from = 0;
00923 size_t to = 0;
00924 size_t length = token.size();
00925
00926 if(from!=length)
00927 {
00928 char c = token[from];
00929 vertex.push_back(c);
00930
00931 to = from+1;
00932 while (to!=length && ((c = token[to]) !='/'))
00933 {
00934 vertex.push_back(c);
00935 ++to;
00936 }
00937 ++to;
00938 while (to!=length && ((c = token[to]) !='/'))
00939 {
00940 texcoord.push_back(c);
00941 ++to;
00942 }
00943 ++to;
00944 while (to!=length && ((c = token[to]) !=' '))
00945 {
00946 normal.push_back(c);
00947 ++to;
00948 }
00949 }
00950 }
00951 #endif
00952
00960 static bool LoadMask(const char * filename, Info &oi)
00961 {
00962
00963 std::ifstream stream(filename);
00964 if (stream.fail())
00965 {
00966 stream.close();
00967 return false;
00968 }
00969
00970 stream.seekg (0, std::ios::end);
00971 int length = stream.tellg();
00972 stream.seekg (0, std::ios::beg);
00973
00974 if (length == 0) return false;
00975
00976 bool bHasPerFaceColor = false;
00977 bool bHasNormals = false;
00978 bool bHasPerVertexColor = false;
00979
00980 oi.numVertices=0;
00981 oi.numEdges=0;
00982 oi.numFaces=0;
00983 oi.numTexCoords=0;
00984 oi.numNormals=0;
00985 int lineCount=0;
00986 int totRead=0;
00987 std::string line;
00988 while (!stream.eof())
00989 {
00990 lineCount++;
00991 std::getline(stream, line);
00992 totRead+=line.size();
00993 if(oi.cb && (lineCount%1000)==0)
00994 (*oi.cb)( (int)(100.0*(float(totRead))/float(length)), "Loading mask...");
00995 if(line.size()>2)
00996 {
00997 if(line[0]=='v')
00998 {
00999 if(line[1]==' ')
01000 {
01001 oi.numVertices++;
01002 if(line.size()>=7)
01003 bHasPerVertexColor = true;
01004 }
01005 if(line[1]=='t') oi.numTexCoords++;
01006 if(line[1]=='n') {
01007 oi.numNormals ++;
01008 bHasNormals = true;
01009 }
01010 }
01011 else {
01012 if((line[0]=='f') || (line[0]=='q')) oi.numFaces++;
01013 else
01014 if (line[0]=='l') oi.numEdges++;
01015 else
01016 if(line[0]=='u' && line[1]=='s') bHasPerFaceColor = true;
01017 }
01018 }
01019 }
01020 oi.mask = 0;
01021 if (oi.numTexCoords)
01022 {
01023 if (oi.numTexCoords==oi.numVertices)
01024 oi.mask |= vcg::tri::io::Mask::IOM_VERTTEXCOORD;
01025
01026 oi.mask |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD;
01027
01028 oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR;
01029 }
01030 if(bHasPerFaceColor) oi.mask |= vcg::tri::io::Mask::IOM_FACECOLOR;
01031 if(bHasPerVertexColor) oi.mask |= vcg::tri::io::Mask::IOM_VERTCOLOR;
01032 if (bHasNormals) {
01033 if (oi.numNormals == oi.numVertices)
01034 oi.mask |= vcg::tri::io::Mask::IOM_VERTNORMAL;
01035 else
01036 oi.mask |= vcg::tri::io::Mask::IOM_WEDGNORMAL;
01037 }
01038 if (oi.numEdges)
01039 oi.mask |= vcg::tri::io::Mask::IOM_EDGEINDEX;
01040
01041 stream.close();
01042
01043 return true;
01044 }
01045
01046 static bool LoadMask(const char * filename, int &mask)
01047 {
01048 Info oi;
01049 bool ret=LoadMask(filename, oi);
01050 mask= oi.mask;
01051 return ret;
01052 }
01053
01054 static bool LoadMaterials(const char * filename, std::vector<Material> &materials, std::vector<std::string> &textures)
01055 {
01056
01057
01058 std::ifstream stream(filename);
01059 if (stream.fail())
01060 return false;
01061
01062 std::vector< std::string > tokens;
01063 std::string header;
01064
01065 materials.clear();
01066 Material currentMaterial;
01067 currentMaterial.index = (unsigned int)(-1);
01068
01069 bool first = true;
01070 while (!stream.eof())
01071 {
01072 tokens.clear();
01073 TokenizeNextLine(stream, tokens,0);
01074
01075 if (tokens.size() > 0)
01076 {
01077 header.clear();
01078 header = tokens[0];
01079
01080 if (header.compare("newmtl")==0)
01081 {
01082 if (!first)
01083 {
01084 materials.push_back(currentMaterial);
01085 currentMaterial = Material();
01086 currentMaterial.index = (unsigned int)(-1);
01087 }
01088 else
01089 first = false;
01090
01091 if(tokens.size() < 2)
01092 return false;
01093 currentMaterial.materialName=tokens[1];
01094 }
01095 else if (header.compare("Ka")==0)
01096 {
01097 if (tokens.size() < 4)
01098 return false;
01099 float r = (float) atof(tokens[1].c_str());
01100 float g = (float) atof(tokens[2].c_str());
01101 float b = (float) atof(tokens[3].c_str());
01102
01103 currentMaterial.Ka = Point3f(r, g, b);
01104 }
01105 else if (header.compare("Kd")==0)
01106 {
01107 if (tokens.size() < 4)
01108 return false;
01109 float r = (float) atof(tokens[1].c_str());
01110 float g = (float) atof(tokens[2].c_str());
01111 float b = (float) atof(tokens[3].c_str());
01112
01113 currentMaterial.Kd = Point3f(r, g, b);
01114 }
01115 else if (header.compare("Ks")==0)
01116 {
01117 if (tokens.size() < 4)
01118 return false;
01119 float r = (float) atof(tokens[1].c_str());
01120 float g = (float) atof(tokens[2].c_str());
01121 float b = (float) atof(tokens[3].c_str());
01122
01123 currentMaterial.Ks = Point3f(r, g, b);
01124 }
01125 else if ( (header.compare("d")==0) ||
01126 (header.compare("Tr")==0) )
01127 {
01128 if (tokens.size() < 2)
01129 return false;
01130 currentMaterial.Tr = (float) atof(tokens[1].c_str());
01131 }
01132 else if (header.compare("Ns")==0)
01133 {
01134 if (tokens.size() < 2)
01135 return false;
01136 currentMaterial.Ns = float(atoi(tokens[1].c_str()));
01137 }
01138 else if (header.compare("illum")==0)
01139 {
01140 if (tokens.size() < 2)
01141 return false;
01142 int illumination = atoi(tokens[1].c_str());
01143
01144 currentMaterial.illum = illumination;
01145 }
01146 else if( (header.compare("map_Kd")==0) || (header.compare("map_Ka")==0) )
01147 {
01148 if (tokens.size() < 2)
01149 return false;
01150 std::string textureName = tokens[1];
01151
01152 currentMaterial.map_Kd=textureName;
01153
01154
01155
01156 bool found = false;
01157 unsigned int size = static_cast<unsigned int>(textures.size());
01158 unsigned j = 0;
01159 while (!found && (j < size))
01160 {
01161 if (textureName.compare(textures[j])==0)
01162 {
01163 currentMaterial.index = (int)j;
01164 found = true;
01165 }
01166 ++j;
01167 }
01168 if (!found)
01169 {
01170 textures.push_back(textureName);
01171 currentMaterial.index = (int)size;
01172 }
01173 }
01174
01175 }
01176 }
01177 materials.push_back(currentMaterial);
01178
01179 stream.close();
01180
01181 return true;
01182 }
01183
01184 };
01185 }
01186 }
01187 }
01188
01189 #endif // ndef __VCGLIB_IMPORT_OBJ