gKit2 light
Files | Classes | Functions
utilitaires pour manipuler des objets 3d

Files

file  mesh.h
 
file  orbiter.h
 
file  wavefront.h
 
file  wavefront_fast.h
 

Classes

struct  TriangleData
 representation d'un triangle. More...
 
struct  TriangleGroup
 representation d'un ensemble de triangles de meme matiere. More...
 
class  Mesh
 representation d'un objet / maillage. More...
 
class  Orbiter
 representation de la camera, type orbiter, placee sur une sphere autour du centre de l'objet. More...
 

Functions

Mesh read_mesh (const char *filename)
 charge un fichier wavefront .obj et renvoie un mesh compose de triangles non indexes. utiliser glDrawArrays pour l'afficher. a detruire avec Mesh::release( ). More...
 
Mesh read_indexed_mesh (const char *filename)
 charge un fichier wavefront .obj et renvoie un mesh compose de triangles indexes. utiliser glDrawElements pour l'afficher. a detruire avec Mesh::release( ). More...
 
int write_mesh (const Mesh &mesh, const char *filename, const char *materials_filename=nullptr)
 enregistre un mesh dans un fichier .obj. More...
 
Materials read_materials (const char *filename)
 charge une description de matieres, utilise par read_mesh. More...
 
int write_materials (const Materials &materials, const char *filename, const char *path="")
 enregistre une description de matieres. More...
 
Mesh read_mesh_fast (const char *filename)
 charge un fichier wavefront .obj et renvoie un mesh compose de triangles non indexes. utiliser glDrawArrays pour l'afficher. a detruire avec Mesh::release( ). More...
 
Mesh read_indexed_mesh_fast (const char *filename)
 charge un fichier wavefront .obj et renvoie un mesh compose de triangles indexes. utiliser glDrawElements pour l'afficher. a detruire avec Mesh::release( ). More...
 

Detailed Description


Class Documentation

◆ TriangleGroup

struct TriangleGroup

representation d'un ensemble de triangles de meme matiere.

Definition at line 102 of file mesh.h.

Class Members
int index indice de la "propriete"du groupe de triangles, par defaut : indice de la matiere
int first premier triangle du groupe
int n nombre de triangles du groupe

Function Documentation

◆ read_mesh()

Mesh read_mesh ( const char *  filename)

charge un fichier wavefront .obj et renvoie un mesh compose de triangles non indexes. utiliser glDrawArrays pour l'afficher. a detruire avec Mesh::release( ).

Definition at line 14 of file wavefront.cpp.

