00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
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
00061 ReadVectors("v",m_Position);
00062 ReadVectors("vt",m_Texture);
00063 ReadVectors("vn",m_Normal);
00064 ReadIndices(m_Faces);
00065
00066
00067 delete[] m_Data;
00068
00069
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
00082
00083
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
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