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