15 {
16  FILE *in= fopen(filename, "rb");
17  if(in == NULL)
18  {
19  printf("[error] loading mesh '%s'...\n", filename);
20  return Mesh::error();
21  }
22 
23  Mesh data(GL_TRIANGLES);
24 
25  printf("loading mesh '%s'...\n", filename);
26 
27  std::vector<vec3> positions;
28  std::vector<vec2> texcoords;
29  std::vector<vec3> normals;
30  int material_id= -1;
31 
32  std::vector<int> idp;
33  std::vector<int> idt;
34  std::vector<int> idn;
35 
36  char tmp[1024];
37  char line_buffer[1024];
38  bool error= true;
39  for(;;)
40  {
41  // charge une ligne du fichier
42  if(fgets(line_buffer, sizeof(line_buffer), in) == NULL)
43  {
44  error= false; // fin du fichier, pas d'erreur detectee
45  break;
46  }
47 
48  // force la fin de la ligne, au cas ou
49  line_buffer[sizeof(line_buffer) -1]= 0;
50 
51  // saute les espaces en debut de ligne
52  char *line= line_buffer;
53  while(*line && isspace(*line))
54  line++;
55 
56  if(line[0] == 'v')
57  {
58  float x, y, z;
59  if(line[1] == ' ') // position x y z
60  {
61  if(sscanf(line, "v %f %f %f", &x, &y, &z) != 3)
62  break;
63  positions.push_back( vec3(x, y, z) );
64  }
65  else if(line[1] == 'n') // normal x y z
66  {
67  if(sscanf(line, "vn %f %f %f", &x, &y, &z) != 3)
68  break;
69  normals.push_back( vec3(x, y, z) );
70  }
71  else if(line[1] == 't') // texcoord x y
72  {
73  if(sscanf(line, "vt %f %f", &x, &y) != 2)
74  break;
75  texcoords.push_back( vec2(x, y) );
76  }
77  }
78 
79  else if(line[0] == 'f') // triangle a b c, les sommets sont numerotes a partir de 1 ou de la fin du tableau (< 0)
80  {
81  idp.clear();
82  idt.clear();
83  idn.clear();
84 
85  int next;
86  for(line= line +1; ; line= line + next)
87  {
88  idp.push_back(0);
89  idt.push_back(0);
90  idn.push_back(0); // 0: invalid index
91 
92  // analyse les attributs du sommet : p/t/n ou p//n ou p/t ou p...
93  next= 0;
94  if(sscanf(line, " %d/%d/%d %n", &idp.back(), &idt.back(), &idn.back(), &next) == 3)
95  continue;
96  else if(sscanf(line, " %d/%d %n", &idp.back(), &idt.back(), &next) == 2)
97  continue;
98  else if(sscanf(line, " %d//%d %n", &idp.back(), &idn.back(), &next) == 2)
99  continue;
100  else if(sscanf(line, " %d %n", &idp.back(), &next) == 1)
101  continue;
102  else if(next == 0) // fin de ligne
103  break;
104  }
105  assert(idt.size() == idp.size());
106  assert(idn.size() == idp.size());
107 
108  // force une matiere par defaut, si necessaire
109  if(material_id == -1)
110  {
111  material_id= data.materials().default_material_index();
112  printf("usemtl default\n");
113  }
114 
115  data.material(material_id);
116 
117  // triangule la face
118  for(int v= 2; v +1 < int(idp.size()); v++)
119  {
120  int idv[3]= { 0, v -1, v };
121  for(int i= 0; i < 3; i++)
122  {
123  int k= idv[i];
124  int p= (idp[k] < 0) ? int(positions.size()) + idp[k] : idp[k] -1;
125  int t= (idt[k] < 0) ? int(texcoords.size()) + idt[k] : idt[k] -1;
126  int n= (idn[k] < 0) ? int(normals.size()) + idn[k] : idn[k] -1;
127 
128  if(p < 0) break; // error
129 
130  // attribut du ieme sommet
131  if(t >= 0) data.texcoord(texcoords[t]);
132  if(n >= 0) data.normal(normals[n]);
133  data.vertex(positions[p]);
134  }
135  }
136  }
137 
138  else if(line[0] == 'm')
139  {
140  if(sscanf(line, "mtllib %[^\r\n]", tmp) == 1)
141  {
142  std::string materials_filename;
143  if(tmp[0] != '/' && tmp[1] != ':') // windows c:\ pour les chemins complets...
144  materials_filename= normalize_filename(pathname(filename) + tmp);
145  else
146  materials_filename= std::string(tmp);
147 
148  // charge les matieres
149  Materials materials= read_materials( materials_filename.c_str() );
150 
151  // enregistre les matieres dans le mesh
152  data.materials(materials);
153  }
154  }
155 
156  else if(line[0] == 'u')
157  {
158  if(sscanf(line, "usemtl %[^\r\n]", tmp) == 1)
159  material_id= data.materials().find(tmp);
160  }
161  }
162 
163  fclose(in);
164 
165  if(error)
166  printf("[error] loading mesh '%s'...\n%s\n\n", filename, line_buffer);
167  else
168  printf("mesh '%s': %d positions %s %s\n", filename, int(data.positions().size()), data.has_texcoord() ? "texcoord" : "", data.has_normal() ? "normal" : "");
169 
170  return data;
171 }
representation d'un objet / maillage.
Definition: mesh.h:112
static Mesh & error()
Definition: mesh.h:348
void printf(Text &text, const int px, const int py, const char *format,...)
affiche un texte a la position x, y. meme utilisation que printf().
Definition: text.cpp:140
Materials read_materials(const char *filename)
charge une description de matieres, utilise par read_mesh.
Definition: wavefront.cpp:454
void normals(MeshData &data)
(re-) calcule les normales des sommets. utiliser avant les reindexations, cf indices() et vertices().
Definition: mesh_data.cpp:307
std::string pathname(const std::string &filename)
Definition: files.cpp:68
vecteur generique, utilitaire.
Definition: vec.h:131
vecteur generique, utilitaire.
Definition: vec.h:146

◆ read_indexed_mesh()

Mesh read_indexed_mesh ( const char *  filename)

