@@ -37,11 +37,11 @@ extern "C" {
3737#include < windows.h>
3838
3939#ifdef max
40- #undef max
40+ #undef max
4141#endif
4242
4343#ifdef min
44- #undef min
44+ #undef min
4545#endif
4646
4747#include < mmsystem.h>
@@ -143,15 +143,15 @@ float eye[3], lookat[3], up[3];
143143
144144GLFWwindow* window;
145145
146- static std::string GetBaseDir (const std::string & filepath) {
146+ static std::string GetBaseDir (const std::string& filepath) {
147147 if (filepath.find_last_of (" /\\ " ) != std::string::npos)
148148 return filepath.substr (0 , filepath.find_last_of (" /\\ " ));
149149 return " " ;
150150}
151151
152- static bool FileExists (const std::string & abs_filename) {
152+ static bool FileExists (const std::string& abs_filename) {
153153 bool ret;
154- FILE * fp = fopen (abs_filename.c_str (), " rb" );
154+ FILE* fp = fopen (abs_filename.c_str (), " rb" );
155155 if (fp) {
156156 ret = true ;
157157 fclose (fp);
@@ -195,10 +195,10 @@ static void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
195195}
196196
197197static bool LoadObjAndConvert (float bmin[3 ], float bmax[3 ],
198- std::vector<DrawObject>* drawObjects,
199- std::vector<tinyobj::material_t >& materials,
200- std::map<std::string, GLuint>& textures,
201- const char * filename) {
198+ std::vector<DrawObject>* drawObjects,
199+ std::vector<tinyobj::material_t >& materials,
200+ std::map<std::string, GLuint>& textures,
201+ const char * filename) {
202202 tinyobj::attrib_t attrib;
203203 std::vector<tinyobj::shape_t > shapes;
204204
@@ -217,8 +217,8 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
217217#endif
218218
219219 std::string err;
220- bool ret =
221- tinyobj::LoadObj (&attrib, &shapes, &materials, &err, filename, base_dir.c_str ());
220+ bool ret = tinyobj::LoadObj (&attrib, &shapes, &materials, &err, filename,
221+ base_dir.c_str ());
222222 if (!err.empty ()) {
223223 std::cerr << err << std::endl;
224224 }
@@ -242,56 +242,62 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
242242 materials.push_back (tinyobj::material_t ());
243243
244244 for (size_t i = 0 ; i < materials.size (); i++) {
245- printf (" material[%d].diffuse_texname = %s\n " , int (i), materials[i].diffuse_texname .c_str ());
245+ printf (" material[%d].diffuse_texname = %s\n " , int (i),
246+ materials[i].diffuse_texname .c_str ());
246247 }
247248
248249 // Load diffuse textures
249250 {
250- for (size_t m = 0 ; m < materials.size (); m++) {
251- tinyobj::material_t * mp = &materials[m];
252-
253- if (mp->diffuse_texname .length () > 0 ) {
254- // Only load the texture if it is not already loaded
255- if (textures.find (mp->diffuse_texname ) == textures.end ()) {
256- GLuint texture_id;
257- int w, h;
258- int comp;
259-
260- std::string texture_filename = mp->diffuse_texname ;
261- if (!FileExists (texture_filename)) {
262- // Append base dir.
263- texture_filename = base_dir + mp->diffuse_texname ;
264- if (!FileExists (texture_filename)) {
265- std::cerr << " Unable to find file: " << mp->diffuse_texname << std::endl;
266- exit ( 1 ) ;
267- }
268- }
269-
270- unsigned char * image = stbi_load (texture_filename. c_str (), &w, &h, &comp, STBI_default);
271- if (! image) {
272- std::cerr << " Unable to load texture: " << texture_filename << std::endl ;
273- exit ( 1 );
274- }
275- std::cout << " Loaded texture: " << texture_filename << " , w = " << w << " , h = " << h << " , comp = " << comp << std::endl;
276-
277- glGenTextures ( 1 , &texture_id);
278- glBindTexture (GL_TEXTURE_2D, texture_id);
279- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) ;
280- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
281- if (comp == 3 ) {
282- glTexImage2D (GL_TEXTURE_2D, 0 , GL_RGB, w, h, 0 , GL_RGB, GL_UNSIGNED_BYTE, image );
283- }
284- else if (comp == 4 ) {
285- glTexImage2D (GL_TEXTURE_2D, 0 , GL_RGBA, w, h, 0 , GL_RGBA, GL_UNSIGNED_BYTE, image);
286- } else {
287- assert ( 0 ); // TODO
288- }
289- glBindTexture (GL_TEXTURE_2D , 0 );
290- stbi_image_free ( image);
291- textures. insert ( std::make_pair (mp-> diffuse_texname , texture_id));
292- }
251+ for (size_t m = 0 ; m < materials.size (); m++) {
252+ tinyobj::material_t * mp = &materials[m];
253+
254+ if (mp->diffuse_texname .length () > 0 ) {
255+ // Only load the texture if it is not already loaded
256+ if (textures.find (mp->diffuse_texname ) == textures.end ()) {
257+ GLuint texture_id;
258+ int w, h;
259+ int comp;
260+
261+ std::string texture_filename = mp->diffuse_texname ;
262+ if (!FileExists (texture_filename)) {
263+ // Append base dir.
264+ texture_filename = base_dir + mp->diffuse_texname ;
265+ if (!FileExists (texture_filename)) {
266+ std::cerr << " Unable to find file: " << mp->diffuse_texname
267+ << std::endl ;
268+ exit ( 1 );
269+ }
270+ }
271+
272+ unsigned char * image =
273+ stbi_load (texture_filename. c_str (), &w, &h, &comp, STBI_default) ;
274+ if (!image) {
275+ std::cerr << " Unable to load texture: " << texture_filename
276+ << std::endl;
277+ exit ( 1 );
278+ }
279+ std::cout << " Loaded texture: " << texture_filename << " , w = " << w
280+ << " , h = " << h << " , comp = " << comp << std::endl ;
281+
282+ glGenTextures ( 1 , &texture_id);
283+ glBindTexture (GL_TEXTURE_2D, texture_id );
284+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
285+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
286+ if (comp == 3 ) {
287+ glTexImage2D (GL_TEXTURE_2D, 0 , GL_RGB, w, h, 0 , GL_RGB,
288+ GL_UNSIGNED_BYTE, image);
289+ } else if (comp == 4 ) {
290+ glTexImage2D (GL_TEXTURE_2D, 0 , GL_RGBA, w, h , 0 , GL_RGBA,
291+ GL_UNSIGNED_BYTE, image);
292+ } else {
293+ assert ( 0 ); // TODO
293294 }
295+ glBindTexture (GL_TEXTURE_2D, 0 );
296+ stbi_image_free (image);
297+ textures.insert (std::make_pair (mp->diffuse_texname , texture_id));
298+ }
294299 }
300+ }
295301 }
296302
297303 bmin[0 ] = bmin[1 ] = bmin[2 ] = std::numeric_limits<float >::max ();
@@ -305,26 +311,43 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
305311 tinyobj::index_t idx0 = shapes[s].mesh .indices [3 * f + 0 ];
306312 tinyobj::index_t idx1 = shapes[s].mesh .indices [3 * f + 1 ];
307313 tinyobj::index_t idx2 = shapes[s].mesh .indices [3 * f + 2 ];
308-
314+
309315 int current_material_id = shapes[s].mesh .material_ids [f];
310316
311- if ((current_material_id < 0 ) || (current_material_id >= static_cast <int >(materials.size ()))) {
317+ if ((current_material_id < 0 ) ||
318+ (current_material_id >= static_cast <int >(materials.size ()))) {
312319 // Invaid material ID. Use default material.
313- current_material_id = materials.size () - 1 ; // Default material is added to the last item in `materials`.
320+ current_material_id =
321+ materials.size () -
322+ 1 ; // Default material is added to the last item in `materials`.
314323 }
315- // if (current_material_id >= materials.size()) {
316- // std::cerr << "Invalid material index: " << current_material_id << std::endl;
324+ // if (current_material_id >= materials.size()) {
325+ // std::cerr << "Invalid material index: " << current_material_id <<
326+ // std::endl;
317327 // }
318328 //
319329 float diffuse[3 ];
320330 for (size_t i = 0 ; i < 3 ; i++) {
321- diffuse[i] = materials[current_material_id].diffuse [i];
331+ diffuse[i] = materials[current_material_id].diffuse [i];
322332 }
323333 float tc[3 ][2 ];
324334 if (attrib.texcoords .size () > 0 ) {
325- assert (attrib.texcoords .size () > 2 * idx0.texcoord_index + 1 );
326- assert (attrib.texcoords .size () > 2 * idx1.texcoord_index + 1 );
327- assert (attrib.texcoords .size () > 2 * idx2.texcoord_index + 1 );
335+ if ((idx0.texcoord_index < 0 ) || (idx1.texcoord_index < 0 ) ||
336+ (idx2.texcoord_index < 0 )) {
337+ // face does not contain valid uv index.
338+ tc[0 ][0 ] = 0 .0f ;
339+ tc[0 ][1 ] = 0 .0f ;
340+ tc[1 ][0 ] = 0 .0f ;
341+ tc[1 ][1 ] = 0 .0f ;
342+ tc[2 ][0 ] = 0 .0f ;
343+ tc[2 ][1 ] = 0 .0f ;
344+ } else {
345+ assert (attrib.texcoords .size () >
346+ size_t (2 * idx0.texcoord_index + 1 ));
347+ assert (attrib.texcoords .size () >
348+ size_t (2 * idx1.texcoord_index + 1 ));
349+ assert (attrib.texcoords .size () >
350+ size_t (2 * idx2.texcoord_index + 1 ));
328351
329352 // Flip Y coord.
330353 tc[0 ][0 ] = attrib.texcoords [2 * idx0.texcoord_index ];
@@ -333,13 +356,14 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
333356 tc[1 ][1 ] = 1 .0f - attrib.texcoords [2 * idx1.texcoord_index + 1 ];
334357 tc[2 ][0 ] = attrib.texcoords [2 * idx2.texcoord_index ];
335358 tc[2 ][1 ] = 1 .0f - attrib.texcoords [2 * idx2.texcoord_index + 1 ];
359+ }
336360 } else {
337- tc[0 ][0 ] = 0 .0f ;
338- tc[0 ][1 ] = 0 .0f ;
339- tc[1 ][0 ] = 0 .0f ;
340- tc[1 ][1 ] = 0 .0f ;
341- tc[2 ][0 ] = 0 .0f ;
342- tc[2 ][1 ] = 0 .0f ;
361+ tc[0 ][0 ] = 0 .0f ;
362+ tc[0 ][1 ] = 0 .0f ;
363+ tc[1 ][0 ] = 0 .0f ;
364+ tc[1 ][1 ] = 0 .0f ;
365+ tc[2 ][0 ] = 0 .0f ;
366+ tc[2 ][1 ] = 0 .0f ;
343367 }
344368
345369 float v[3 ][3 ];
@@ -363,27 +387,40 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
363387 }
364388
365389 float n[3 ][3 ];
366- if (attrib.normals .size () > 0 ) {
367- int f0 = idx0.normal_index ;
368- int f1 = idx1.normal_index ;
369- int f2 = idx2.normal_index ;
370- assert (f0 >= 0 );
371- assert (f1 >= 0 );
372- assert (f2 >= 0 );
373- for (int k = 0 ; k < 3 ; k++) {
374- n[0 ][k] = attrib.normals [3 * f0 + k];
375- n[1 ][k] = attrib.normals [3 * f1 + k];
376- n[2 ][k] = attrib.normals [3 * f2 + k];
390+ {
391+ bool invalid_normal_index = false ;
392+ if (attrib.normals .size () > 0 ) {
393+ int nf0 = idx0.normal_index ;
394+ int nf1 = idx1.normal_index ;
395+ int nf2 = idx2.normal_index ;
396+
397+ if ((nf0 < 0 ) || (nf1 < 0 ) || (nf2 < 0 )) {
398+ // normal index is missing from this face.
399+ invalid_normal_index = true ;
400+ } else {
401+ for (int k = 0 ; k < 3 ; k++) {
402+ assert (size_t (3 * nf0 + k) < attrib.normals .size ());
403+ assert (size_t (3 * nf1 + k) < attrib.normals .size ());
404+ assert (size_t (3 * nf2 + k) < attrib.normals .size ());
405+ n[0 ][k] = attrib.normals [3 * nf0 + k];
406+ n[1 ][k] = attrib.normals [3 * nf1 + k];
407+ n[2 ][k] = attrib.normals [3 * nf2 + k];
408+ }
409+ }
410+ } else {
411+ invalid_normal_index = true ;
412+ }
413+
414+ if (invalid_normal_index) {
415+ // compute geometric normal
416+ CalcNormal (n[0 ], v[0 ], v[1 ], v[2 ]);
417+ n[1 ][0 ] = n[0 ][0 ];
418+ n[1 ][1 ] = n[0 ][1 ];
419+ n[1 ][2 ] = n[0 ][2 ];
420+ n[2 ][0 ] = n[0 ][0 ];
421+ n[2 ][1 ] = n[0 ][1 ];
422+ n[2 ][2 ] = n[0 ][2 ];
377423 }
378- } else {
379- // compute geometric normal
380- CalcNormal (n[0 ], v[0 ], v[1 ], v[2 ]);
381- n[1 ][0 ] = n[0 ][0 ];
382- n[1 ][1 ] = n[0 ][1 ];
383- n[1 ][2 ] = n[0 ][2 ];
384- n[2 ][0 ] = n[0 ][0 ];
385- n[2 ][1 ] = n[0 ][1 ];
386- n[2 ][2 ] = n[0 ][2 ];
387424 }
388425
389426 for (int k = 0 ; k < 3 ; k++) {
@@ -396,11 +433,9 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
396433 // Combine normal and diffuse to get color.
397434 float normal_factor = 0.2 ;
398435 float diffuse_factor = 1 - normal_factor;
399- float c[3 ] = {
400- n[k][0 ] * normal_factor + diffuse[0 ] * diffuse_factor,
401- n[k][1 ] * normal_factor + diffuse[1 ] * diffuse_factor,
402- n[k][2 ] * normal_factor + diffuse[2 ] * diffuse_factor
403- };
436+ float c[3 ] = {n[k][0 ] * normal_factor + diffuse[0 ] * diffuse_factor,
437+ n[k][1 ] * normal_factor + diffuse[1 ] * diffuse_factor,
438+ n[k][2 ] * normal_factor + diffuse[2 ] * diffuse_factor};
404439 float len2 = c[0 ] * c[0 ] + c[1 ] * c[1 ] + c[2 ] * c[2 ];
405440 if (len2 > 0 .0f ) {
406441 float len = sqrtf (len2);
@@ -412,7 +447,7 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
412447 buffer.push_back (c[0 ] * 0.5 + 0.5 );
413448 buffer.push_back (c[1 ] * 0.5 + 0.5 );
414449 buffer.push_back (c[2 ] * 0.5 + 0.5 );
415-
450+
416451 buffer.push_back (tc[k][0 ]);
417452 buffer.push_back (tc[k][1 ]);
418453 }
@@ -422,19 +457,22 @@ static bool LoadObjAndConvert(float bmin[3], float bmax[3],
422457 o.numTriangles = 0 ;
423458
424459 // OpenGL viewer does not support texturing with per-face material.
425- if (shapes[s].mesh .material_ids .size () > 0 && shapes[s].mesh .material_ids .size () > s) {
426- o.material_id = shapes[s].mesh .material_ids [0 ]; // use the material ID of the first face.
460+ if (shapes[s].mesh .material_ids .size () > 0 &&
461+ shapes[s].mesh .material_ids .size () > s) {
462+ o.material_id = shapes[s].mesh .material_ids [0 ]; // use the material ID
463+ // of the first face.
427464 } else {
428- o.material_id = materials.size () - 1 ; // = ID for default material.
465+ o.material_id = materials.size () - 1 ; // = ID for default material.
429466 }
430467 printf (" shape[%d] material_id %d\n " , int (s), int (o.material_id ));
431-
468+
432469 if (buffer.size () > 0 ) {
433470 glGenBuffers (1 , &o.vb_id );
434471 glBindBuffer (GL_ARRAY_BUFFER, o.vb_id );
435- glBufferData (GL_ARRAY_BUFFER, buffer.size () * sizeof (float ), &buffer.at (0 ),
436- GL_STATIC_DRAW);
437- o.numTriangles = buffer.size () / (3 + 3 + 3 + 2 ) / 3 ; // 3:vtx, 3:normal, 3:col, 2:texcoord
472+ glBufferData (GL_ARRAY_BUFFER, buffer.size () * sizeof (float ),
473+ &buffer.at (0 ), GL_STATIC_DRAW);
474+ o.numTriangles = buffer.size () / (3 + 3 + 3 + 2 ) /
475+ 3 ; // 3:vtx, 3:normal, 3:col, 2:texcoord
438476
439477 printf (" shape[%d] # of triangles = %d\n " , static_cast <int >(s),
440478 o.numTriangles );
@@ -467,7 +505,7 @@ static void reshapeFunc(GLFWwindow* window, int w, int h) {
467505}
468506
469507static void keyboardFunc (GLFWwindow* window, int key, int scancode, int action,
470- int mods) {
508+ int mods) {
471509 (void )window;
472510 (void )scancode;
473511 (void )mods;
@@ -549,7 +587,9 @@ static void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y) {
549587 prevMouseY = mouse_y;
550588}
551589
552- static void Draw (const std::vector<DrawObject>& drawObjects, std::vector<tinyobj::material_t >& materials, std::map<std::string, GLuint>& textures) {
590+ static void Draw (const std::vector<DrawObject>& drawObjects,
591+ std::vector<tinyobj::material_t >& materials,
592+ std::map<std::string, GLuint>& textures) {
553593 glPolygonMode (GL_FRONT, GL_FILL);
554594 glPolygonMode (GL_BACK, GL_FILL);
555595
@@ -572,7 +612,7 @@ static void Draw(const std::vector<DrawObject>& drawObjects, std::vector<tinyobj
572612 if ((o.material_id < materials.size ())) {
573613 std::string diffuse_texname = materials[o.material_id ].diffuse_texname ;
574614 if (textures.find (diffuse_texname) != textures.end ()) {
575- glBindTexture (GL_TEXTURE_2D, textures[diffuse_texname]);
615+ glBindTexture (GL_TEXTURE_2D, textures[diffuse_texname]);
576616 }
577617 }
578618 glVertexPointer (3 , GL_FLOAT, stride, (const void *)0 );
@@ -668,7 +708,8 @@ int main(int argc, char** argv) {
668708 float bmin[3 ], bmax[3 ];
669709 std::vector<tinyobj::material_t > materials;
670710 std::map<std::string, GLuint> textures;
671- if (false == LoadObjAndConvert (bmin, bmax, &gDrawObjects , materials, textures, argv[1 ])) {
711+ if (false == LoadObjAndConvert (bmin, bmax, &gDrawObjects , materials, textures,
712+ argv[1 ])) {
672713 return -1 ;
673714 }
674715
0 commit comments