export_obj.h
Go to the documentation of this file.
00001 /****************************************************************************
00002 * VCGLib                                                            o o     *
00003 * Visual and Computer Graphics Library                            o     o   *
00004 *                                                                _   O  _   *
00005 * Copyright(C) 2004                                                \/)\/    *
00006 * Visual Computing Lab                                            /\/|      *
00007 * ISTI - Italian National Research Council                           |      *
00008 *                                                                    \      *
00009 * All rights reserved.                                                      *
00010 *                                                                           *
00011 * This program is free software; you can redistribute it and/or modify      *
00012 * it under the terms of the GNU General Public License as published by      *
00013 * the Free Software Foundation; either version 2 of the License, or         *
00014 * (at your option) any later version.                                       *
00015 *                                                                           *
00016 * This program is distributed in the hope that it will be useful,           *
00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
00019 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
00020 * for more details.                                                         *
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             enum of all the types of error
00054         */
00055   enum SaveError
00056   {
00057     E_NOERROR,                                  // 0
00058     E_CANTOPENFILE,                             // 1
00059     E_CANTCLOSEFILE,                    // 2
00060     E_UNESPECTEDEOF,                    // 3
00061     E_ABORTED,                                  // 4
00062     E_NOTDEFINITION,                    // 5
00063     E_NOTVEXTEXVALID,                   // 6
00064     E_NOTFACESVALID                             // 7
00065   };
00066 
00067   /*
00068             this function takes an index and the relative error message gets back
00069         */
00070   static const char* ErrorMsg(int error)
00071   {
00072     static const char* obj_error_msg[] =
00073     {
00074       "No errors",                                                      // 0
00075       "Can't open file",                                                // 1
00076       "can't close file",                                               // 2
00077       "Premature End of file",                          // 3
00078       "File saving aborted",                                    // 4
00079       "Function not defined",                                   // 5
00080       "Vertices not valid",                                     // 6
00081       "Faces not valid"                                         // 7
00082     };
00083 
00084     if(error>7 || error<0) return "Unknown error";
00085     else return obj_error_msg[error];
00086   };
00087 
00088   /*
00089             returns mask of capability one define with what are the saveable information of the format.
00090         */
00091   static int GetExportMaskCapability()
00092   {
00093     int capability = 0;
00094 
00095     //vert
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     //face
00101     capability |= vcg::tri::io::Mask::IOM_FACECOLOR;
00102 
00103     capability |= vcg::tri::io::Mask::IOM_EDGEINDEX;
00104     //wedg
00105     capability |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD;
00106     capability |= vcg::tri::io::Mask::IOM_WEDGNORMAL;
00107 
00108     return capability;
00109   }
00110 
00111   /*
00112             function which saves in OBJ file format
00113         */
00114   static int Save(SaveMeshType &m, const char * filename, int mask, CallBackPos *cb=0)
00115   {
00116     // texture coord and normal: cannot be saved BOTH per vertex and per wedge
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     // Commented out this control. You should be allowed to save a point cloud.
00127     // if(m.fn == 0)    return E_NOTFACESVALID;
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     //library materialVec
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     //vertexs + normal
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       //saves normal per vertex
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       //if (mask & Mask::IOM_VERTCOLOR ) {
00175       //  fprintf(fp,"vc %f %f %f\n",(*vi).T().P()[0],(*vi).T().P()[1]);
00176       //}
00177 
00178       //saves vertex
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     //faces + texture coords
00200     std::map<TexCoordType,int> CoordIndexTexture;
00201     unsigned int material_num = 0;
00202     int mem_index = 0; //var temporany
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())//inserts a new element material
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)//inserts old name elemente material
00219           {
00220             fprintf(fp,"\nusemtl material_%d\n",materialVec[index].index);
00221             mem_index=index;
00222           }
00223         }
00224       }
00225 
00226       //saves texture coord x wedge
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++; //ncreases the value number to be associated to the Texture
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         // +1 because Obj file format begins from index = 1 but not from index = 0.
00244         vInd = VertexId[tri::Index(m, (*fi).V(k))] + 1;//index of vertex per face
00245 
00246         int vt = -1;
00247         if(mask & Mask::IOM_WEDGTEXCOORD)
00248           vt = GetIndexVertexTexture(CoordIndexTexture,(*fi).WT(k));//index of vertex texture per face
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());//index of vertex normal per face.
00255         if (mask & Mask::IOM_VERTNORMAL)
00256           vn = vInd;
00257 
00258         //writes elements on file obj
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     }//for faces
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);//write material
00285 
00286     if(errCode!= E_NOERROR)
00287       return errCode;
00288     return E_NOERROR;
00289   }
00290 
00291    /*
00292             returns index of the texture coord
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     // Old wrong version.
00300     // int index = mapTexToInt[wt];
00301     // if(index!=0){return index;}
00302   }
00303 
00304   /*
00305             returns index of the vertex normal
00306         */
00307   inline static int GetIndexVertexNormal(SaveMeshType &/*m*/, 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             write elements on file
00316 
00317                 f v/tc/vn v/tc/vn v/tc/vn ...
00318                 f v/tc v/tc v/tc ...
00319                 f v//vn v//vn v//vn ...
00320                 f v v v ...
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             adds a new index to the coordinate of Texture if it is the first time
00338             which is otherwise met not execute anything
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             adds a new index to the normal per vertex if it is the first time
00351             which is otherwise met does not execute anything
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             writes material into file
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         { /* fclose(fp); return E_ABORTED; */ }
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 }; // end class
00403 } // end Namespace tri
00404 } // end Namespace io
00405 } // end Namespace vcg
00406 
00407 #endif


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:30:52