charge un fichier wavefront .obj et renvoie un mesh compose de triangles indexes. utiliser glDrawElements pour l'afficher. a detruire avec Mesh::release( ).

Definition at line 197 of file wavefront.cpp.

198 {
199  FILE *in= fopen(filename, "rb");
200  if(in == NULL)
201  {
202  printf("[error] loading indexed mesh '%s'...\n", filename);
203  return Mesh::error();
204  }
205 
206  Mesh data(GL_TRIANGLES);
207 
208  printf("loading indexed mesh '%s'...\n", filename);
209 
210  std::vector<vec3> positions;
211  std::vector<vec2> texcoords;
212  std::vector<vec3> normals;
213  int material_id= -1;
214 
215  std::vector<int> idp;
216  std::vector<int> idt;
217  std::vector<int> idn;
218 
219  std::map<vertex, int> remap;
220 
221  char tmp[1024];
222  char line_buffer[1024];
223  bool error= true;
224  for(;;)
225  {
226  // charge une ligne du fichier
227  if(fgets(line_buffer, sizeof(line_buffer), in) == NULL)
228  {
229  error= false; // fin du fichier, pas d'erreur detectee
230  break;
231  }
232 
233  // force la fin de la ligne, au cas ou
234  line_buffer[sizeof(line_buffer) -1]= 0;
235 
236  // saute les espaces en debut de ligne
237  char *line= line_buffer;
238  while(*line && isspace(*line))
239  line++;
240 
241  if(line[0] == 'v')
242  {
243  float x, y, z;
244  if(line[1] == ' ') // position x y z
245  {
246  if(sscanf(line, "v %f %f %f", &x, &y, &z) != 3)
247  break;
248  positions.push_back( vec3(x, y, z) );
249  }
250  else if(line[1] == 'n') // normal x y z
251  {
252  if(sscanf(line, "vn %f %f %f", &x, &y, &z) != 3)
253  break;
254  normals.push_back( vec3(x, y, z) );
255  }
256  else if(line[1] == 't') // texcoord x y
257  {
258  if(sscanf(line, "vt %f %f", &x, &y) != 2)
259  break;
260  texcoords.push_back( vec2(x, y) );
261  }
262  }
263 
264  else if(line[0] == 'f') // triangle a b c, les sommets sont numerotes a partir de 1 ou de la fin du tableau (< 0)
265  {
266  idp.clear();
267  idt.clear();
268  idn.clear();
269 
270  int next;
271  for(line= line +1; ; line= line + next)
272  {
273  idp.push_back(0);
274  idt.push_back(0);
275  idn.push_back(0); // 0: invalid index
276 
277  // analyse les attributs du sommet : p/t/n ou p//n ou p/t ou p...
278  next= 0;
279  if(sscanf(line, " %d/%d/%d %n", &idp.back(), &idt.back(), &idn.back(), &next) == 3)
280  continue;
281  else if(sscanf(line, " %d/%d %n", &idp.back(), &idt.back(), &next) == 2)
282  continue;
283  else if(sscanf(line, " %d//%d %n", &idp.back(), &idn.back(), &next) == 2)
284  continue;
285  else if(sscanf(line, " %d %n", &idp.back(), &next) == 1)
286  continue;
287  else if(next == 0) // fin de ligne
288  break;
289  }
290 
291  // force une matiere par defaut, si necessaire
292  if(material_id == -1 && data.materials().count() > 0)
293  {
294  material_id= data.materials().default_material_index();
295  printf("usemtl default\n");
296  }
297 
298  data.material(material_id);
299 
300  // triangule la face
301  for(int v= 2; v +1 < (int) idp.size(); v++)
302  {
303  int idv[3]= { 0, v -1, v };
304  for(int i= 0; i < 3; i++)
305  {
306  int k= idv[i];
307  // indices des attributs du sommet
308  int p= (idp[k] < 0) ? (int) positions.size() + idp[k] : idp[k] -1;
309  int t= (idt[k] < 0) ? (int) texcoords.size() + idt[k] : idt[k] -1;
310  int n= (idn[k] < 0) ? (int) normals.size() + idn[k] : idn[k] -1;
311 
312  if(p < 0) break; // error
313 
314  // recherche / insere le sommet
315  auto found= remap.insert( std::make_pair(vertex(material_id, p, t, n), int(remap.size())) );
316  if(found.second)
317  {
318  // pas trouve, copie les nouveaux attributs
319  if(t != -1) data.texcoord(texcoords[t]);
320  if(n != -1) data.normal(normals[n]);
321  data.vertex(positions[p]);
322  }
323 
324  // construit l'index buffer
325  data.index(found.first->second);
326  }
327  }
328  }
329 
330  else if(line[0] == 'm')
331  {
332  if(sscanf(line, "mtllib %[^\r\n]", tmp) == 1)
333  {
334  Materials materials= read_materials( normalize_filename(pathname(filename) + tmp).c_str() );
335  // enregistre les matieres dans le mesh
336  data.materials(materials);
337  }
338  }
339 
340  else if(line[0] == 'u')
341  {
342  if(sscanf(line, "usemtl %[^\r\n]", tmp) == 1)
343  material_id= data.materials().find(tmp);
344  }
345  }
346 
347  fclose(in);
348 
349  if(error)
350  printf("[error] loading indexed mesh '%s'...\n%s\n\n", filename, line_buffer);
351  else
352  printf(" %d indices, %d positions %d texcoords %d normals\n",
353  int(data.indices().size()), int(data.positions().size()), int(data.texcoords().size()), int(data.normals().size()));
354 
355  return data;
356 }
representation de l'indexation complete d'un sommet
Definition: wavefront.cpp:176

