1 #include "obj-loader.h"
2 #include "../../nanort.h"  // for float3
3 
4 #define TINYOBJLOADER_IMPLEMENTATION
5 #include "tiny_obj_loader.h"
6 
7 #ifdef __clang__
8 #pragma clang diagnostic push
9 #pragma clang diagnostic ignored "-Wold-style-cast"
10 #pragma clang diagnostic ignored "-Wreserved-id-macro"
11 #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
12 #pragma clang diagnostic ignored "-Wcast-align"
13 #pragma clang diagnostic ignored "-Wpadded"
14 #pragma clang diagnostic ignored "-Wold-style-cast"
15 #pragma clang diagnostic ignored "-Wsign-conversion"
16 #pragma clang diagnostic ignored "-Wvariadic-macros"
17 #pragma clang diagnostic ignored "-Wc++11-extensions"
18 #pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
19 #pragma clang diagnostic ignored "-Wimplicit-fallthrough"
20 #if __has_warning("-Wdouble-promotion")
21 #pragma clang diagnostic ignored "-Wdouble-promotion"
22 #endif
23 #if __has_warning("-Wcomma")
24 #pragma clang diagnostic ignored "-Wcomma"
25 #endif
26 #if __has_warning("-Wcast-qual")
27 #pragma clang diagnostic ignored "-Wcast-qual"
28 #endif
29 #endif
30 
31 #define STB_IMAGE_IMPLEMENTATION
32 #include "stb_image.h"
33 
34 #ifdef __clang__
35 #pragma clang diagnostic pop
36 #endif
37 
38 #include <iostream>
39 
40 #ifdef NANOSG_USE_CXX11
41 #include <unordered_map>
42 #else
43 #include <map>
44 #endif
45 
46 #define USE_TEX_CACHE 1
47 
48 namespace example {
49 
50 typedef nanort::real3<float> float3;
51 
52 #ifdef __clang__
53 #pragma clang diagnostic push
54 #pragma clang diagnostic ignored "-Wexit-time-destructors"
55 #pragma clang diagnostic ignored "-Wglobal-constructors"
56 #endif
57 
58 // TODO(LTE): Remove global static definition.
59 #ifdef NANOSG_USE_CXX11
60 static std::unordered_map<std::string, int> hashed_tex;
61 #else
62 static std::map<std::string, int> hashed_tex;
63 #endif
64 
65 #ifdef __clang__
66 #pragma clang diagnostic pop
67 #endif
68 
CalcNormal(float3 & N,float3 v0,float3 v1,float3 v2)69 inline void CalcNormal(float3 &N, float3 v0, float3 v1, float3 v2) {
70   float3 v10 = v1 - v0;
71   float3 v20 = v2 - v0;
72 
73   N = vcross(v10, v20); // CCW
74   N = vnormalize(N);
75 }
76 
GetBaseDir(const std::string & filepath)77 static std::string GetBaseDir(const std::string &filepath) {
78   if (filepath.find_last_of("/\\") != std::string::npos)
79     return filepath.substr(0, filepath.find_last_of("/\\"));
80   return "";
81 }
82 
LoadTexture(const std::string & filename,std::vector<Texture> * textures)83 static int LoadTexture(const std::string &filename,
84                        std::vector<Texture> *textures) {
85   int idx;
86 
87   if (filename.empty()) return -1;
88 
89   std::cout << "  Loading texture : " << filename << std::endl;
90   Texture texture;
91 
92   // tigra: find in cache. get index
93   if (USE_TEX_CACHE) {
94     if (hashed_tex.find(filename) != hashed_tex.end()) {
95       puts("from cache");
96       return hashed_tex[filename];
97     }
98   }
99 
100   int w, h, n;
101   unsigned char *data = stbi_load(filename.c_str(), &w, &h, &n, 0);
102   if (data) {
103     texture.width = w;
104     texture.height = h;
105     texture.components = n;
106 
107     size_t n_elem = size_t(w * h * n);
108     texture.image = new unsigned char[n_elem];
109     for (size_t i = 0; i < n_elem; i++) {
110       texture.image[i] = data[i];
111     }
112 
113     free(data);
114 
115     textures->push_back(texture);
116 
117     idx = int(textures->size()) - 1;
118 
119     // tigra: store index to cache
120     if (USE_TEX_CACHE) {
121       hashed_tex[filename] = idx;
122     }
123 
124     return idx;
125   }
126 
127   std::cout << "  Failed to load : " << filename << std::endl;
128   return -1;
129 }
130 
ComputeBoundingBoxOfMesh(float bmin[3],float bmax[3],const example::Mesh<float> & mesh)131 static void ComputeBoundingBoxOfMesh(float bmin[3], float bmax[3],
132                                      const example::Mesh<float> &mesh) {
133   bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
134   bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
135 
136   for (size_t i = 0; i < mesh.vertices.size() / 3; i++) {
137     bmin[0] = std::min(bmin[0], mesh.vertices[3 * i + 0]);
138     bmin[1] = std::min(bmin[1], mesh.vertices[3 * i + 1]);
139     bmin[2] = std::min(bmin[1], mesh.vertices[3 * i + 2]);
140 
141     bmax[0] = std::max(bmax[0], mesh.vertices[3 * i + 0]);
142     bmax[1] = std::max(bmax[1], mesh.vertices[3 * i + 1]);
143     bmax[2] = std::max(bmax[2], mesh.vertices[3 * i + 2]);
144   }
145 }
146 
LoadObj(const std::string & filename,float scale,std::vector<Mesh<float>> * meshes,std::vector<Material> * out_materials,std::vector<Texture> * out_textures)147 bool LoadObj(const std::string &filename, float scale,
148              std::vector<Mesh<float> > *meshes,
149              std::vector<Material> *out_materials,
150              std::vector<Texture> *out_textures) {
151   tinyobj::attrib_t attrib;
152   std::vector<tinyobj::shape_t> shapes;
153   std::vector<tinyobj::material_t> materials;
154   std::string err;
155 
156   std::string basedir = GetBaseDir(filename) + "/";
157   const char *basepath = (basedir.compare("/") == 0) ? NULL : basedir.c_str();
158 
159   // auto t_start = std::chrono::system_clock::now();
160 
161   bool ret =
162       tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename.c_str(),
163                        basepath, /* triangulate */ true);
164 
165   // auto t_end = std::chrono::system_clock::now();
166   // std::chrono::duration<double, std::milli> ms = t_end - t_start;
167 
168   if (!err.empty()) {
169     std::cerr << err << std::endl;
170   }
171 
172   if (!ret) {
173     return false;
174   }
175 
176   // std::cout << "[LoadOBJ] Parse time : " << ms.count() << " [msecs]"
177   //          << std::endl;
178 
179   std::cout << "[LoadOBJ] # of shapes in .obj : " << shapes.size() << std::endl;
180   std::cout << "[LoadOBJ] # of materials in .obj : " << materials.size()
181             << std::endl;
182 
183   {
184     size_t total_num_vertices = 0;
185     size_t total_num_faces = 0;
186 
187     total_num_vertices = attrib.vertices.size() / 3;
188     std::cout << "  vertices : " << attrib.vertices.size() / 3 << std::endl;
189 
190     for (size_t i = 0; i < shapes.size(); i++) {
191       std::cout << "  shape[" << i << "].name : " << shapes[i].name
192                 << std::endl;
193       std::cout << "  shape[" << i
194                 << "].indices : " << shapes[i].mesh.indices.size() << std::endl;
195       assert((shapes[i].mesh.indices.size() % 3) == 0);
196 
197       total_num_faces += shapes[i].mesh.indices.size() / 3;
198 
199       // tigra: empty name convert to _id
200       if (shapes[i].name.length() == 0) {
201 #ifdef NANOSG_USE_CXX11
202         shapes[i].name = "_" + std::to_string(i);
203 #else
204         std::stringstream ss;
205         ss << i;
206         shapes[i].name = "_" + ss.str();
207 #endif
208         std::cout << "  EMPTY shape[" << i << "].name, new : " << shapes[i].name
209                   << std::endl;
210       }
211     }
212     std::cout << "[LoadOBJ] # of faces: " << total_num_faces << std::endl;
213     std::cout << "[LoadOBJ] # of vertices: " << total_num_vertices << std::endl;
214   }
215 
216   // TODO(LTE): Implement tangents and binormals
217 
218   for (size_t i = 0; i < shapes.size(); i++) {
219     Mesh<float> mesh(/* stride */ sizeof(float) * 3);
220 
221     mesh.name = shapes[i].name;
222 
223     const size_t num_faces = shapes[i].mesh.indices.size() / 3;
224     mesh.faces.resize(num_faces * 3);
225     mesh.material_ids.resize(num_faces);
226     mesh.facevarying_normals.resize(num_faces * 3 * 3);
227     mesh.facevarying_uvs.resize(num_faces * 3 * 2);
228     mesh.vertices.resize(num_faces * 3 * 3);
229 
230     for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
231       // reorder vertices. may create duplicated vertices.
232       size_t f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index);
233       size_t f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index);
234       size_t f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index);
235 
236       mesh.vertices[9 * f + 0] = scale * attrib.vertices[3 * f0 + 0];
237       mesh.vertices[9 * f + 1] = scale * attrib.vertices[3 * f0 + 1];
238       mesh.vertices[9 * f + 2] = scale * attrib.vertices[3 * f0 + 2];
239 
240       mesh.vertices[9 * f + 3] = scale * attrib.vertices[3 * f1 + 0];
241       mesh.vertices[9 * f + 4] = scale * attrib.vertices[3 * f1 + 1];
242       mesh.vertices[9 * f + 5] = scale * attrib.vertices[3 * f1 + 2];
243 
244       mesh.vertices[9 * f + 6] = scale * attrib.vertices[3 * f2 + 0];
245       mesh.vertices[9 * f + 7] = scale * attrib.vertices[3 * f2 + 1];
246       mesh.vertices[9 * f + 8] = scale * attrib.vertices[3 * f2 + 2];
247 
248       mesh.faces[3 * f + 0] = static_cast<unsigned int>(3 * f + 0);
249       mesh.faces[3 * f + 1] = static_cast<unsigned int>(3 * f + 1);
250       mesh.faces[3 * f + 2] = static_cast<unsigned int>(3 * f + 2);
251 
252       mesh.material_ids[f] =
253           static_cast<unsigned int>(shapes[i].mesh.material_ids[f]);
254     }
255 
256     if (attrib.normals.size() > 0) {
257       for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
258         size_t f0, f1, f2;
259 
260         f0 = size_t(shapes[i].mesh.indices[3 * f + 0].normal_index);
261         f1 = size_t(shapes[i].mesh.indices[3 * f + 1].normal_index);
262         f2 = size_t(shapes[i].mesh.indices[3 * f + 2].normal_index);
263 
264         if (f0 > 0 && f1 > 0 && f2 > 0) {
265           float n0[3], n1[3], n2[3];
266 
267           n0[0] = attrib.normals[3 * f0 + 0];
268           n0[1] = attrib.normals[3 * f0 + 1];
269           n0[2] = attrib.normals[3 * f0 + 2];
270 
271           n1[0] = attrib.normals[3 * f1 + 0];
272           n1[1] = attrib.normals[3 * f1 + 1];
273           n1[2] = attrib.normals[3 * f1 + 2];
274 
275           n2[0] = attrib.normals[3 * f2 + 0];
276           n2[1] = attrib.normals[3 * f2 + 1];
277           n2[2] = attrib.normals[3 * f2 + 2];
278 
279           mesh.facevarying_normals[3 * (3 * f + 0) + 0] = n0[0];
280           mesh.facevarying_normals[3 * (3 * f + 0) + 1] = n0[1];
281           mesh.facevarying_normals[3 * (3 * f + 0) + 2] = n0[2];
282 
283           mesh.facevarying_normals[3 * (3 * f + 1) + 0] = n1[0];
284           mesh.facevarying_normals[3 * (3 * f + 1) + 1] = n1[1];
285           mesh.facevarying_normals[3 * (3 * f + 1) + 2] = n1[2];
286 
287           mesh.facevarying_normals[3 * (3 * f + 2) + 0] = n2[0];
288           mesh.facevarying_normals[3 * (3 * f + 2) + 1] = n2[1];
289           mesh.facevarying_normals[3 * (3 * f + 2) + 2] = n2[2];
290         } else {  // face contains invalid normal index. calc geometric normal.
291           f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index);
292           f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index);
293           f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index);
294 
295           float3 v0, v1, v2;
296 
297           v0[0] = attrib.vertices[3 * f0 + 0];
298           v0[1] = attrib.vertices[3 * f0 + 1];
299           v0[2] = attrib.vertices[3 * f0 + 2];
300 
301           v1[0] = attrib.vertices[3 * f1 + 0];
302           v1[1] = attrib.vertices[3 * f1 + 1];
303           v1[2] = attrib.vertices[3 * f1 + 2];
304 
305           v2[0] = attrib.vertices[3 * f2 + 0];
306           v2[1] = attrib.vertices[3 * f2 + 1];
307           v2[2] = attrib.vertices[3 * f2 + 2];
308 
309           float3 N;
310           CalcNormal(N, v0, v1, v2);
311 
312           mesh.facevarying_normals[3 * (3 * f + 0) + 0] = N[0];
313           mesh.facevarying_normals[3 * (3 * f + 0) + 1] = N[1];
314           mesh.facevarying_normals[3 * (3 * f + 0) + 2] = N[2];
315 
316           mesh.facevarying_normals[3 * (3 * f + 1) + 0] = N[0];
317           mesh.facevarying_normals[3 * (3 * f + 1) + 1] = N[1];
318           mesh.facevarying_normals[3 * (3 * f + 1) + 2] = N[2];
319 
320           mesh.facevarying_normals[3 * (3 * f + 2) + 0] = N[0];
321           mesh.facevarying_normals[3 * (3 * f + 2) + 1] = N[1];
322           mesh.facevarying_normals[3 * (3 * f + 2) + 2] = N[2];
323         }
324       }
325     } else {
326       // calc geometric normal
327       for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
328         size_t f0, f1, f2;
329 
330         f0 = size_t(shapes[i].mesh.indices[3 * f + 0].vertex_index);
331         f1 = size_t(shapes[i].mesh.indices[3 * f + 1].vertex_index);
332         f2 = size_t(shapes[i].mesh.indices[3 * f + 2].vertex_index);
333 
334         float3 v0, v1, v2;
335 
336         v0[0] = attrib.vertices[3 * f0 + 0];
337         v0[1] = attrib.vertices[3 * f0 + 1];
338         v0[2] = attrib.vertices[3 * f0 + 2];
339 
340         v1[0] = attrib.vertices[3 * f1 + 0];
341         v1[1] = attrib.vertices[3 * f1 + 1];
342         v1[2] = attrib.vertices[3 * f1 + 2];
343 
344         v2[0] = attrib.vertices[3 * f2 + 0];
345         v2[1] = attrib.vertices[3 * f2 + 1];
346         v2[2] = attrib.vertices[3 * f2 + 2];
347 
348         float3 N;
349         CalcNormal(N, v0, v1, v2);
350 
351         mesh.facevarying_normals[3 * (3 * f + 0) + 0] = N[0];
352         mesh.facevarying_normals[3 * (3 * f + 0) + 1] = N[1];
353         mesh.facevarying_normals[3 * (3 * f + 0) + 2] = N[2];
354 
355         mesh.facevarying_normals[3 * (3 * f + 1) + 0] = N[0];
356         mesh.facevarying_normals[3 * (3 * f + 1) + 1] = N[1];
357         mesh.facevarying_normals[3 * (3 * f + 1) + 2] = N[2];
358 
359         mesh.facevarying_normals[3 * (3 * f + 2) + 0] = N[0];
360         mesh.facevarying_normals[3 * (3 * f + 2) + 1] = N[1];
361         mesh.facevarying_normals[3 * (3 * f + 2) + 2] = N[2];
362       }
363     }
364 
365     if (attrib.texcoords.size() > 0) {
366       for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
367         size_t f0, f1, f2;
368 
369         f0 = size_t(shapes[i].mesh.indices[3 * f + 0].texcoord_index);
370         f1 = size_t(shapes[i].mesh.indices[3 * f + 1].texcoord_index);
371         f2 = size_t(shapes[i].mesh.indices[3 * f + 2].texcoord_index);
372 
373         if (f0 > 0 && f1 > 0 && f2 > 0) {
374           float3 n0, n1, n2;
375 
376           n0[0] = attrib.texcoords[2 * f0 + 0];
377           n0[1] = attrib.texcoords[2 * f0 + 1];
378 
379           n1[0] = attrib.texcoords[2 * f1 + 0];
380           n1[1] = attrib.texcoords[2 * f1 + 1];
381 
382           n2[0] = attrib.texcoords[2 * f2 + 0];
383           n2[1] = attrib.texcoords[2 * f2 + 1];
384 
385           mesh.facevarying_uvs[2 * (3 * f + 0) + 0] = n0[0];
386           mesh.facevarying_uvs[2 * (3 * f + 0) + 1] = n0[1];
387 
388           mesh.facevarying_uvs[2 * (3 * f + 1) + 0] = n1[0];
389           mesh.facevarying_uvs[2 * (3 * f + 1) + 1] = n1[1];
390 
391           mesh.facevarying_uvs[2 * (3 * f + 2) + 0] = n2[0];
392           mesh.facevarying_uvs[2 * (3 * f + 2) + 1] = n2[1];
393         }
394       }
395     }
396 
397     // Compute pivot translation and add offset to the vertices.
398     float bmin[3], bmax[3];
399     ComputeBoundingBoxOfMesh(bmin, bmax, mesh);
400 
401     float bcenter[3];
402     bcenter[0] = 0.5f * (bmax[0] - bmin[0]) + bmin[0];
403     bcenter[1] = 0.5f * (bmax[1] - bmin[1]) + bmin[1];
404     bcenter[2] = 0.5f * (bmax[2] - bmin[2]) + bmin[2];
405 
406     for (size_t v = 0; v < mesh.vertices.size() / 3; v++) {
407       mesh.vertices[3 * v + 0] -= bcenter[0];
408       mesh.vertices[3 * v + 1] -= bcenter[1];
409       mesh.vertices[3 * v + 2] -= bcenter[2];
410     }
411 
412     mesh.pivot_xform[0][0] = 1.0f;
413     mesh.pivot_xform[0][1] = 0.0f;
414     mesh.pivot_xform[0][2] = 0.0f;
415     mesh.pivot_xform[0][3] = 0.0f;
416 
417     mesh.pivot_xform[1][0] = 0.0f;
418     mesh.pivot_xform[1][1] = 1.0f;
419     mesh.pivot_xform[1][2] = 0.0f;
420     mesh.pivot_xform[1][3] = 0.0f;
421 
422     mesh.pivot_xform[2][0] = 0.0f;
423     mesh.pivot_xform[2][1] = 0.0f;
424     mesh.pivot_xform[2][2] = 1.0f;
425     mesh.pivot_xform[2][3] = 0.0f;
426 
427     mesh.pivot_xform[3][0] = bcenter[0];
428     mesh.pivot_xform[3][1] = bcenter[1];
429     mesh.pivot_xform[3][2] = bcenter[2];
430     mesh.pivot_xform[3][3] = 1.0f;
431 
432     meshes->push_back(mesh);
433   }
434 
435   // material_t -> Material and Texture
436   out_materials->resize(materials.size());
437   out_textures->resize(0);
438   for (size_t i = 0; i < materials.size(); i++) {
439     (*out_materials)[i].diffuse[0] = materials[i].diffuse[0];
440     (*out_materials)[i].diffuse[1] = materials[i].diffuse[1];
441     (*out_materials)[i].diffuse[2] = materials[i].diffuse[2];
442     (*out_materials)[i].specular[0] = materials[i].specular[0];
443     (*out_materials)[i].specular[1] = materials[i].specular[1];
444     (*out_materials)[i].specular[2] = materials[i].specular[2];
445 
446     (*out_materials)[i].id = int(i);
447 
448     // map_Kd
449     (*out_materials)[i].diffuse_texid =
450         LoadTexture(materials[i].diffuse_texname, out_textures);
451     // map_Ks
452     (*out_materials)[i].specular_texid =
453         LoadTexture(materials[i].specular_texname, out_textures);
454   }
455 
456   return true;
457 }
458 
459 }  // namespace example
460