OBJPrimitiveIO.cpp

Go to the documentation of this file.
00001 // Copyright (C) 2008 Dave Griffiths
00002 //
00003 // This program is free software; you can redistribute it and/or modify
00004 // it under the terms of the GNU General Public License as published by
00005 // the Free Software Foundation; either version 2 of the License, or
00006 // (at your option) any later version.
00007 //
00008 // This program is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 // GNU General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this program; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00016  
00017 #include "assert.h"
00018 #include "PolyPrimitive.h"
00019 #include "OBJPrimitiveIO.h"
00020 #include "Trace.h"
00021 
00022 using namespace Fluxus;
00023     
00024 OBJPrimitiveIO::OBJPrimitiveIO()
00025 {
00026 }
00027 
00028 OBJPrimitiveIO::~OBJPrimitiveIO()
00029 {
00030     // clear some mem
00031     m_Position.clear();
00032     m_Texture.clear();
00033     m_Normal.clear();
00034     m_Faces.clear();
00035 }
00036     
00037 Primitive *OBJPrimitiveIO::FormatRead(const string &filename)
00038 {
00039     FILE *file = fopen(filename.c_str(),"r");
00040     if (file==NULL)
00041     {
00042         Trace::Stream<<"Cannot open .obj file: "<<filename<<endl;
00043         return NULL;
00044     }
00045     
00046     fseek(file,0,SEEK_END);
00047     m_DataSize = ftell(file);
00048     rewind(file);
00049     
00050     m_Data = new char[m_DataSize+1];
00051     if (m_DataSize!=fread(m_Data,1,m_DataSize,file))
00052     {
00053         Trace::Stream<<"Error reading .obj file: "<<filename<<endl;
00054         fclose(file);
00055         return NULL;
00056     }
00057     fclose(file);
00058     m_Data[m_DataSize]='\0';
00059     
00060     // get all the data we need
00061     ReadVectors("v",m_Position);
00062     ReadVectors("vt",m_Texture);
00063     ReadVectors("vn",m_Normal);
00064     ReadIndices(m_Faces);
00065     
00066     // now get rid of the text
00067     delete[] m_Data;
00068     
00069     // shuffle stuff around so we only have one set of indices
00070     vector<Indices> unique=RemoveDuplicateIndices();
00071     ReorderData(unique);
00072     UnifyIndices(unique);
00073     
00074     if (m_Faces.empty()) return NULL;
00075     
00076     return MakePrimitive();
00077 }
00078 
00079 Primitive *OBJPrimitiveIO::MakePrimitive()
00080 {
00081     // stick all the data in a primitive
00082     
00083     // what type?
00084     PolyPrimitive::Type type;
00085     switch (m_Faces[0].Index.size())
00086     {
00087         case 3: type=PolyPrimitive::TRILIST; break;
00088         case 4: type=PolyPrimitive::QUADS; break;
00089         default: 
00090         {
00091             Trace::Stream<<"obj file needs to contain triangles or quads"<<endl;
00092             return NULL;
00093         }
00094     }
00095     
00096     PolyPrimitive *prim = new PolyPrimitive(type);
00097     prim->Resize(m_Position.size());
00098     
00099     TypedPData<dVector> *pos = new TypedPData<dVector>(m_Position);
00100     prim->SetDataRaw("p", pos);
00101     
00102     if (!m_Texture.empty())
00103     {
00104         assert(m_Texture.size()==m_Position.size());
00105         TypedPData<dVector> *tex = new TypedPData<dVector>(m_Texture);
00106         prim->SetDataRaw("t", tex);
00107     }
00108     
00109     if (!m_Normal.empty())
00110     {   
00111         assert(m_Normal.size()==m_Position.size());
00112         TypedPData<dVector> *nrm = new TypedPData<dVector>(m_Normal);
00113         prim->SetDataRaw("n", nrm);
00114     }
00115 
00116     prim->GetIndex()=m_Indices;
00117     prim->SetIndexMode(true); 
00118     return prim;
00119 }
00120 
00121 unsigned int OBJPrimitiveIO::TokeniseLine(unsigned int pos, vector<string> &output)
00122 {
00123     char c=m_Data[pos];
00124     vector<string> temp;
00125     temp.push_back("");
00126     while(c!='\n' && pos<m_DataSize)
00127     {
00128         if (c==' ' && *temp.rbegin()!="") temp.push_back("");
00129         else temp.rbegin()->push_back(c);
00130         c=m_Data[++pos];
00131     }       
00132     
00133     // get rid of whitespace
00134     output.clear();
00135     for(vector<string>::iterator i=temp.begin(); i!=temp.end(); ++i)
00136     {
00137         if (*i!="") output.push_back(*i);
00138     }
00139     
00140     return pos+1;
00141 }
00142 
00143 void OBJPrimitiveIO::TokeniseIndices(const string &str, vector<string> &output)
00144 {
00145     unsigned int pos=0;
00146     output.clear();
00147     output.push_back("");
00148     while(pos<str.size())
00149     {
00150         char c=str[pos++];
00151         if (c==' ' || c=='/') output.push_back("");
00152         else output.rbegin()->push_back(c);
00153     }           
00154 }
00155 
00156 void OBJPrimitiveIO::ReadVectors(const string &code, std::vector<dVector> &output)
00157 {
00158     unsigned int pos=0;
00159     output.clear();
00160     while (pos<m_DataSize)
00161     {
00162         vector<string> tokens;
00163         pos = TokeniseLine(pos, tokens);
00164         if (tokens.size()==4 && tokens[0]==code)
00165         {
00166             output.push_back(dVector(atof(tokens[1].c_str()),
00167                                      atof(tokens[2].c_str()),
00168                                      atof(tokens[3].c_str())));
00169         }
00170     }
00171 }
00172 
00173 void OBJPrimitiveIO::ReadIndices(vector<Face> &output)
00174 {
00175     unsigned int pos=0;
00176     output.clear();
00177     while (pos<m_DataSize)
00178     {
00179         vector<string> tokens;
00180         pos = TokeniseLine(pos, tokens);
00181         if (!tokens.empty() && tokens[0]=="f")
00182         {
00183             Face f;
00184             for(unsigned int i=1; i<tokens.size(); i++)
00185             {
00186                 vector<string> itokens;
00187                 TokeniseIndices(tokens[i],itokens);
00188                 if (itokens.size()==3)
00189                 {
00190                     Indices ind;
00191                     if (itokens[0]!="") ind.Position=(unsigned int)atof(itokens[0].c_str())-1;
00192                     if (itokens[1]!="") ind.Texture=(unsigned int)atof(itokens[1].c_str())-1;
00193                     if (itokens[2]!="") ind.Normal=(unsigned int)atof(itokens[2].c_str())-1;
00194                     f.Index.push_back(ind);
00195                 }
00196                 else if (itokens.size()==2)
00197                 {
00198                     Indices ind;
00199                     if (itokens[0]!="") ind.Position=(unsigned int)atof(itokens[0].c_str())-1;
00200                     if (itokens[1]!="") ind.Texture=(unsigned int)atof(itokens[1].c_str())-1;
00201                     f.Index.push_back(ind);
00202                 }
00203                 else
00204                 {
00205                     Trace::Stream<<"Wrong number of indices in .obj file ("<<itokens.size()<<")"<<endl;
00206                 }
00207             }
00208             output.push_back(f);
00209         }
00210     }
00211 }
00212 
00213 vector<OBJPrimitiveIO::Indices> OBJPrimitiveIO::RemoveDuplicateIndices()
00214 {
00215     vector<Indices> ret;
00216     for (vector<Face>::const_iterator fi=m_Faces.begin();
00217         fi!=m_Faces.end(); ++fi)
00218     {
00219         for (vector<Indices>::const_iterator ii=fi->Index.begin();
00220             ii!=fi->Index.end(); ++ii)
00221         {
00222             bool exists=false;
00223             for (vector<Indices>::iterator ri=ret.begin();
00224                 ri!=ret.end(); ++ri)
00225             {   
00226                 if (*ri==*ii) 
00227                 {
00228                     exists=true;
00229                     break;
00230                 }
00231             }
00232             if (!exists) ret.push_back(*ii);
00233         }
00234     }
00235     return ret;
00236 }
00237 
00238 void OBJPrimitiveIO::ReorderData(const vector<OBJPrimitiveIO::Indices> &unique)
00239 {
00240     vector<dVector> NewPosition;
00241     vector<dVector> NewTexture;
00242     vector<dVector> NewNormal;
00243     
00244     for (vector<Indices>::const_iterator i=unique.begin();
00245         i!=unique.end(); ++i)
00246     {
00247         if (!m_Position.empty()) NewPosition.push_back(m_Position[i->Position]);
00248         if (!m_Texture.empty()) NewTexture.push_back(m_Texture[i->Texture]);
00249         if (!m_Normal.empty()) NewNormal.push_back(m_Normal[i->Normal]);
00250     }
00251 
00252     m_Position=NewPosition;
00253     m_Texture=NewTexture;
00254     m_Normal=NewNormal;
00255 }
00256 
00257 void OBJPrimitiveIO::UnifyIndices(const vector<Indices> &unique)
00258 {
00259     m_Indices.clear();
00260     for (vector<Face>::const_iterator fi=m_Faces.begin();
00261         fi!=m_Faces.end(); ++fi)
00262     {
00263         for (vector<Indices>::const_iterator ii=fi->Index.begin();
00264             ii!=fi->Index.end(); ++ii)
00265         {
00266             unsigned int index=0;
00267             for (vector<Indices>::const_iterator ri=unique.begin();
00268                 ri!=unique.end(); ++ri)
00269             {   
00270                 if (*ri==*ii) break;                
00271                 index++;
00272             }
00273             m_Indices.push_back((unsigned int)index);
00274         }
00275     }
00276 }
00277 
00279 
00280 void OBJPrimitiveIO::WriteVertices(const string &pdataname, const string &objname, const Primitive *ob, FILE *file)
00281 {
00282     char line[2048];
00283     const TypedPData<dVector> *pdata = dynamic_cast<const TypedPData<dVector> *>(ob->GetDataRawConst(pdataname));
00284     for (unsigned int i=0; i<ob->Size(); i++)
00285     {
00286         dVector o = pdata->m_Data[i];
00287         snprintf(line,2048,"%s %f %f %f\n",objname.c_str(),o.x,o.y,o.z);
00288         fwrite(line,1,strlen(line),file);
00289     }
00290 }
00291 
00292 void OBJPrimitiveIO::WriteIndices(const Primitive *ob, FILE *file)
00293 {
00294     char line[2048];
00295     const PolyPrimitive *pp = dynamic_cast<const PolyPrimitive *>(ob);
00296     
00297     int facecount=3;
00298     switch (pp->GetType())
00299     {
00300         case PolyPrimitive::TRILIST: facecount=3; break;
00301         case PolyPrimitive::QUADS: facecount=4; break;
00302         default: 
00303         {
00304             Trace::Stream<<"primitive can only be saved with type triangle-list or quad-list"<<endl;
00305             return;
00306         }
00307     }
00308     
00309     if (pp->IsIndexed())
00310     {
00311         vector<unsigned int> indices = pp->GetIndexConst();
00312         unsigned int i=0;
00313         while (i<indices.size())
00314         {
00315             snprintf(line,2048,"f ");
00316             fwrite(line,1,strlen(line),file);
00317 
00318             for (int c=0; c<facecount; c++)
00319             {
00320                 snprintf(line,2048,"%d/%d/%d ",indices[i]+1,indices[i]+1,indices[i]+1);
00321                 fwrite(line,1,strlen(line),file);
00322                 i++;
00323             }
00324             
00325             snprintf(line,2048,"\n");
00326             fwrite(line,1,strlen(line),file);
00327         }
00328     }
00329     else
00330     {
00331         unsigned int i=0;
00332         while (i<pp->Size())
00333         {
00334             snprintf(line,2048,"f ");
00335             fwrite(line,1,strlen(line),file);
00336 
00337             for (int c=0; c<facecount; c++)
00338             {
00339                 snprintf(line,2048,"%d/%d/%d ",i+1,i+1,i+1);
00340                 fwrite(line,1,strlen(line),file);
00341                 i++;
00342             }
00343             
00344             snprintf(line,2048,"\n");
00345             fwrite(line,1,strlen(line),file);
00346         }
00347     }
00348 }
00349 
00350 bool OBJPrimitiveIO::FormatWrite(const std::string &filename, const Primitive *ob)
00351 {
00352     FILE *file = fopen(filename.c_str(),"w");
00353     if (file==NULL)
00354     {
00355         Trace::Stream<<"Cannot open .obj file: "<<filename<<endl;
00356         return false;
00357     }
00358     
00359     WriteVertices("p","v",ob,file);
00360     WriteVertices("n","vn",ob,file);
00361     WriteVertices("t","vt",ob,file);
00362     WriteIndices(ob,file);
00363     
00364     fclose(file);
00365     
00366     return false;
00367 }
00368     

Generated on Wed Sep 17 21:16:30 2008 for The Fluxus Renderer (libfluxus) by  doxygen 1.5.1