◆ write_mesh()

int write_mesh ( const Mesh mesh,
const char *  filename,
const char *  materials_filename = nullptr 
)

enregistre un mesh dans un fichier .obj.

Definition at line 359 of file wavefront.cpp.

360 {
361  if(mesh == Mesh::error())
362  return -1;
363 
364  if(mesh.primitives() != GL_TRIANGLES)
365  return -1;
366  if(mesh.positions().size() == 0)
367  return -1;
368  if(filename == nullptr)
369  return -1;
370 
371  FILE *out= fopen(filename, "wt");
372  if(out == nullptr)
373  return -1;
374 
375  printf("writing mesh '%s'...\n", filename);
376  if(materials_filename && materials_filename[0] && strcmp(filename, materials_filename))
377  {
378  printf(" materials '%s'...\n", materials_filename);
379  fprintf(out, "mtllib %s\n", materials_filename);
380  }
381  {
382  printf(" %d positions, %d texcoords, %d normals\n", int(mesh.positions().size()), int(mesh.texcoords().size()), int(mesh.normals().size()));
383  }
384 
385  const std::vector<vec3>& positions= mesh.positions();
386  for(unsigned i= 0; i < positions.size(); i++)
387  fprintf(out, "v %f %f %f\n", positions[i].x, positions[i].y, positions[i].z);
388  fprintf(out, "\n");
389 
390  //~ bool has_texcoords= false;
391  const std::vector<vec2>& texcoords= mesh.texcoords();
392  bool has_texcoords= (texcoords.size() == positions.size());
393  for(unsigned i= 0; i < texcoords.size(); i++)
394  fprintf(out, "vt %f %f\n", texcoords[i].x, texcoords[i].y);
395  fprintf(out, "\n");
396 
397  //~ bool has_normals= false;
398  const std::vector<vec3>& normals= mesh.normals();
399  bool has_normals= (normals.size() == positions.size());
400  for(unsigned i= 0; i < normals.size(); i++)
401  fprintf(out, "vn %f %f %f\n", normals[i].x, normals[i].y, normals[i].z);
402  fprintf(out, "\n");
403 
404  int material_id= -1;
405  const std::vector<unsigned>& materials= mesh.material_indices();
406  bool has_materials= (materials.size() > 0);
407 
408  const std::vector<unsigned>& indices= mesh.indices();
409  bool has_indices= (indices.size() > 0);
410 
411  unsigned n= has_indices ? indices.size() : positions.size();
412  for(unsigned i= 0; i +2 < n; i+= 3)
413  {
414  if(has_materials && material_id != int(materials[i/3]))
415  {
416  material_id= int(materials[i/3]);
417  if(material_id != -1)
418  {
419  fprintf(out, "o %s\n", mesh.materials().name(material_id));
420  fprintf(out, "usemtl %s\n", mesh.materials().name(material_id));
421  }
422  }
423 
424  fprintf(out, "f");
425  for(unsigned k= 0; k < 3; k++)
426  {
427  unsigned id= has_indices ? indices[i+k] +1 : i+k +1;
428  fprintf(out, " %u", id);
430  fprintf(out, "/%u/%u", id, id);
431  else if(has_texcoords)
432  fprintf(out, "/%u", id);
433  else if(has_normals)
434  fprintf(out, "//%u", id);
435  }
436  fprintf(out, "\n");
437  }
438 
439  fclose(out);
440  return 0;
441 }
const std::vector< unsigned int > & material_indices() const
renvoie les indices des matieres des triangles.
Definition: mesh.cpp:287
GLenum primitives() const
renvoie le type de primitives.
Definition: mesh.h:336
const Materials & materials() const
renvoie la description des matieres.
Definition: mesh.cpp:267
const char * name(const int id) const
renvoie le nom de la ieme matiere.
Definition: materials.h:97
bool has_normals(const Hit &hit, const GLTFScene &scene)
verifie la presence des normales par sommet.
bool has_texcoords(const Hit &hit, const GLTFScene &scene)
verifie la presence des coordonnees de texture...

