ObjIO.cpp
Go to the documentation of this file.
1 
28 /*
29  * ObjIO.cpp
30  *
31  * @date 07.11.2011
32  * @author Florian Otte (fotte@uos.de)
33  * @author Kim Rinnewitz (krinnewitz@uos.de)
34  * @author Sven Schalk (sschalk@uos.de)
35  * @author Lars Kiesow (lkiesow@uos.de)
36  * @author Denis Meyer (denmeyer@uos.de)
37  */
38 
39 #include <climits>
40 #include <iostream>
41 #include <fstream>
42 #include <string.h>
43 #include <locale.h>
44 #include <sstream>
45 
46 #include <boost/filesystem.hpp>
47 #include <boost/tuple/tuple.hpp>
48 
49 #include "lvr2/io/Timestamp.hpp"
50 #include "lvr2/io/ObjIO.hpp"
52 #include "lvr2/texture/Texture.hpp"
54 #include "lvr2/util/Util.hpp"
55 
56 
57 namespace lvr2
58 {
59 
60 using namespace std; // Bitte vergebt mir....
61 // Meinst du wirklich, dass ich dir so etwas durchgehen lassen kann?
62 
63 void tokenize(const string& str,
64  vector<string>& tokens,
65  const string& delimiters = " ")
66 {
67  // Skip delimiters at beginning.
68  string::size_type lastPos = str.find_first_not_of(delimiters, 0);
69  // Find first "non-delimiter".
70  string::size_type pos = str.find_first_of(delimiters, lastPos);
71 
72  while (string::npos != pos || string::npos != lastPos)
73  {
74  // Found a token, add it to the vector.
75  tokens.push_back(str.substr(lastPos, pos - lastPos));
76  // Skip delimiters. Note the "not_of"
77  lastPos = str.find_first_not_of(delimiters, pos);
78  // Find next "non-delimiter"
79  pos = str.find_first_of(delimiters, lastPos);
80  }
81 }
82 
84  map<string, int>& matNames,
85  vector<Material>& materials,
86  vector<Texture>& textures,
87  string mtlname)
88 {
89  cout << "Parsing " << mtlname << endl;
90 
91  // Get path object
92  boost::filesystem::path p(mtlname);
93  p = p.remove_filename();
94 
95  ifstream in(mtlname.c_str());
96  if(in.good())
97  {
98  char buffer[1024];
99  int matIndex = 0;
100  while(in.good())
101  {
102  in.getline(buffer, 1024);
103 
104  // Skip comments
105  if(buffer[0] == '#') continue;
106 
107  stringstream ss(buffer);
108  string keyword;
109  ss >> keyword;
110 
111 
112  if(keyword == "newmtl")
113  {
114  string matName;
115  ss >> matName;
116  map<string, int>::iterator it = matNames.find(matName);
117  if(it == matNames.end())
118  {
119  Material m;
120  m.m_color = boost::optional<Rgb8Color>({128, 128, 128});
121  m.m_texture = boost::none;
122  materials.push_back(m);
123  matNames[matName] = matIndex;
124  matIndex++;
125 
126  }
127  else
128  {
129  //m = materials[matNames[matName]];
130  cout << "ObjIO::parseMtlFile(): Warning: Duplicate material: " << matName << endl;
131  }
132  }
133  else if(keyword == "Ka")
134  {
135  float r, g, b;
136  ss >> r >> g >> b;
137  Material& current = materials.back();
138  current.m_color = boost::optional<Rgb8Color>({
139  static_cast<unsigned char>(r * 255 + 0.5),
140  static_cast<unsigned char>(g * 255 + 0.5),
141  static_cast<unsigned char>(b * 255 + 0.5)
142  });
143  }
144  else if(keyword == "map_Kd")
145  {
146  string texname;
147  ss >> texname;
148 
149  // Add full path to texture file name
150  boost::filesystem::path tex_file = p / texname;
151 
152  Texture texture = TextureFactory::readTexture(tex_file.string());
153  unsigned int tex_idx = textures.size();
154  texture.m_index = tex_idx;
155  textures.push_back(std::move(texture));
156  materials.back().m_texture = TextureHandle(tex_idx);
157  }
158  else
159  {
160  continue;
161  }
162  }
163  }
164  else
165  {
166  cout << "ObjIO::parseMtlFile(): Error opening '" << mtlname << "'." << endl;
167  }
168 }
169 
171 {
172  // Get path from filename
173  boost::filesystem::path p(filename);
174 
175  ifstream in(filename.c_str());
176 
178 
179  vector<float> vertices;
180  vector<float> normals;
181  vector<unsigned char> colors;
182  vector<float> texcoords;
183  vector<uint> faceMaterials;
184  vector<uint> faces;
185  vector<Material>& materials = mesh->getMaterials();
186  vector<Texture>& textures = mesh->getTextures();
187 
188  map<string, int> matNames;
189 
190  int currentMat = 0;
191 
192  if(in.good())
193  {
194  char buffer[1024];
195  while(in.good())
196  {
197  in.getline(buffer, 1024);
198 
199  // Skip comments
200  if(buffer[0] == '#') continue;
201 
202  stringstream ss(buffer);
203  string keyword;
204  ss >> keyword;
205  float x, y, z;
206  float r, g, b;
207  if(keyword == "v")
208  {
209  ss >> x >> y >> z;
210  vertices.push_back(x);
211  vertices.push_back(y);
212  vertices.push_back(z);
213  // TODO: check if r is end of line
214  std::string s;
215  bool colors_exist = static_cast<bool>(ss >> r);
216  // r = s[0];
217  ss >> g >> b;
218  if(colors_exist)
219  {
220  colors.push_back(static_cast<unsigned char>(r*255.0 + 0.5));
221  colors.push_back(static_cast<unsigned char>(g*255.0 + 0.5));
222  colors.push_back(static_cast<unsigned char>(b*255.0 + 0.5));
223  }
224  }
225  else if(keyword == "vt")
226  {
227  ss >> x >> y >> z;
228  texcoords.push_back(x);
229  texcoords.push_back(1.0 - y);
230  // z is ignored because texcoords only have 2 coords...
231  //texcoords.push_back(z);
232  }
233  else if(keyword == "vn")
234  {
235  ss >> x >> y >> z;
236  normals.push_back(x);
237  normals.push_back(y);
238  normals.push_back(z);
239  }
240  else if(keyword == "f")
241  {
242  vector<string> tokens;
243  tokenize(buffer, tokens);
244 
245  if(tokens.size() < 4)
246  continue;
247 
248  vector<string> tokens2;
249  tokenize(tokens.at(1),tokens2,"/");
250  int a = atoi(tokens2.at(0).c_str());
251  tokens2.clear();
252 
253  tokenize(tokens.at(2),tokens2,"/");
254  int b = atoi(tokens2.at(0).c_str());
255  tokens2.clear();
256 
257  tokenize(tokens.at(3),tokens2,"/");
258  int c = atoi(tokens2.at(0).c_str());
259  tokens2.clear();
260 
261  faces.push_back(a - 1);
262  faces.push_back(b - 1);
263  faces.push_back(c - 1);
264 
265  // Use current material
266  faceMaterials.push_back(currentMat);
267  }
268  else if(keyword == "usemtl")
269  {
270  string mtlname;
271  ss >> mtlname;
272  // Find name and set current material
273  map<string, int>::iterator it = matNames.find(mtlname);
274  if(it == matNames.end())
275  {
276  cout << "ObjIO:read(): Warning material '" << mtlname << "' is undefined." << endl;
277  }
278  else
279  {
280  currentMat = it->second;
281  }
282  }
283  else if(keyword == "mtllib")
284  {
285  // Get current path
286  p = p.remove_filename();
287 
288  // Append .mtl file name
289  string mtlfile;
290  ss >> mtlfile;
291  p = p / mtlfile;
292 
293  // Get path as string and parse mtl
294  string mtl_path = p.string();
295  parseMtlFile(matNames, materials, textures, mtl_path);
296  }
297  }
298 
299  }
300  else
301  {
302  cout << timestamp << "ObjIO::read(): Unable to open file'" << filename << "'." << endl;
303  }
304 
305  mesh->setVertices(Util::convert_vector_to_shared_array(vertices), vertices.size() / 3);
306  mesh->setFaceIndices(Util::convert_vector_to_shared_array(faces), faces.size() / 3);
307 
308  if(faceMaterials.size() == faces.size() / 3)
309  {
310  mesh->setFaceMaterialIndices(Util::convert_vector_to_shared_array(faceMaterials));
311  }
312  else
313  {
314  cout << "ObjIO::read(): Warning: Face material index buffer does not match face number." << endl;
315  }
316 
317  mesh->setTextureCoordinates(Util::convert_vector_to_shared_array(texcoords));
318  mesh->setVertexNormals(Util::convert_vector_to_shared_array(normals));
319  mesh->setVertexColors(Util::convert_vector_to_shared_array(colors));
320 
321  ModelPtr m(new Model(mesh));
322  m_model = m;
323 
324  return m;
325 }
326 
327 
329 {
330  private:
332  public:
333  sort_indices(uintArr faceMaterialIndices) : faceMaterialIndices(faceMaterialIndices) {}
334  bool operator()(int i, int j) { return faceMaterialIndices[i]<faceMaterialIndices[j]; }
335 };
336 
337 void ObjIO::save( string filename )
338 {
339  if (!m_model->m_mesh)
340  {
341  std::cout << "ObjIO: Unable to save to file " << filename << ". No mesh to save present." << std::endl;
342  return;
343  }
344 
345  size_t w_color;
346  size_t lenVertices = m_model->m_mesh->numVertices();
347  size_t lenNormals = lenVertices;
348  size_t lenFaces = m_model->m_mesh->numFaces();
349  size_t lenTextureCoordinates = lenVertices;
350  size_t lenFaceMaterialIndices = lenFaces;
351  size_t lenColors = lenVertices;
352  floatArr vertices = m_model->m_mesh->getVertices();
353  floatArr normals = m_model->m_mesh->getVertexNormals();
354  floatArr textureCoordinates = m_model->m_mesh->getTextureCoordinates();
355  indexArray faceIndices = m_model->m_mesh->getFaceIndices();
356  vector<Material> &materials = m_model->m_mesh->getMaterials();
357  indexArray faceMaterialIndices = m_model->m_mesh->getFaceMaterialIndices();
358  ucharArr colors = m_model->m_mesh->getVertexColors(w_color);
359 
360  bool saveTextures = false;
361  std::string textureImageExtension = ".ppm";
362 
363  // should we write textures to disk?
364  intOptional saveTexturesOpt = m_model->m_mesh->getIntAtomic("mesh_save_textures");
365  if (saveTexturesOpt && (*saveTexturesOpt) != 0)
366  {
367  saveTextures = true;
368  }
369 
370  intOptional textureImageExtensionOpt = m_model->m_mesh->getIntAtomic("mesh_texture_image_extension");
371 
372  // 0 = .ppm (default); 1 = .jpg; 2 = .png
373  if (textureImageExtensionOpt)
374  {
375  switch (*textureImageExtensionOpt) {
376  case 1: textureImageExtension = ".jpg"; break;
377  case 2: textureImageExtension = ".png"; break;
378  }
379  }
380 
381 
382  std::set<unsigned int> materialIndexSet;
383  std::set<unsigned int> colorIndexSet;
384 
385  ofstream out(filename.c_str());
386  ofstream mtlFile("textures.mtl");
387 
388  if(out.good())
389  {
390  out<<"mtllib textures.mtl"<<endl;
391 
392  if ( !vertices )
393  {
394  cerr << "Received no vertices to store. Aborting save operation." << endl;
395  return;
396  }
397  out << endl << endl << "## Beginning of vertex definitions.\n";
398 
399  for( size_t i=0; i < lenVertices; ++i )
400  {
401  out << "v " << vertices[i*3 + 0] << " "
402  << vertices[i*3 + 1] << " "
403  << vertices[i*3 + 2] << " ";
404  if(lenColors>0){
405  unsigned char r = colors[i*w_color + 0],
406  g = colors[i*w_color + 1],
407  b = colors[i*w_color + 2];
408 
409  out << static_cast<float>(r)/255.0 << " "
410  << static_cast<float>(g)/255.0 << " "
411  << static_cast<float>(b)/255.0 ;
412  }
413 
414  out << endl;
415  }
416 
417  out<<endl;
418 
419  if (m_model->m_mesh->hasVertexNormals())
420  {
421  out << endl << endl << "## Beginning of vertex normals.\n";
422  for( size_t i=0; i < lenNormals; ++i )
423  {
424  out << "vn " << normals[i*3 + 0] << " "
425  << normals[i*3 + 1] << " "
426  << normals[i*3 + 2] << endl;
427  }
428  }
429 
430  out << endl << endl << "## Beginning of vertexTextureCoordinates.\n";
431 
432  for( size_t i=0; i < lenTextureCoordinates; ++i )
433  {
434  out << "vt " << textureCoordinates[i*2 + 0] << " "
435  << 1.0 - textureCoordinates[i*2 + 1] << " "
436  << 0.0 << endl;
437  }
438 
439 
440  out << endl << endl << "## Beginning of faces.\n";
441  // format of a face: f v/vt/vn
442  //for( size_t i = 0; i < lenFaces; ++i )
443  //{
444  //cout << faceMaterialIndices[i] << " " << lenFaceMaterials << endl;
445  //RGBMaterial* m = materials[faceMaterialIndices[i]];
446  //if(m->texture_index >= 0)
447  //{
448  //out << "usemtl texture_" << m->texture_index << endl;
449  //}
450  //else
451  //{
452  //out << "usemtl color_" << faceMaterialIndices[i] << endl;
453  //}
454 
459  //out << "f "
460  //<< faceIndices[i * 3 + 0] + 1 << "/"
461  //<< faceIndices[i * 3 + 0] + 1 << "/"
462  //<< faceIndices[i * 3 + 0] + 1 << " "
463  //<< faceIndices[i * 3 + 1] + 1 << "/"
464  //<< faceIndices[i * 3 + 1] + 1 << "/"
465  //<< faceIndices[i * 3 + 1] + 1 << " "
466  //<< faceIndices[i * 3 + 2] + 1 << "/"
467  //<< faceIndices[i * 3 + 2] + 1 << "/"
468  //<< faceIndices[i * 3 + 2] + 1 << endl;
469  //}
470 
471  // format of a face: f v/vt/vn
472 
473  std::vector<int> color_indices, texture_indices;
474 
475  //splitting materials in colors an textures
476  for(size_t i = 0; i< lenFaceMaterialIndices; ++i)
477  {
478  Material &m = materials[faceMaterialIndices[i]];
479  if(m.m_texture)
480  {
481  texture_indices.push_back(i);
482  }else{
483  color_indices.push_back(i);
484  }
485  }
486  //sort faceMaterialsIndices: colors, textur_indices
487  //sort new index lists instead of the faceMaterialIndices
488  std::sort(color_indices.begin(),color_indices.end(),sort_indices(faceMaterialIndices));
489  std::sort(texture_indices.begin(),texture_indices.end(),sort_indices(faceMaterialIndices));
490 
491  //colors
492  for(size_t i = 0; i<color_indices.size() ; i++)
493  {
494  unsigned int first = faceMaterialIndices[color_indices[i]];
495  unsigned int face_index=color_indices[i];
496 
497  if( i == 0 || first != faceMaterialIndices[color_indices[i-1]] )
498  {
499  out << "usemtl color_" << faceMaterialIndices[color_indices[i]] << endl;
500  out << "f "
501  << faceIndices[face_index * 3 + 0] + 1 << "/"
502  << faceIndices[face_index * 3 + 0] + 1 << "/"
503  << faceIndices[face_index * 3 + 0] + 1 << " "
504  << faceIndices[face_index * 3 + 1] + 1 << "/"
505  << faceIndices[face_index * 3 + 1] + 1 << "/"
506  << faceIndices[face_index * 3 + 1] + 1 << " "
507  << faceIndices[face_index * 3 + 2] + 1 << "/"
508  << faceIndices[face_index * 3 + 2] + 1 << "/"
509  << faceIndices[face_index * 3 + 2] + 1 << endl;
510 
511  }else if( first == faceMaterialIndices[color_indices[i-1]] )
512  {
513  out << "f "
514  << faceIndices[face_index * 3 + 0] + 1 << "/"
515  << faceIndices[face_index * 3 + 0] + 1 << "/"
516  << faceIndices[face_index * 3 + 0] + 1 << " "
517  << faceIndices[face_index * 3 + 1] + 1 << "/"
518  << faceIndices[face_index * 3 + 1] + 1 << "/"
519  << faceIndices[face_index * 3 + 1] + 1 << " "
520  << faceIndices[face_index * 3 + 2] + 1 << "/"
521  << faceIndices[face_index * 3 + 2] + 1 << "/"
522  << faceIndices[face_index * 3 + 2] + 1 << endl;
523  }
524  }
525 
526  out<<endl;
527 
528  //textures
529  for(size_t i = 0; i<texture_indices.size() ; i++)
530  {
531  Material &first = materials[faceMaterialIndices[texture_indices[i]]];
532  size_t face_index=texture_indices[i];
533 
534  if(i==0 || first.m_texture != materials[faceMaterialIndices[texture_indices[i-1]]].m_texture )
535  {
536  out << "usemtl texture_" << first.m_texture->idx() << endl;
537  //std::cout << "usemtl texture_" << first->texture_index << std::endl;
538  out << "f "
539  << faceIndices[face_index * 3 + 0] + 1 << "/"
540  << faceIndices[face_index * 3 + 0] + 1 << "/"
541  << faceIndices[face_index * 3 + 0] + 1 << " "
542  << faceIndices[face_index * 3 + 1] + 1 << "/"
543  << faceIndices[face_index * 3 + 1] + 1 << "/"
544  << faceIndices[face_index * 3 + 1] + 1 << " "
545  << faceIndices[face_index * 3 + 2] + 1 << "/"
546  << faceIndices[face_index * 3 + 2] + 1 << "/"
547  << faceIndices[face_index * 3 + 2] + 1 << endl;
548  }else if(first.m_texture == materials[faceMaterialIndices[texture_indices[i-1]]].m_texture )
549  {
550  out << "f "
551  << faceIndices[face_index * 3 + 0] + 1 << "/"
552  << faceIndices[face_index * 3 + 0] + 1 << "/"
553  << faceIndices[face_index * 3 + 0] + 1 << " "
554  << faceIndices[face_index * 3 + 1] + 1 << "/"
555  << faceIndices[face_index * 3 + 1] + 1 << "/"
556  << faceIndices[face_index * 3 + 1] + 1 << " "
557  << faceIndices[face_index * 3 + 2] + 1 << "/"
558  << faceIndices[face_index * 3 + 2] + 1 << "/"
559  << faceIndices[face_index * 3 + 2] + 1 << endl;
560  }
561  }
562 
563 
564  out<<endl;
565  out.close();
566  }
567  else
568  {
569  cerr << "no good. file! \n";
570  }
571 
572 
573 
574  if( mtlFile.good() )
575  {
576 
577  for(int i = 0; i < materials.size(); i++)
578  {
579  const Material &m = materials[i];
580  if(!m.m_texture)
581  {
582  mtlFile << "newmtl color_" << i << endl;
583  mtlFile << "Ka "
584  << m.m_color->at(0) / 255.0f << " "
585  << m.m_color->at(1) / 255.0f << " "
586  << m.m_color->at(2) / 255.0f << endl;
587  mtlFile << "Kd "
588  << m.m_color->at(0) / 255.0f << " "
589  << m.m_color->at(1) / 255.0f << " "
590  << m.m_color->at(2) / 255.0f << endl << endl;
591  }
592  else
593  {
594  mtlFile << "newmtl texture_" << m.m_texture->idx() << endl;
595  mtlFile << "Ka 1.000 1.000 1.000" << endl;
596  mtlFile << "Kd 1.000 1.000 1.000" << endl;
597  mtlFile << "map_Kd texture_" << m.m_texture->idx()
598  << textureImageExtension << endl << endl;
599  }
600  }
601  }
602  mtlFile.close();
603 
604  // save textures
605  if (saveTextures)
606  {
607  std::vector<Texture>& texts = m_model->m_mesh->getTextures();
608 
609  for (size_t i = 0; i < texts.size(); i++)
610  {
611  TextureFactory::saveTexture(texts[i], "texture_" + std::to_string(i) + textureImageExtension);
612  }
613  }
614 }
615 
616 
617 } // Namespace lvr2
void saveTextures(std::vector< int32_t > *textureValue, textureArr textures, size_t numTextures)
pushes the given textures in a int32_t vector to store it in the draco structure
A material that stores information about color and texture of a cluster.
Definition: Material.hpp:42
HalfEdgeMesh< Vec > mesh
void first(int id)
Definition: example.cpp:7
std::shared_ptr< MeshBuffer > MeshBufferPtr
Definition: MeshBuffer.hpp:217
boost::shared_array< unsigned int > uintArr
Definition: DataStruct.hpp:130
int m_index
Texture index.
Definition: Texture.hpp:108
void tokenize(const string &str, vector< string > &tokens, const string &delimiters=" ")
Definition: ObjIO.cpp:63
static Timestamp timestamp
A global time stamp object for program runtime measurement.
Definition: Timestamp.hpp:116
boost::optional< int > intOptional
Definition: BaseBuffer.hpp:40
boost::shared_array< unsigned char > ucharArr
Definition: DataStruct.hpp:137
Handle to access textures of the mesh.
Definition: Handles.hpp:158
static void saveTexture(const Texture &texture, std::string filename)
TODO.
boost::shared_array< unsigned int > indexArray
Definition: DataStruct.hpp:128
uintArr faceMaterialIndices
Definition: ObjIO.cpp:331
This class represents a texture.
Definition: Texture.hpp:54
boost::shared_array< float > floatArr
Definition: DataStruct.hpp:133
SharedPointer p
ModelPtr read(string filename)
Parse the given file and load supported elements.
Definition: ObjIO.cpp:170
std::shared_ptr< Model > ModelPtr
Definition: Model.hpp:80
bool operator()(int i, int j)
Definition: ObjIO.cpp:334
void save(string filename)
Writes the mesh to an obj file.
Definition: ObjIO.cpp:337
boost::optional< Rgb8Color > m_color
Optional color.
Definition: Material.hpp:47
static Texture readTexture(std::string filename)
Returns a new texture if the file contains readable image data or a null point if the file couldn&#39;t b...
void parseMtlFile(map< string, int > &matNames, vector< Material > &materials, vector< Texture > &textures, string mtlname)
Definition: ObjIO.cpp:83
boost::optional< TextureHandle > m_texture
Optional texture handle.
Definition: Material.hpp:45
sort_indices(uintArr faceMaterialIndices)
Definition: ObjIO.cpp:333
static boost::shared_array< T > convert_vector_to_shared_array(std::vector< T > source)
Creates a shared array with the data from the given vector.
Definition: Util.hpp:108
The MeshBuffer Mesh representation for I/O modules.
Definition: MeshBuffer.hpp:41


lvr2
Author(s): Thomas Wiemann , Sebastian Pütz , Alexander Mock , Lars Kiesow , Lukas Kalbertodt , Tristan Igelbrink , Johan M. von Behren , Dominik Feldschnieders , Alexander Löhr
autogenerated on Mon Feb 28 2022 22:46:08