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
00026 #ifndef __VCGLIB_EXPORT_OBJ
00027 #define __VCGLIB_EXPORT_OBJ
00028
00029 #include <wrap/callback.h>
00030 #include <wrap/io_trimesh/io_mask.h>
00031 #include "io_material.h"
00032 #include <iostream>
00033 #include <fstream>
00034 #include <map>
00035
00036 namespace vcg {
00037 namespace tri {
00038 namespace io {
00039
00040 template <class SaveMeshType>
00041 class ExporterOBJ
00042 {
00043 public:
00044 typedef typename SaveMeshType::FaceIterator FaceIterator;
00045 typedef typename SaveMeshType::EdgeIterator EdgeIterator;
00046 typedef typename SaveMeshType::VertexIterator VertexIterator;
00047 typedef typename SaveMeshType::VertexType VertexType;
00048 typedef typename SaveMeshType::ScalarType ScalarType;
00049 typedef typename SaveMeshType::CoordType CoordType;
00050 typedef typename SaveMeshType::FaceType::TexCoordType TexCoordType;
00051
00052
00053
00054
00055 enum SaveError
00056 {
00057 E_NOERROR,
00058 E_CANTOPENFILE,
00059 E_CANTCLOSEFILE,
00060 E_UNESPECTEDEOF,
00061 E_ABORTED,
00062 E_NOTDEFINITION,
00063 E_NOTVEXTEXVALID,
00064 E_NOTFACESVALID
00065 };
00066
00067
00068
00069
00070 static const char* ErrorMsg(int error)
00071 {
00072 static const char* obj_error_msg[] =
00073 {
00074 "No errors",
00075 "Can't open file",
00076 "can't close file",
00077 "Premature End of file",
00078 "File saving aborted",
00079 "Function not defined",
00080 "Vertices not valid",
00081 "Faces not valid"
00082 };
00083
00084 if(error>7 || error<0) return "Unknown error";
00085 else return obj_error_msg[error];
00086 };
00087
00088
00089
00090
00091 static int GetExportMaskCapability()
00092 {
00093 int capability = 0;
00094
00095
00096 capability |= vcg::tri::io::Mask::IOM_VERTNORMAL;
00097 capability |= vcg::tri::io::Mask::IOM_VERTTEXCOORD;
00098 capability |= vcg::tri::io::Mask::IOM_VERTCOLOR;
00099
00100
00101 capability |= vcg::tri::io::Mask::IOM_FACECOLOR;
00102
00103 capability |= vcg::tri::io::Mask::IOM_EDGEINDEX;
00104
00105 capability |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD;
00106 capability |= vcg::tri::io::Mask::IOM_WEDGNORMAL;
00107
00108 return capability;
00109 }
00110
00111
00112
00113
00114 static int Save(SaveMeshType &m, const char * filename, int mask, CallBackPos *cb=0)
00115 {
00116
00117 if (mask & vcg::tri::io::Mask::IOM_WEDGTEXCOORD &&
00118 mask & vcg::tri::io::Mask::IOM_VERTTEXCOORD ) {
00119 mask &= ~vcg::tri::io::Mask::IOM_VERTTEXCOORD;
00120 }
00121 if (mask & vcg::tri::io::Mask::IOM_WEDGCOLOR &&
00122 mask & vcg::tri::io::Mask::IOM_VERTCOLOR ) {
00123 mask &= ~vcg::tri::io::Mask::IOM_VERTCOLOR;
00124 }
00125 if(m.vn == 0) return E_NOTVEXTEXVALID;
00126
00127
00128
00129 int current = 0;
00130 int totalPrimitives = m.vn+m.fn;
00131
00132 std::vector<Material> materialVec;
00133
00134 std::string fn(filename);
00135 int LastSlash=fn.size()-1;
00136 while(LastSlash>=0 && fn[LastSlash]!='/')
00137 --LastSlash;
00138
00139 FILE *fp;
00140 fp = fopen(filename,"w");
00141 if(fp == NULL) return E_CANTOPENFILE;
00142
00143 fprintf(fp,"####\n#\n# OBJ File Generated by Meshlab\n#\n####\n");
00144 fprintf(fp,"# Object %s\n#\n# Vertices: %d\n# Faces: %d\n#\n####\n",fn.substr(LastSlash+1).c_str(),m.vn,m.fn);
00145
00146
00147 if( (mask & vcg::tri::io::Mask::IOM_FACECOLOR) || (mask & Mask::IOM_WEDGTEXCOORD) || (mask & Mask::IOM_VERTTEXCOORD) )
00148 fprintf(fp,"mtllib ./%s.mtl\n\n",fn.substr(LastSlash+1).c_str());
00149
00150
00151 VertexIterator vi;
00152 std::map<CoordType,int> NormalVertex;
00153 std::vector<int> VertexId(m.vert.size());
00154 int numvert = 0;
00155 int curNormalIndex = 1;
00156 for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi) if( !(*vi).IsD() )
00157 {
00158 VertexId[vi-m.vert.begin()]=numvert;
00159
00160 if (mask & Mask::IOM_WEDGNORMAL )
00161 {
00162 if(AddNewNormalVertex(NormalVertex,(*vi).N(),curNormalIndex))
00163 {
00164 fprintf(fp,"vn %f %f %f\n",(*vi).N()[0],(*vi).N()[1],(*vi).N()[2]);
00165 curNormalIndex++;
00166 }
00167 }
00168 if (mask & Mask::IOM_VERTNORMAL ) {
00169 fprintf(fp,"vn %f %f %f\n",(*vi).N()[0],(*vi).N()[1],(*vi).N()[2]);
00170 }
00171 if (mask & Mask::IOM_VERTTEXCOORD ) {
00172 fprintf(fp,"vt %f %f\n",(*vi).T().P()[0],(*vi).T().P()[1]);
00173 }
00174
00175
00176
00177
00178
00179
00180 fprintf(fp,"v %f %f %f",(*vi).P()[0],(*vi).P()[1],(*vi).P()[2]);
00181 if(mask & Mask::IOM_VERTCOLOR)
00182 fprintf(fp," %f %f %f",double((*vi).C()[0])/255.,double((*vi).C()[1])/255.,double((*vi).C()[2])/255.);
00183 fprintf(fp,"\n");
00184
00185 if (cb !=NULL)
00186 {
00187 if(!(*cb)((100*++current)/totalPrimitives, "writing vertices "))
00188 {
00189 fclose(fp);
00190 return E_ABORTED;
00191 }
00192 }
00193 numvert++;
00194 }
00195 assert(numvert == m.vn);
00196
00197 fprintf(fp,"# %d vertices, %d vertices normals\n\n",m.vn,int(NormalVertex.size()));
00198
00199
00200 std::map<TexCoordType,int> CoordIndexTexture;
00201 unsigned int material_num = 0;
00202 int mem_index = 0;
00203 int curTexCoordIndex = 1;
00204 for(FaceIterator fi=m.face.begin(); fi!=m.face.end(); ++fi) if( !(*fi).IsD() )
00205 {
00206 if((mask & Mask::IOM_FACECOLOR) || (mask & Mask::IOM_WEDGTEXCOORD) || (mask & Mask::IOM_VERTTEXCOORD))
00207 {
00208 int index = Materials<SaveMeshType>::CreateNewMaterial(m,materialVec,material_num,fi);
00209
00210 if(index == (int)materialVec.size())
00211 {
00212 material_num++;
00213 fprintf(fp,"\nusemtl material_%d\n",materialVec[index-1].index);
00214 mem_index = index-1;
00215 }
00216 else
00217 {
00218 if(index != mem_index)
00219 {
00220 fprintf(fp,"\nusemtl material_%d\n",materialVec[index].index);
00221 mem_index=index;
00222 }
00223 }
00224 }
00225
00226
00227 if(HasPerWedgeTexCoord(m) && (mask & Mask::IOM_WEDGTEXCOORD))
00228 for(int k=0;k<(*fi).VN();k++)
00229 {
00230 if(AddNewTextureCoord(CoordIndexTexture,(*fi).WT(k),curTexCoordIndex))
00231 {
00232 fprintf(fp,"vt %f %f\n",(*fi).WT(k).u(),(*fi).WT(k).v());
00233 curTexCoordIndex++;
00234 }
00235 }
00236
00237
00238 fprintf(fp,"f ");
00239 for(int k=0;k<(*fi).VN();k++)
00240 {
00241 if(k!=0) fprintf(fp," ");
00242 int vInd = -1;
00243
00244 vInd = VertexId[tri::Index(m, (*fi).V(k))] + 1;
00245
00246 int vt = -1;
00247 if(mask & Mask::IOM_WEDGTEXCOORD)
00248 vt = GetIndexVertexTexture(CoordIndexTexture,(*fi).WT(k));
00249 if (mask & Mask::IOM_VERTTEXCOORD)
00250 vt = vInd;
00251
00252 int vn = -1;
00253 if(mask & Mask::IOM_WEDGNORMAL )
00254 vn = GetIndexVertexNormal(m, NormalVertex, (*fi).V(k)->cN());
00255 if (mask & Mask::IOM_VERTNORMAL)
00256 vn = vInd;
00257
00258
00259 WriteFacesElement(fp,vInd,vt,vn);
00260 }
00261 fprintf(fp,"\n");
00262
00263 if (cb !=NULL) {
00264 if(!(*cb)((100*++current)/totalPrimitives, "writing vertices "))
00265 { fclose(fp); return E_ABORTED;}
00266 }
00267
00268 }
00269
00270 for(EdgeIterator ei=m.edge.begin(); ei!=m.edge.end(); ++ei) if( !(*ei).IsD() )
00271 {
00272 fprintf(fp,"l %i %i\n",
00273 VertexId[tri::Index(m, (*ei).V(0))] + 1,
00274 VertexId[tri::Index(m, (*ei).V(1))] + 1);
00275 }
00276
00277 fprintf(fp,"# %d faces, %d coords texture\n\n",m.fn,int(CoordIndexTexture.size()));
00278
00279 fprintf(fp,"# End of File\n");
00280 fclose(fp);
00281
00282 int errCode = E_NOERROR;
00283 if((mask & Mask::IOM_WEDGTEXCOORD) || (mask & Mask::IOM_FACECOLOR) || (mask & Mask::IOM_VERTTEXCOORD) )
00284 errCode = WriteMaterials(materialVec, filename,cb);
00285
00286 if(errCode!= E_NOERROR)
00287 return errCode;
00288 return E_NOERROR;
00289 }
00290
00291
00292
00293
00294 inline static int GetIndexVertexTexture(typename std::map<TexCoordType,int> &mapTexToInt, const TexCoordType &wt)
00295 {
00296 typename std::map<TexCoordType,int>::iterator iter= mapTexToInt.find(wt);
00297 if(iter != mapTexToInt.end()) return (*iter).second;
00298 else return -1;
00299
00300
00301
00302 }
00303
00304
00305
00306
00307 inline static int GetIndexVertexNormal(SaveMeshType &, std::map<CoordType,int> &mapNormToInt, const CoordType &norm )
00308 {
00309 typename std::map<CoordType,int>::iterator iter= mapNormToInt.find(norm);
00310 if(iter != mapNormToInt.end()) return (*iter).second;
00311 else return -1;
00312 }
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 inline static void WriteFacesElement(FILE *fp,int v,int vt, int vn)
00324 {
00325 fprintf(fp,"%d",v);
00326 if(vt!=-1)
00327 {
00328 fprintf(fp,"/%d",vt);
00329 if(vn!=-1)
00330 fprintf(fp,"/%d",vn);
00331 }
00332 else if(vn!=-1)
00333 fprintf(fp,"//%d",vn);
00334 }
00335
00336
00337
00338
00339
00340 template <class TexScalarType>
00341 inline static bool AddNewTextureCoord(std::map<typename vcg::TexCoord2<TexScalarType>,int> &m,
00342 const typename vcg::TexCoord2<TexScalarType> &wt,int value)
00343 {
00344 int index = m[wt];
00345 if(index==0){m[wt]=value;return true;}
00346 return false;
00347 }
00348
00349
00350
00351
00352
00353 inline static bool AddNewNormalVertex(typename std::map<CoordType,int> &m, CoordType &n ,int value)
00354 {
00355 int index = m[n];
00356 if(index==0){m[n]=value;return true;}
00357 return false;
00358 }
00359
00360
00361
00362
00363 inline static int WriteMaterials(std::vector<Material> &materialVec, const char * filename, CallBackPos *cb=0)
00364 {
00365 std::string fileName = std::string(filename);
00366 fileName+=".mtl";
00367
00368 if(materialVec.size() > 0)
00369 {
00370 FILE *fp;
00371 fp = fopen(fileName.c_str(),"w");
00372 if(fp==NULL)return E_ABORTED;
00373
00374 fprintf(fp,"#\n# Wavefront material file\n# Converted by Meshlab Group\n#\n\n");
00375
00376 int current = 0;
00377
00378 for(unsigned int i=0;i<materialVec.size();i++)
00379 {
00380 if (cb !=NULL)
00381 (*cb)((100 * ++current)/materialVec.size(), "saving material file ");
00382 else
00383 { }
00384
00385 fprintf(fp,"newmtl material_%d\n",materialVec[i].index);
00386 fprintf(fp,"Ka %f %f %f\n",materialVec[i].Ka[0],materialVec[i].Ka[1],materialVec[i].Ka[2]);
00387 fprintf(fp,"Kd %f %f %f\n",materialVec[i].Kd[0],materialVec[i].Kd[1],materialVec[i].Kd[2]);
00388 fprintf(fp,"Ks %f %f %f\n",materialVec[i].Ks[0],materialVec[i].Ks[1],materialVec[i].Ks[2]);
00389 fprintf(fp,"Tr %f\n",materialVec[i].Tr);
00390 fprintf(fp,"illum %d\n",materialVec[i].illum);
00391 fprintf(fp,"Ns %f\n",materialVec[i].Ns);
00392
00393 if(materialVec[i].map_Kd.size()>0)
00394 fprintf(fp,"map_Kd %s\n",materialVec[i].map_Kd.c_str());
00395 fprintf(fp,"\n");
00396 }
00397 fclose(fp);
00398 }
00399 return E_NOERROR;
00400 }
00401
00402 };
00403 }
00404 }
00405 }
00406
00407 #endif