◆ read_materials()

Materials read_materials ( const char *  filename)

charge une description de matieres, utilise par read_mesh.

Definition at line 454 of file wavefront.cpp.

455 {
456  Materials materials;
457 
458  FILE *in= fopen(filename, "rt");
459  if(in == NULL)
460  {
461  printf("[error] loading materials '%s'...\n", filename);
462  return materials;
463  }
464 
465  printf("loading materials '%s'...\n", filename);
466 
467  Material *material= NULL;
468  char tmp[1024];
469  char line_buffer[1024];
470  bool error= true;
471  for(;;)
472  {
473  // charge une ligne du fichier
474  if(fgets(line_buffer, sizeof(line_buffer), in) == NULL)
475  {
476  error= false; // fin du fichier, pas d'erreur detectee
477  break;
478  }
479 
480  // force la fin de la ligne, au cas ou
481  line_buffer[sizeof(line_buffer) -1]= 0;
482 
483  // saute les espaces en debut de ligne
484  char *line= line_buffer;
485  while(*line && isspace(*line))
486  line++;
487 
488  if(line[0] == 'n')
489  {
490  if(sscanf(line, "newmtl %[^\r\n]", tmp) == 1)
491  {
492  int id= materials.insert(Material(Black()), tmp);
493  material= &materials.material(id);
494  }
495  }
496 
497  if(material == nullptr)
498  continue;
499 
500  if(line[0] == 'K')
501  {
502  float r, g, b;
503  if(sscanf(line, "Kd %f %f %f", &r, &g, &b) == 3)
504  material->diffuse= Color(r, g, b);
505  else if(sscanf(line, "Ks %f %f %f", &r, &g, &b) == 3)
506  material->specular= Color(r, g, b);
507  else if(sscanf(line, "Ke %f %f %f", &r, &g, &b) == 3)
508  material->emission= Color(r, g, b);
509  }
510 
511  else if(line[0] == 'N')
512  {
513  float n;
514  if(sscanf(line, "Ns %f", &n) == 1) // Ns, puissance / concentration du reflet, modele blinn phong
515  material->ns= n;
516  }
517 
518  else if(line[0] == 'm')
519  {
520  if(sscanf(line, "map_Kd %[^\r\n]", tmp) == 1)
521  material->diffuse_texture= materials.insert_texture( texture_filename(tmp, pathname(filename)).c_str() );
522 
523  else if(sscanf(line, "map_Ks %[^\r\n]", tmp) == 1)
524  material->specular_texture= materials.insert_texture( texture_filename(tmp, pathname(filename)).c_str() );
525 
526  else if(sscanf(line, "map_Ke %[^\r\n]", tmp) == 1)
527  material->emission_texture= materials.insert_texture( texture_filename(tmp, pathname(filename)).c_str() );
528  }
529 
530  }
531 
532  fclose(in);
533  if(error)
534  printf("[error] parsing line :\n%s\n", line_buffer);
535 
536  return materials;
537 }
Color Black()
utilitaire. renvoie une couleur noire.
Definition: color.cpp:47
representation d'une couleur (rgba) transparente ou opaque.
Definition: color.h:14
int diffuse_texture
indice de la texture de la couleur de base, ou -1.
Definition: materials.h:21
float ns
concentration des reflets, exposant pour les reflets blinn-phong.
Definition: materials.h:20
Color emission
pour une source de lumiere.
Definition: materials.h:19
Color diffuse
couleur diffuse / de base.
Definition: materials.h:17
int emission_texture
indice de la texture, ou -1.
Definition: materials.h:23
Color specular
couleur du reflet.
Definition: materials.h:18
int specular_texture
indice de la texture, ou -1.
Definition: materials.h:22
int insert(const Material &material, const char *name)
ajoute une matiere.
Definition: materials.h:54
const Material & material(const int id) const
renvoie la ieme matiere.
Definition: materials.h:102
int insert_texture(const char *filename)
ajoute une texture / nom du fichier.
Definition: materials.h:68

