gKit2 light
Loading...
Searching...
No Matches
mesh_data.cpp
Go to the documentation of this file.
1
2
3#include <cstdio>
4#include <ctype.h>
5#include <climits>
6#include <cmath>
7
8#include <algorithm>
9#include <map>
10
11#include "files.h"
12#include "material_data.h"
13#include "mesh_data.h"
14
15
16MeshData read_mesh_data( const char *filename )
17{
18 FILE *in= fopen(filename, "rt");
19 if(in == NULL)
20 {
21 printf("[error] loading mesh '%s'...\n", filename);
22 return MeshData();
23 }
24
25 printf("loading mesh '%s'...\n", filename);
26
27 MeshData data;
28 MaterialDataLib materials;
29 int default_material_id= -1;
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 data.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 data.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 data.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 next= 0;
93 if(sscanf(line, " %d/%d/%d %n", &idp.back(), &idt.back(), &idn.back(), &next) == 3)
94 continue;
95 else if(sscanf(line, " %d/%d %n", &idp.back(), &idt.back(), &next) == 2)
96 continue;
97 else if(sscanf(line, " %d//%d %n", &idp.back(), &idn.back(), &next) == 2)
98 continue;
99 else if(sscanf(line, " %d %n", &idp.back(), &next) == 1)
100 continue;
101 else if(next == 0) // fin de ligne
102 break;
103 }
104
105 // force une matiere par defaut, si necessaire
106 if(material_id == -1)
107 {
108 if(default_material_id == -1)
109 {
110 // creer une matiere par defaut
111 default_material_id= data.materials.size();
112 data.materials.push_back( MaterialData() );
113 }
114
115 material_id= default_material_id;
116 printf("usemtl default\n");
117 }
118
119 // triangule la face, construit les triangles 0 1 2, 0 2 3, 0 3 4, etc
120 for(int v= 2; v +1 < (int) idp.size(); v++)
121 {
122 int idv[3]= { 0, v -1, v };
123 for(int i= 0; i < 3; i++)
124 {
125 int k= idv[i];
126 int p= (idp[k] < 0) ? (int) data.positions.size() + idp[k] : idp[k] -1;
127 int t= (idt[k] < 0) ? (int) data.texcoords.size() + idt[k] : idt[k] -1;
128 int n= (idn[k] < 0) ? (int) data.normals.size() + idn[k] : idn[k] -1;
129
130 if(p < 0 || p >= (int) data.positions.size())
131 break; // error
132
133 // conserve les indices du sommet
134 data.position_indices.push_back(p);
135 data.texcoord_indices.push_back(t);
136 data.normal_indices.push_back(n);
137 }
138
139 // matiere du triangle...
140 data.material_indices.push_back(material_id);
141 }
142 }
143
144 else if(line[0] == 'm')
145 {
146 if(sscanf(line, "mtllib %[^\r\n]", tmp) == 1)
147 {
148 materials= read_material_data( std::string(pathname(filename) + tmp).c_str() );
149 data.materials= materials.data;
150 }
151 }
152
153 else if(line[0] == 'u')
154 {
155 if(sscanf(line, "usemtl %[^\r\n]", tmp) == 1)
156 {
157 material_id= -1;
158 for(unsigned int i= 0; i < (unsigned int) materials.names.size(); i++)
159 if(materials.names[i] == tmp)
160 material_id= i;
161
162 if(material_id == -1)
163 {
164 // force une matiere par defaut, si necessaire
165 if(default_material_id == -1)
166 {
167 // creer une matiere par defaut
168 default_material_id= data.materials.size();
169 data.materials.push_back( MaterialData() );
170 }
171
172 material_id= default_material_id;
173 }
174 }
175 }
176 }
177
178 fclose(in);
179
180 if(error)
181 printf("loading mesh '%s'...\n[error]\n%s\n\n", filename, line_buffer);
182
183 printf(" %d positions, %d texcoords, %d normals, %d triangles\n",
184 (int) data.positions.size(), (int) data.texcoords.size(), (int) data.normals.size(), (int) data.material_indices.size());
185
186 return data;
187}
188
189
190static
191std::string normalize_path( std::string file )
192{
193#ifndef WIN32
194 std::replace(file.begin(), file.end(), '\\', '/'); // linux, macos : remplace les \ par /.
195#else
196 std::replace(file.begin(), file.end(), '/', '\\'); // windows : remplace les / par \.
197#endif
198 return file;
199}
200
201
202MaterialDataLib read_material_data( const char *filename )
203{
204 MaterialDataLib materials;
205
206 FILE *in= fopen(filename, "rt");
207 if(in == NULL)
208 {
209 printf("[error] loading materials '%s'...\n", filename);
210 return materials;
211 }
212
213 printf("loading materials '%s'...\n", filename);
214
215 MaterialData *material= NULL;
216 std::string path= pathname(filename);
217
218 char tmp[1024];
219 char line_buffer[1024];
220 bool error= true;
221 for(;;)
222 {
223 // charge une ligne du fichier
224 if(fgets(line_buffer, sizeof(line_buffer), in) == NULL)
225 {
226 error= false; // fin du fichier, pas d'erreur detectee
227 break;
228 }
229
230 // force la fin de la ligne, au cas ou
231 line_buffer[sizeof(line_buffer) -1]= 0;
232
233 // saute les espaces en debut de ligne
234 char *line= line_buffer;
235 while(*line && isspace(*line))
236 line++;
237
238 if(line[0] == 'n')
239 {
240 if(sscanf(line, "newmtl %[^\r\n]", tmp) == 1)
241 {
242 materials.names.push_back( tmp );
243 materials.data.push_back( MaterialData() );
244 material= &materials.data.back();
245 }
246 }
247
248 if(material == NULL)
249 continue;
250
251 if(line[0] == 'K')
252 {
253 float r, g, b;
254 if(sscanf(line, "Kd %f %f %f", &r, &g, &b) == 3)
255 material->diffuse= Color(r, g, b);
256 else if(sscanf(line, "Ks %f %f %f", &r, &g, &b) == 3)
257 material->specular= Color(r, g, b);
258 else if(sscanf(line, "Ke %f %f %f", &r, &g, &b) == 3)
259 material->emission= Color(r, g, b);
260 }
261
262 else if(line[0] == 'N')
263 {
264 float n;
265 if(sscanf(line, "Ns %f", &n) == 1) // Ns, puissance / concentration du reflet, modele blinn phong
266 material->ns= n;
267 }
268
269 else if(line[0] == 'm')
270 {
271 if(sscanf(line, "map_Kd %[^\r\n]", tmp) == 1)
272 material->diffuse_filename= normalize_path(path + tmp);
273
274 if(sscanf(line, "map_Ks %[^\r\n]", tmp) == 1)
275 material->ns_filename= normalize_path(path + tmp);
276
277 //~ if(sscanf(line, "map_bump %[^\r\n]", tmp) == 1)
278 //~ material->normal_filename= tmp;
279 }
280 }
281
282 fclose(in);
283 if(error)
284 printf("[error] parsing line :\n%s\n", line_buffer);
285
286 return materials;
287}
288
289
290void bounds( const MeshData& data, Point& pmin, Point& pmax )
291{
292 if(data.positions.size() < 1)
293 return;
294
295 pmin= Point(data.positions[0]);
296 pmax= pmin;
297
298 for(int i= 1; i < (int) data.positions.size(); i++)
299 {
300 vec3 p= data.positions[i];
301 pmin= Point( std::min(pmin.x, p.x), std::min(pmin.y, p.y), std::min(pmin.z, p.z) );
302 pmax= Point( std::max(pmax.x, p.x), std::max(pmax.y, p.y), std::max(pmax.z, p.z) );
303 }
304}
305
306
307void normals( MeshData& data )
308{
309printf("[mesh] building normals...\n");
310
311 // une normale par position
312 std::vector<Vector> normals(data.positions.size(), Vector());
313 for(int i= 0; i + 2 < (int) data.position_indices.size(); i+= 3)
314 {
315 // positions des sommets du triangle
316 Point a= Point(data.positions[data.position_indices[i]]);
317 Point b= Point(data.positions[data.position_indices[i +1]]);
318 Point c= Point(data.positions[data.position_indices[i +2]]);
319
320 // normale geometrique
321 Vector n= normalize(cross(normalize(b - a), normalize(c - a)));
322 float anglea= std::acos(dot(normalize(b - a), normalize(c - a)));
323 //~ float anglea= std::atan2(length(cross(normalize(b - a), normalize(c - a))), dot(normalize(b - a), normalize(c - a)));
324 //~ if(anglea < 0) anglea+= float(2*M_PI);
325 float angleb= std::acos(dot(normalize(c - b), normalize(a - b)));
326 //~ float angleb= std::atan2(length(cross(normalize(c - b), normalize(a - b))), dot(normalize(c - b), normalize(a - b)));
327 //~ if(angleb < 0) angleb+= float(2*M_PI);
328 float anglec= std::acos(dot(normalize(a - c), normalize(b - c)));
329 //~ float anglec= std::atan2(length(cross(normalize(a - c), normalize(b - c))), dot(normalize(a - c), normalize(b - c)));
330 //~ if(anglec < 0) anglec+= float(2*M_PI);
331
332 // somme la normale sur les sommets du triangle
333 normals[data.position_indices[i]]= normals[data.position_indices[i]] + n * anglea;
334 normals[data.position_indices[i +1]]= normals[data.position_indices[i +1]] + n * angleb;
335 normals[data.position_indices[i +2]]= normals[data.position_indices[i +2]] + n * anglec;
336 }
337
338 // copie
339 data.normals.clear();
340 data.normals.reserve(normals.size());
341 for(int i= 0; i < (int) normals.size(); i++)
342 data.normals.push_back( vec3(normalize(normals[i])) );
343
344 // re-indexe les sommets
345 for(int i= 0; i < (int) data.normal_indices.size(); i++)
346 data.normal_indices[i]= data.position_indices[i];
347}
348
349
351{
352 MeshData mesh;
353 mesh.materials= data.materials;
354 mesh.material_indices= data.material_indices;
355
356 mesh.positions.reserve(data.positions.size());
357 mesh.texcoords.reserve(data.texcoords.size());
358 mesh.normals.reserve(data.normals.size());
359
360 for(int i= 0; i < (int) data.position_indices.size(); i++)
361 {
362 mesh.positions.push_back( data.positions[data.position_indices[i]] );
363 if(data.texcoord_indices[i] >= 0)
364 mesh.texcoords.push_back( data.texcoords[data.texcoord_indices[i]] );
365 if(data.normal_indices[i] >= 0)
366 mesh.normals.push_back( data.normals[data.normal_indices[i]] );
367 }
368
369 data.position_indices.clear();
370 data.texcoord_indices.clear();
371 data.normal_indices.clear();
372
373 return mesh;
374}
375
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
float dot(const Vector &u, const Vector &v)
renvoie le produit scalaire de 2 vecteurs.
Definition vec.cpp:181
Vector normalize(const Vector &v)
renvoie un vecteur unitaire / longueur == 1.
Definition vec.cpp:167
Vector cross(const Vector &u, const Vector &v)
renvoie le produit vectoriel de 2 vecteurs.
Definition vec.cpp:173
charge les textures utiilisees par un ensemble de matieres.
MaterialDataLib read_material_data(const char *filename)
charge un ensemble de matieres texturees.
void normals(MeshData &data)
(re-) calcule les normales des sommets. utiliser avant les reindexations, cf indices() et vertices().
MeshData read_mesh_data(const char *filename)
charge un fichier wavefront .obj et renvoie les donnees.
Definition mesh_data.cpp:16
MeshData vertices(MeshData &data)
construit les sommets. prepare l'affichage openGL, avec glDrawArrays().
void bounds(const MeshData &data, Point &pmin, Point &pmax)
renvoie l'englobant.
representation des donnees d'un fichier wavefront .obj
ensemble de matieres texturees.
Definition mesh_data.h:40
representation d'une couleur (rgba) transparente ou opaque.
Definition color.h:14
representation d'une matiere texturee.
Definition mesh_data.h:16
Color specular
couleur du reflet
Definition mesh_data.h:23
Color emission
pour une source de lumiere
Definition mesh_data.h:25
std::string diffuse_filename
nom de la texture diffuse
Definition mesh_data.h:20
float ns
exposant pour les reflets blinn-phong
Definition mesh_data.h:26
Color diffuse
couleur diffuse
Definition mesh_data.h:17
std::string ns_filename
nom de la texture exposant
Definition mesh_data.h:28
representation d'un point 3d.
Definition vec.h:21
representation d'un vecteur 3d.
Definition vec.h:67
vecteur generique, utilitaire.
Definition vec.h:152
vecteur generique, utilitaire.
Definition vec.h:169