◆ write_materials()

int write_materials ( const Materials materials,
const char *  filename,
const char *  path = "" 
)

enregistre une description de matieres.

Definition at line 540 of file wavefront.cpp.

541 {
542  FILE *out= fopen(filename, "wt");
543  if(out == NULL)
544  return -1;
545 
546  printf("writing materials '%s'...\n", filename);
547 
548  for(int i= 0; i < materials.count(); i++)
549  {
550  const Material& m= materials.material(i);
551 
552  fprintf(out, "newmtl %s\n", materials.name(i));
553 
554  if(m.diffuse.r + m.diffuse.g + m.diffuse.b)
555  fprintf(out, " Kd %f %f %f\n", m.diffuse.r, m.diffuse.g, m.diffuse.b);
556  if(m.diffuse_texture != -1)
557  fprintf(out, " map_Kd %s\n", relative_filename(materials.filename(m.diffuse_texture), path).c_str());
558 
559  if(m.specular.r + m.specular.g + m.specular.b)
560  fprintf(out, " Ks %f %f %f\n", m.specular.r, m.specular.g, m.specular.b);
561  if(m.specular_texture != -1)
562  fprintf(out, " map_Ks %s\n", relative_filename(materials.filename(m.specular_texture), path).c_str());
563 
564  if(m.specular.power() > 0)
565  {
566  fprintf(out, " Ns %f\n", m.ns);
567  if(m.ns_texture != -1)
568  fprintf(out, " map_Ns %s\n", relative_filename(materials.filename(m.ns_texture), path).c_str());
569  }
570 
571  if(m.emission.power() > 0)
572  {
573  fprintf(out, " Ke %f %f %f\n", m.emission.r, m.emission.g, m.emission.b);
574  if(m.emission_texture != -1)
575  fprintf(out, " map_Ke %s\n", relative_filename(materials.filename(m.emission_texture), path).c_str());
576  }
577 
578  fprintf(out, "\n");
579  }
580 
581  fclose(out);
582  return 0;
583 }
int ns_texture
indice de la texture de reflet, ou -1.
Definition: materials.h:24
int count() const
nombre de matieres.
Definition: materials.h:94
const char * filename(const int id) const
renvoie le nombre de noms de fichiers de textures.
Definition: materials.h:141

◆ read_mesh_fast()

Mesh read_mesh_fast ( const char *  filename)

charge un fichier wavefront .obj et renvoie un mesh compose de triangles non indexes. utiliser glDrawArrays pour l'afficher. a detruire avec Mesh::release( ).

Definition at line 151 of file wavefront_fast.cpp.

152 {
153  FILE *in= fopen(filename, "rb");
154  if(in == NULL)
155  {
156  printf("[error] loading mesh '%s'...\n", filename);
157  return Mesh::error();
158  }
159 
160  Mesh data(GL_TRIANGLES);
161 
162  printf("loading mesh '%s'...\n", filename);
163 
164  std::vector<vec3> positions;
165  std::vector<vec2> texcoords;
166  std::vector<vec3> normals;
167  int material_id= -1;
168 
169  std::vector<int> idp;
170  std::vector<int> idt;
171  std::vector<int> idn;
172 
173  char tmp[1024*64];
174  char line_buffer[1024*64];
175  bool error= true;
176  for(;;)
177  {
178  // charge une ligne du fichier
179  if(fgets(line_buffer, sizeof(line_buffer), in) == NULL)
180  {
181  error= false; // fin du fichier, pas d'erreur detectee
182  break;
183  }
184 
185  // force la fin de la ligne, au cas ou
186  line_buffer[sizeof(line_buffer) -1]= 0;
187 
188  // saute les espaces en debut de ligne
189  const char *line= skip_whitespace(line_buffer);
190  if(line[0] == 'v')
191  {
192  float x, y, z;
193  if(line[1] == ' ') // position x y z
194  {
195  line+= 2;
196  line= parse_float(line, &x);
197  line= parse_float(line, &y);
198  line= parse_float(line, &z);
199 
200  positions.push_back( vec3(x, y, z) );
201  }
202  else if(line[1] == 'n') // normal x y z
203  {
204  line+= 3;
205  line= parse_float(line, &x);
206  line= parse_float(line, &y);
207  line= parse_float(line, &z);
208 
209  normals.push_back( vec3(x, y, z) );
210  }
211  else if(line[1] == 't') // texcoord x y
212  {
213  line+= 3;
214  line= parse_float(line, &x);
215  line= parse_float(line, &y);
216 
217  texcoords.push_back( vec2(x, y) );
218  }
219  }
220 
221  else if(line[0] == 'f') // triangle a b c, les sommets sont numerotes a partir de 1 ou de la fin du tableau (< 0)
222  {
223  idp.clear();
224  idt.clear();
225  idn.clear();
226 
227  line+= 2;
228  while(*line)
229  {
230  idp.push_back(0);
231  idt.push_back(0);
232  idn.push_back(0); // 0: invalid index
233 
234  line= parse_int(line, &idp.back());
235  if(*line == '/')
236  {
237  line++;
238  if(*line != '/')
239  line= parse_int(line, &idt.back());
240 
241  if(*line == '/')
242  {
243  line++;
244  line= parse_int(line, &idn.back());
245  }
246  }
247 
248  while(isspace(*line))
249  line++;
250  }
251 
252  // verifie qu'une matiere est deja definie pour le triangle
253  if(material_id == -1)
254  // sinon affecte une matiere par defaut
255  material_id= data.materials().default_material_index();
256 
257  data.material(material_id);
258 
259  // triangulation de la face (supposee convexe)
260  for(int v= 2; v < int(idp.size()); v++)
261  {
262  int idv[3]= { 0, v -1, v };
263  for(int i= 0; i < 3; i++)
264  {
265  int k= idv[i];
266  int p= (idp[k] < 0) ? (int) positions.size() + idp[k] : idp[k] -1;
267  int t= (idt[k] < 0) ? (int) texcoords.size() + idt[k] : idt[k] -1;
268  int n= (idn[k] < 0) ? (int) normals.size() + idn[k] : idn[k] -1;
269 
270  if(p < 0) break; // error
271  if(t >= 0) data.texcoord(texcoords[t]);
272  if(n >= 0) data.normal(normals[n]);
273  data.vertex(positions[p]);
274  }
275  }
276  }
277 
278  else if(line[0] == 'm')
279  {
280  if(sscanf(line, "mtllib %[^\r\n]", tmp) == 1)
281  {
282  Materials materials= read_materials( normalize_filename(pathname(filename) + tmp).c_str() );
283  // enregistre les matieres dans le mesh
284  data.materials(materials);
285  }
286  }
287 
288  else if(line[0] == 'u')
289  {
290  if(sscanf(line, "usemtl %[^\r\n]", tmp) == 1)
291  material_id= data.materials().find(tmp);
292  }
293  }
294 
295  fclose(in);
296 
297  if(error)
298  printf("[error] loading mesh '%s'...\n%s\n\n", filename, line_buffer);
299  else
300  printf("mesh '%s': %d positions %s %s\n", filename, int(data.positions().size()), data.has_texcoord() ? "texcoord" : "", data.has_normal() ? "normal" : "");
301 
302  return data;
303 }

◆ read_indexed_mesh_fast()

Mesh read_indexed_mesh_fast ( const char *  filename)

charge un fichier wavefront .obj et renvoie un mesh compose de triangles indexes. utiliser glDrawElements pour l'afficher. a detruire avec Mesh::release( ).

Definition at line 329 of file wavefront_fast.cpp.

330 {
331  FILE *in= fopen(filename, "rb");
332  if(in == NULL)
333  {
334  printf("[error] loading indexed mesh '%s'...\n", filename);
335  return Mesh::error();
336  }
337 
338  Mesh data(GL_TRIANGLES);
339 
340  printf("loading indexed mesh '%s'...\n", filename);
341 
342  std::vector<vec3> positions;
343  std::vector<vec2> texcoords;
344  std::vector<vec3> normals;
345  int material_id= -1;
346 
347  std::vector<int> idp;
348  std::vector<int> idt;
349  std::vector<int> idn;
350 
351  std::map<vertex, int> remap;
352 
353  char tmp[1024*64];
354  char line_buffer[1024*64];
355  bool error= true;
356  for(;;)
357  {
358  // charge une ligne du fichier
359  if(fgets(line_buffer, sizeof(line_buffer), in) == NULL)
360  {
361  error= false; // fin du fichier, pas d'erreur detectee
362  break;
363  }
364 
365  // force la fin de la ligne, au cas ou
366  line_buffer[sizeof(line_buffer) -1]= 0;
367 
368  // saute les espaces en debut de ligne
369  const char *line= skip_whitespace(line_buffer);
370  if(line[0] == 'v')
371  {
372  float x, y, z;
373  if(line[1] == ' ') // position x y z
374  {
375  line+= 2;
376  line= parse_float(line, &x);
377  line= parse_float(line, &y);
378  line= parse_float(line, &z);
379 
380  positions.push_back( vec3(x, y, z) );
381  }
382  else if(line[1] == 'n') // normal x y z
383  {
384  line+= 3;
385  line= parse_float(line, &x);
386  line= parse_float(line, &y);
387  line= parse_float(line, &z);
388 
389  normals.push_back( vec3(x, y, z) );
390  }
391  else if(line[1] == 't') // texcoord x y
392  {
393  line+= 3;
394  line= parse_float(line, &x);
395  line= parse_float(line, &y);
396 
397  texcoords.push_back( vec2(x, y) );
398  }
399  }
400 
401  else if(line[0] == 'f') // triangle a b c, les sommets sont numerotes a partir de 1 ou de la fin du tableau (< 0)
402  {
403  idp.clear();
404  idt.clear();
405  idn.clear();
406 
407  line+= 2;
408  while(*line)
409  {
410  idp.push_back(0);
411  idt.push_back(0);
412  idn.push_back(0); // 0: invalid index
413 
414  line= parse_int(line, &idp.back());
415  if(*line == '/')
416  {
417  line++;
418  if(*line != '/')
419  line= parse_int(line, &idt.back());
420 
421  if(*line == '/')
422  {
423  line++;
424  line= parse_int(line, &idn.back());
425  }
426  }
427 
428  while(isspace(*line))
429  line++;
430  }
431 
432  // force une matiere par defaut, si necessaire
433  if(material_id == -1)
434  {
435  material_id= data.materials().default_material_index();
436  printf("usemtl default\n");
437  }
438 
439  data.material(material_id);
440 
441  // triangule la face
442  for(int v= 2; v < int(idp.size()); v++)
443  {
444  int idv[3]= { 0, v -1, v };
445  for(int i= 0; i < 3; i++)
446  {
447  int k= idv[i];
448  // indices des attributs du sommet
449  int p= (idp[k] < 0) ? (int) positions.size() + idp[k] : idp[k] -1;
450  int t= (idt[k] < 0) ? (int) texcoords.size() + idt[k] : idt[k] -1;
451  int n= (idn[k] < 0) ? (int) normals.size() + idn[k] : idn[k] -1;
452 
453  if(p < 0) break; // error
454 
455  // recherche / insere le sommet
456  auto found= remap.insert( std::make_pair(vertex(material_id, p, t, n), int(remap.size())) );
457  if(found.second)
458  {
459  // pas trouve, copie les nouveaux attributs
460  if(t != -1) data.texcoord(texcoords[t]);
461  if(n != -1) data.normal(normals[n]);
462  data.vertex(positions[p]);
463  }
464 
465  // construit l'index buffer
466  data.index(found.first->second);
467  }
468  }
469  }
470 
471  else if(line[0] == 'm')
472  {
473  if(sscanf(line, "mtllib %[^\r\n]", tmp) == 1)
474  {
475  Materials materials= read_materials( normalize_filename(pathname(filename) + tmp).c_str() );
476  // enregistre les matieres dans le mesh
477  data.materials(materials);
478  }
479  }
480 
481  else if(line[0] == 'u')
482  {
483  if(sscanf(line, "usemtl %[^\r\n]", tmp) == 1)
484  material_id= data.materials().find(tmp);
485  }
486  }
487 
488  fclose(in);
489 
490  if(error)
491  printf("[error] loading indexed mesh '%s'...\n%s\n\n", filename, line_buffer);
492  else
493  printf(" %d indices, %d positions %d texcoords %d normals\n",
494  int(data.indices().size()), int(data.positions().size()), int(data.texcoords().size()), int(data.normals().size()));
495 
496  return data;
497 }