1 #define TINYOBJLOADER_IMPLEMENTATION
2 #include "../tiny_obj_loader.h"
3
4 #if defined(__clang__)
5 #pragma clang diagnostic push
6 #pragma clang diagnostic ignored "-Weverything"
7 #elif defined(__GNUC__)
8 #pragma GCC diagnostic ignored "-Wmissing-declarations"
9 #pragma GCC diagnostic ignored "-Wignored-qualifiers"
10 #pragma GCC diagnostic push
11 #pragma GCC diagnostic ignored "-Wcast-qual"
12 #pragma GCC diagnostic ignored "-Wsign-conversion"
13 #pragma GCC diagnostic ignored "-Wformat"
14 #pragma GCC diagnostic ignored "-Wswitch-default"
15 #endif
16
17
18 #include "acutest.h"
19
20 #if defined(__clang__)
21 #pragma clang diagnostic pop
22 #elif defined(__GNUC__)
23 #pragma GCC diagnostic pop
24 #endif
25
26 #include <cassert>
27 #include <cstdio>
28 #include <cstdlib>
29 #include <fstream>
30 #include <iostream>
31 #include <sstream>
32
33 template <typename T>
FloatEquals(const T & a,const T & b)34 static bool FloatEquals(const T& a, const T& b) {
35 // Edit eps value as you wish.
36 const T eps = std::numeric_limits<T>::epsilon() * static_cast<T>(100);
37
38 const T abs_diff = std::abs(a - b);
39
40 if (abs_diff < eps) {
41 return true;
42 } else {
43 return false;
44 }
45 }
46
PrintInfo(const tinyobj::attrib_t & attrib,const std::vector<tinyobj::shape_t> & shapes,const std::vector<tinyobj::material_t> & materials,bool triangulate=true)47 static void PrintInfo(const tinyobj::attrib_t& attrib,
48 const std::vector<tinyobj::shape_t>& shapes,
49 const std::vector<tinyobj::material_t>& materials,
50 bool triangulate = true) {
51 std::cout << "# of vertices : " << (attrib.vertices.size() / 3) << std::endl;
52 std::cout << "# of normals : " << (attrib.normals.size() / 3) << std::endl;
53 std::cout << "# of texcoords : " << (attrib.texcoords.size() / 2)
54 << std::endl;
55
56 std::cout << "# of shapes : " << shapes.size() << std::endl;
57 std::cout << "# of materials : " << materials.size() << std::endl;
58
59 for (size_t v = 0; v < attrib.vertices.size() / 3; v++) {
60 printf(" v[%ld] = (%f, %f, %f)\n", v,
61 static_cast<const double>(attrib.vertices[3 * v + 0]),
62 static_cast<const double>(attrib.vertices[3 * v + 1]),
63 static_cast<const double>(attrib.vertices[3 * v + 2]));
64 }
65
66 for (size_t v = 0; v < attrib.normals.size() / 3; v++) {
67 printf(" n[%ld] = (%f, %f, %f)\n", v,
68 static_cast<const double>(attrib.normals[3 * v + 0]),
69 static_cast<const double>(attrib.normals[3 * v + 1]),
70 static_cast<const double>(attrib.normals[3 * v + 2]));
71 }
72
73 for (size_t v = 0; v < attrib.texcoords.size() / 2; v++) {
74 printf(" uv[%ld] = (%f, %f)\n", v,
75 static_cast<const double>(attrib.texcoords[2 * v + 0]),
76 static_cast<const double>(attrib.texcoords[2 * v + 1]));
77 }
78
79 for (size_t i = 0; i < shapes.size(); i++) {
80 printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
81 printf("Size of shape[%ld].indices: %ld\n", i,
82 shapes[i].mesh.indices.size());
83
84 if (triangulate) {
85 printf("Size of shape[%ld].material_ids: %ld\n", i,
86 shapes[i].mesh.material_ids.size());
87 assert((shapes[i].mesh.indices.size() % 3) == 0);
88 for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
89 tinyobj::index_t i0 = shapes[i].mesh.indices[3 * f + 0];
90 tinyobj::index_t i1 = shapes[i].mesh.indices[3 * f + 1];
91 tinyobj::index_t i2 = shapes[i].mesh.indices[3 * f + 2];
92 printf(" idx[%ld] = %d/%d/%d, %d/%d/%d, %d/%d/%d. mat_id = %d\n", f,
93 i0.vertex_index, i0.normal_index, i0.texcoord_index,
94 i1.vertex_index, i1.normal_index, i1.texcoord_index,
95 i2.vertex_index, i2.normal_index, i2.texcoord_index,
96 shapes[i].mesh.material_ids[f]);
97 }
98 } else {
99 for (size_t f = 0; f < shapes[i].mesh.indices.size(); f++) {
100 tinyobj::index_t idx = shapes[i].mesh.indices[f];
101 printf(" idx[%ld] = %d/%d/%d\n", f, idx.vertex_index, idx.normal_index,
102 idx.texcoord_index);
103 }
104
105 printf("Size of shape[%ld].material_ids: %ld\n", i,
106 shapes[i].mesh.material_ids.size());
107 assert(shapes[i].mesh.material_ids.size() ==
108 shapes[i].mesh.num_face_vertices.size());
109 for (size_t m = 0; m < shapes[i].mesh.material_ids.size(); m++) {
110 printf(" material_id[%ld] = %d\n", m, shapes[i].mesh.material_ids[m]);
111 }
112 }
113
114 printf("shape[%ld].num_faces: %ld\n", i,
115 shapes[i].mesh.num_face_vertices.size());
116 for (size_t v = 0; v < shapes[i].mesh.num_face_vertices.size(); v++) {
117 printf(" num_vertices[%ld] = %ld\n", v,
118 static_cast<long>(shapes[i].mesh.num_face_vertices[v]));
119 }
120
121 // printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
122 // assert((shapes[i].mesh.positions.size() % 3) == 0);
123 // for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
124 // printf(" v[%ld] = (%f, %f, %f)\n", v,
125 // static_cast<const double>(shapes[i].mesh.positions[3*v+0]),
126 // static_cast<const double>(shapes[i].mesh.positions[3*v+1]),
127 // static_cast<const double>(shapes[i].mesh.positions[3*v+2]));
128 //}
129
130 printf("shape[%ld].num_tags: %ld\n", i, shapes[i].mesh.tags.size());
131 for (size_t t = 0; t < shapes[i].mesh.tags.size(); t++) {
132 printf(" tag[%ld] = %s ", t, shapes[i].mesh.tags[t].name.c_str());
133 printf(" ints: [");
134 for (size_t j = 0; j < shapes[i].mesh.tags[t].intValues.size(); ++j) {
135 printf("%ld", static_cast<long>(shapes[i].mesh.tags[t].intValues[j]));
136 if (j < (shapes[i].mesh.tags[t].intValues.size() - 1)) {
137 printf(", ");
138 }
139 }
140 printf("]");
141
142 printf(" floats: [");
143 for (size_t j = 0; j < shapes[i].mesh.tags[t].floatValues.size(); ++j) {
144 printf("%f", static_cast<const double>(
145 shapes[i].mesh.tags[t].floatValues[j]));
146 if (j < (shapes[i].mesh.tags[t].floatValues.size() - 1)) {
147 printf(", ");
148 }
149 }
150 printf("]");
151
152 printf(" strings: [");
153 for (size_t j = 0; j < shapes[i].mesh.tags[t].stringValues.size(); ++j) {
154 printf("%s", shapes[i].mesh.tags[t].stringValues[j].c_str());
155 if (j < (shapes[i].mesh.tags[t].stringValues.size() - 1)) {
156 printf(", ");
157 }
158 }
159 printf("]");
160 printf("\n");
161 }
162 }
163
164 for (size_t i = 0; i < materials.size(); i++) {
165 printf("material[%ld].name = %s\n", i, materials[i].name.c_str());
166 printf(" material.Ka = (%f, %f ,%f)\n",
167 static_cast<const double>(materials[i].ambient[0]),
168 static_cast<const double>(materials[i].ambient[1]),
169 static_cast<const double>(materials[i].ambient[2]));
170 printf(" material.Kd = (%f, %f ,%f)\n",
171 static_cast<const double>(materials[i].diffuse[0]),
172 static_cast<const double>(materials[i].diffuse[1]),
173 static_cast<const double>(materials[i].diffuse[2]));
174 printf(" material.Ks = (%f, %f ,%f)\n",
175 static_cast<const double>(materials[i].specular[0]),
176 static_cast<const double>(materials[i].specular[1]),
177 static_cast<const double>(materials[i].specular[2]));
178 printf(" material.Tr = (%f, %f ,%f)\n",
179 static_cast<const double>(materials[i].transmittance[0]),
180 static_cast<const double>(materials[i].transmittance[1]),
181 static_cast<const double>(materials[i].transmittance[2]));
182 printf(" material.Ke = (%f, %f ,%f)\n",
183 static_cast<const double>(materials[i].emission[0]),
184 static_cast<const double>(materials[i].emission[1]),
185 static_cast<const double>(materials[i].emission[2]));
186 printf(" material.Ns = %f\n",
187 static_cast<const double>(materials[i].shininess));
188 printf(" material.Ni = %f\n", static_cast<const double>(materials[i].ior));
189 printf(" material.dissolve = %f\n",
190 static_cast<const double>(materials[i].dissolve));
191 printf(" material.illum = %d\n", materials[i].illum);
192 printf(" material.map_Ka = %s\n", materials[i].ambient_texname.c_str());
193 printf(" material.map_Kd = %s\n", materials[i].diffuse_texname.c_str());
194 printf(" material.map_Ks = %s\n", materials[i].specular_texname.c_str());
195 printf(" material.map_Ns = %s\n",
196 materials[i].specular_highlight_texname.c_str());
197 printf(" material.map_bump = %s\n", materials[i].bump_texname.c_str());
198 printf(" material.map_d = %s\n", materials[i].alpha_texname.c_str());
199 printf(" material.disp = %s\n", materials[i].displacement_texname.c_str());
200 printf(" material.refl = %s\n", materials[i].reflection_texname.c_str());
201 std::map<std::string, std::string>::const_iterator it(
202 materials[i].unknown_parameter.begin());
203 std::map<std::string, std::string>::const_iterator itEnd(
204 materials[i].unknown_parameter.end());
205
206 for (; it != itEnd; it++) {
207 printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
208 }
209 printf("\n");
210 }
211 }
212
TestLoadObj(const char * filename,const char * basepath=NULL,bool triangulate=true)213 static bool TestLoadObj(const char* filename, const char* basepath = NULL,
214 bool triangulate = true) {
215 std::cout << "Loading " << filename << std::endl;
216
217 tinyobj::attrib_t attrib;
218 std::vector<tinyobj::shape_t> shapes;
219 std::vector<tinyobj::material_t> materials;
220
221 std::string warn;
222 std::string err;
223 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
224 filename, basepath, triangulate);
225
226 if (!warn.empty()) {
227 std::cout << "WARN: " << warn << std::endl;
228 }
229
230 if (!err.empty()) {
231 std::cerr << "ERR: " << err << std::endl;
232 }
233
234 if (!ret) {
235 printf("Failed to load/parse .obj.\n");
236 return false;
237 }
238
239 PrintInfo(attrib, shapes, materials, triangulate);
240
241 return true;
242 }
243
TestLoadObjFromPreopenedFile(const char * filename,const char * basepath=NULL,bool readMaterials=true,bool triangulate=true)244 static bool TestLoadObjFromPreopenedFile(const char* filename,
245 const char* basepath = NULL,
246 bool readMaterials = true,
247 bool triangulate = true) {
248 std::string fullFilename = std::string(basepath) + filename;
249 std::cout << "Loading " << fullFilename << std::endl;
250
251 std::ifstream fileStream(fullFilename.c_str());
252
253 if (!fileStream) {
254 std::cerr << "Could not find specified file: " << fullFilename << std::endl;
255 return false;
256 }
257
258 tinyobj::MaterialStreamReader materialStreamReader(fileStream);
259 tinyobj::MaterialStreamReader* materialReader =
260 readMaterials ? &materialStreamReader : NULL;
261
262 tinyobj::attrib_t attrib;
263 std::vector<tinyobj::shape_t> shapes;
264 std::vector<tinyobj::material_t> materials;
265
266 std::string warn;
267 std::string err;
268 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
269 &fileStream, materialReader);
270
271 if (!warn.empty()) {
272 std::cout << "WARN: " << warn << std::endl;
273 }
274
275 if (!err.empty()) {
276 std::cerr << "ERR: " << err << std::endl;
277 }
278
279 if (!ret) {
280 printf("Failed to load/parse .obj.\n");
281 return false;
282 }
283
284 std::cout << "Loaded material count: " << materials.size() << "\n";
285
286 return true;
287 }
288
TestStreamLoadObj()289 static bool TestStreamLoadObj() {
290 std::cout << "Stream Loading " << std::endl;
291
292 std::stringstream objStream;
293 objStream << "mtllib cube.mtl\n"
294 "\n"
295 "v 0.000000 2.000000 2.000000\n"
296 "v 0.000000 0.000000 2.000000\n"
297 "v 2.000000 0.000000 2.000000\n"
298 "v 2.000000 2.000000 2.000000\n"
299 "v 0.000000 2.000000 0.000000\n"
300 "v 0.000000 0.000000 0.000000\n"
301 "v 2.000000 0.000000 0.000000\n"
302 "v 2.000000 2.000000 0.000000\n"
303 "# 8 vertices\n"
304 "\n"
305 "g front cube\n"
306 "usemtl white\n"
307 "f 1 2 3 4\n"
308 "g back cube\n"
309 "# expects white material\n"
310 "f 8 7 6 5\n"
311 "g right cube\n"
312 "usemtl red\n"
313 "f 4 3 7 8\n"
314 "g top cube\n"
315 "usemtl white\n"
316 "f 5 1 4 8\n"
317 "g left cube\n"
318 "usemtl green\n"
319 "f 5 6 2 1\n"
320 "g bottom cube\n"
321 "usemtl white\n"
322 "f 2 6 7 3\n"
323 "# 6 elements";
324
325 std::string matStream(
326 "newmtl white\n"
327 "Ka 0 0 0\n"
328 "Kd 1 1 1\n"
329 "Ks 0 0 0\n"
330 "\n"
331 "newmtl red\n"
332 "Ka 0 0 0\n"
333 "Kd 1 0 0\n"
334 "Ks 0 0 0\n"
335 "\n"
336 "newmtl green\n"
337 "Ka 0 0 0\n"
338 "Kd 0 1 0\n"
339 "Ks 0 0 0\n"
340 "\n"
341 "newmtl blue\n"
342 "Ka 0 0 0\n"
343 "Kd 0 0 1\n"
344 "Ks 0 0 0\n"
345 "\n"
346 "newmtl light\n"
347 "Ka 20 20 20\n"
348 "Kd 1 1 1\n"
349 "Ks 0 0 0");
350
351 using namespace tinyobj;
352 class MaterialStringStreamReader : public MaterialReader {
353 public:
354 MaterialStringStreamReader(const std::string& matSStream)
355 : m_matSStream(matSStream) {}
356 virtual ~MaterialStringStreamReader() {}
357 virtual bool operator()(const std::string& matId,
358 std::vector<material_t>* materials,
359 std::map<std::string, int>* matMap,
360 std::string* warn, std::string* err) {
361 (void)matId;
362 (void)warn;
363 (void)err;
364 std::string warning;
365 std::string error_msg;
366 LoadMtl(matMap, materials, &m_matSStream, &warning, &error_msg);
367 return true;
368 }
369
370 private:
371 std::stringstream m_matSStream;
372 };
373
374 MaterialStringStreamReader matSSReader(matStream);
375 tinyobj::attrib_t attrib;
376 std::vector<tinyobj::shape_t> shapes;
377 std::vector<tinyobj::material_t> materials;
378 std::string warn;
379 std::string err;
380 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
381 &objStream, &matSSReader);
382
383 if (!warn.empty()) {
384 std::cout << "WARN: " << warn << std::endl;
385 }
386
387 if (!err.empty()) {
388 std::cerr << "ERR: " << err << std::endl;
389 }
390
391 if (!ret) {
392 return false;
393 }
394
395 PrintInfo(attrib, shapes, materials);
396
397 return true;
398 }
399
400 const char* gMtlBasePath = "../models/";
401
test_cornell_box()402 void test_cornell_box() {
403 TEST_CHECK(true == TestLoadObj("../models/cornell_box.obj", gMtlBasePath));
404 }
405
test_catmark_torus_creases0()406 void test_catmark_torus_creases0() {
407 tinyobj::attrib_t attrib;
408 std::vector<tinyobj::shape_t> shapes;
409 std::vector<tinyobj::material_t> materials;
410
411 std::string warn;
412 std::string err;
413 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
414 "../models/catmark_torus_creases0.obj",
415 gMtlBasePath, /*triangulate*/ false);
416
417 if (!warn.empty()) {
418 std::cout << "WARN: " << warn << std::endl;
419 }
420
421 if (!err.empty()) {
422 std::cerr << "ERR: " << err << std::endl;
423 }
424
425 TEST_CHECK(true == ret);
426
427 TEST_CHECK(1 == shapes.size());
428 TEST_CHECK(8 == shapes[0].mesh.tags.size());
429 }
430
test_pbr()431 void test_pbr() {
432 tinyobj::attrib_t attrib;
433 std::vector<tinyobj::shape_t> shapes;
434 std::vector<tinyobj::material_t> materials;
435
436 std::string warn;
437 std::string err;
438 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
439 "../models/pbr-mat-ext.obj", gMtlBasePath,
440 /*triangulate*/ false);
441
442 if (!warn.empty()) {
443 std::cout << "WARN: " << warn << std::endl;
444 }
445
446 if (!err.empty()) {
447 std::cerr << "ERR: " << err << std::endl;
448 }
449 TEST_CHECK(true == ret);
450 TEST_CHECK(1 == materials.size());
451 TEST_CHECK(FloatEquals(0.2f, materials[0].roughness));
452 TEST_CHECK(FloatEquals(0.3f, materials[0].metallic));
453 TEST_CHECK(FloatEquals(0.4f, materials[0].sheen));
454 TEST_CHECK(FloatEquals(0.5f, materials[0].clearcoat_thickness));
455 TEST_CHECK(FloatEquals(0.6f, materials[0].clearcoat_roughness));
456 TEST_CHECK(FloatEquals(0.7f, materials[0].anisotropy));
457 TEST_CHECK(FloatEquals(0.8f, materials[0].anisotropy_rotation));
458 TEST_CHECK(0 == materials[0].roughness_texname.compare("roughness.tex"));
459 TEST_CHECK(0 == materials[0].metallic_texname.compare("metallic.tex"));
460 TEST_CHECK(0 == materials[0].sheen_texname.compare("sheen.tex"));
461 TEST_CHECK(0 == materials[0].emissive_texname.compare("emissive.tex"));
462 TEST_CHECK(0 == materials[0].normal_texname.compare("normalmap.tex"));
463 }
464
test_stream_load()465 void test_stream_load() { TEST_CHECK(true == TestStreamLoadObj()); }
466
test_stream_load_from_file_skipping_materials()467 void test_stream_load_from_file_skipping_materials() {
468 TEST_CHECK(true == TestLoadObjFromPreopenedFile(
469 "../models/pbr-mat-ext.obj", gMtlBasePath,
470 /*readMaterials*/ false, /*triangulate*/ false));
471 }
472
test_stream_load_from_file_with_materials()473 void test_stream_load_from_file_with_materials() {
474 TEST_CHECK(true == TestLoadObjFromPreopenedFile(
475 "../models/pbr-mat-ext.obj", gMtlBasePath,
476 /*readMaterials*/ true, /*triangulate*/ false));
477 }
478
test_trailing_whitespace_in_mtl_issue92()479 void test_trailing_whitespace_in_mtl_issue92() {
480 tinyobj::attrib_t attrib;
481 std::vector<tinyobj::shape_t> shapes;
482 std::vector<tinyobj::material_t> materials;
483
484 std::string warn;
485 std::string err;
486 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
487 "../models/issue-92.obj", gMtlBasePath);
488
489 if (!warn.empty()) {
490 std::cout << "WARN: " << warn << std::endl;
491 }
492
493 if (!err.empty()) {
494 std::cerr << "ERR: " << err << std::endl;
495 }
496 TEST_CHECK(true == ret);
497 TEST_CHECK(1 == materials.size());
498 TEST_CHECK(0 == materials[0].diffuse_texname.compare("tmp.png"));
499 }
500
test_transmittance_filter_issue95()501 void test_transmittance_filter_issue95() {
502 tinyobj::attrib_t attrib;
503 std::vector<tinyobj::shape_t> shapes;
504 std::vector<tinyobj::material_t> materials;
505
506 std::string warn;
507 std::string err;
508 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
509 "../models/issue-95.obj", gMtlBasePath);
510
511 if (!warn.empty()) {
512 std::cout << "WARN: " << warn << std::endl;
513 }
514
515 if (!err.empty()) {
516 std::cerr << "ERR: " << err << std::endl;
517 }
518 TEST_CHECK(true == ret);
519 TEST_CHECK(1 == materials.size());
520 TEST_CHECK(FloatEquals(0.1f, materials[0].transmittance[0]));
521 TEST_CHECK(FloatEquals(0.2f, materials[0].transmittance[1]));
522 TEST_CHECK(FloatEquals(0.3f, materials[0].transmittance[2]));
523 }
524
test_transmittance_filter_Tf_issue95()525 void test_transmittance_filter_Tf_issue95() {
526 tinyobj::attrib_t attrib;
527 std::vector<tinyobj::shape_t> shapes;
528 std::vector<tinyobj::material_t> materials;
529
530 std::string warn;
531 std::string err;
532 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
533 "../models/issue-95-2.obj", gMtlBasePath);
534
535 if (!warn.empty()) {
536 std::cout << "WARN: " << warn << std::endl;
537 }
538
539 if (!err.empty()) {
540 std::cerr << "ERR: " << err << std::endl;
541 }
542 TEST_CHECK(true == ret);
543 TEST_CHECK(1 == materials.size());
544 TEST_CHECK(FloatEquals(0.1f, materials[0].transmittance[0]));
545 TEST_CHECK(FloatEquals(0.2f, materials[0].transmittance[1]));
546 TEST_CHECK(FloatEquals(0.3f, materials[0].transmittance[2]));
547 }
548
test_transmittance_filter_Kt_issue95()549 void test_transmittance_filter_Kt_issue95() {
550 tinyobj::attrib_t attrib;
551 std::vector<tinyobj::shape_t> shapes;
552 std::vector<tinyobj::material_t> materials;
553
554 std::string warn;
555 std::string err;
556 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
557 "../models/issue-95.obj", gMtlBasePath);
558
559 if (!warn.empty()) {
560 std::cout << "WARN: " << warn << std::endl;
561 }
562
563 if (!err.empty()) {
564 std::cerr << "ERR: " << err << std::endl;
565 }
566 TEST_CHECK(true == ret);
567 TEST_CHECK(1 == materials.size());
568 TEST_CHECK(FloatEquals(0.1f, materials[0].transmittance[0]));
569 TEST_CHECK(FloatEquals(0.2f, materials[0].transmittance[1]));
570 TEST_CHECK(FloatEquals(0.3f, materials[0].transmittance[2]));
571 }
572
test_usemtl_at_last_line_issue104()573 void test_usemtl_at_last_line_issue104() {
574 tinyobj::attrib_t attrib;
575 std::vector<tinyobj::shape_t> shapes;
576 std::vector<tinyobj::material_t> materials;
577
578 std::string warn;
579 std::string err;
580 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
581 "../models/usemtl-issue-104.obj", gMtlBasePath);
582
583 if (!warn.empty()) {
584 std::cout << "WARN: " << warn << std::endl;
585 }
586
587 if (!err.empty()) {
588 std::cerr << "ERR: " << err << std::endl;
589 }
590 TEST_CHECK(true == ret);
591 TEST_CHECK(1 == shapes.size());
592 }
593
test_texture_opts_issue85()594 void test_texture_opts_issue85() {
595 tinyobj::attrib_t attrib;
596 std::vector<tinyobj::shape_t> shapes;
597 std::vector<tinyobj::material_t> materials;
598
599 std::string warn;
600 std::string err;
601 bool ret =
602 tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
603 "../models/texture-options-issue-85.obj", gMtlBasePath);
604
605 if (!warn.empty()) {
606 std::cout << "WARN: " << warn << std::endl;
607 }
608
609 if (!err.empty()) {
610 std::cerr << "ERR: " << err << std::endl;
611 }
612 TEST_CHECK(true == ret);
613 TEST_CHECK(1 == shapes.size());
614 TEST_CHECK(3 == materials.size());
615 TEST_CHECK(0 == materials[0].name.compare("default"));
616 TEST_CHECK(0 == materials[1].name.compare("bm2"));
617 TEST_CHECK(0 == materials[2].name.compare("bm3"));
618 TEST_CHECK(true == materials[0].ambient_texopt.clamp);
619 TEST_CHECK(FloatEquals(0.1f, materials[0].diffuse_texopt.origin_offset[0]));
620 TEST_CHECK(FloatEquals(0.0f, materials[0].diffuse_texopt.origin_offset[1]));
621 TEST_CHECK(FloatEquals(0.0f, materials[0].diffuse_texopt.origin_offset[2]));
622 TEST_CHECK(FloatEquals(0.1f, materials[0].specular_texopt.scale[0]));
623 TEST_CHECK(FloatEquals(0.2f, materials[0].specular_texopt.scale[1]));
624 TEST_CHECK(FloatEquals(1.0f, materials[0].specular_texopt.scale[2]));
625 TEST_CHECK(
626 FloatEquals(0.1f, materials[0].specular_highlight_texopt.turbulence[0]));
627 TEST_CHECK(
628 FloatEquals(0.2f, materials[0].specular_highlight_texopt.turbulence[1]));
629 TEST_CHECK(
630 FloatEquals(0.3f, materials[0].specular_highlight_texopt.turbulence[2]));
631 TEST_CHECK(FloatEquals(3.0f, materials[0].bump_texopt.bump_multiplier));
632
633 TEST_CHECK(
634 FloatEquals(0.1f, materials[1].specular_highlight_texopt.brightness));
635 TEST_CHECK(
636 FloatEquals(0.3f, materials[1].specular_highlight_texopt.contrast));
637 TEST_CHECK('r' == materials[1].bump_texopt.imfchan);
638
639 TEST_CHECK(tinyobj::TEXTURE_TYPE_SPHERE == materials[2].diffuse_texopt.type);
640 TEST_CHECK(tinyobj::TEXTURE_TYPE_CUBE_TOP ==
641 materials[2].specular_texopt.type);
642 TEST_CHECK(tinyobj::TEXTURE_TYPE_CUBE_BOTTOM ==
643 materials[2].specular_highlight_texopt.type);
644 TEST_CHECK(tinyobj::TEXTURE_TYPE_CUBE_LEFT ==
645 materials[2].ambient_texopt.type);
646 TEST_CHECK(tinyobj::TEXTURE_TYPE_CUBE_RIGHT ==
647 materials[2].alpha_texopt.type);
648 TEST_CHECK(tinyobj::TEXTURE_TYPE_CUBE_FRONT == materials[2].bump_texopt.type);
649 TEST_CHECK(tinyobj::TEXTURE_TYPE_CUBE_BACK ==
650 materials[2].displacement_texopt.type);
651 }
652
test_mtllib_multiple_filenames_issue112()653 void test_mtllib_multiple_filenames_issue112() {
654 tinyobj::attrib_t attrib;
655 std::vector<tinyobj::shape_t> shapes;
656 std::vector<tinyobj::material_t> materials;
657
658 std::string warn;
659 std::string err;
660 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
661 "../models/mtllib-multiple-files-issue-112.obj",
662 gMtlBasePath);
663
664 if (!warn.empty()) {
665 std::cout << "WARN: " << warn << std::endl;
666 }
667
668 if (!err.empty()) {
669 std::cerr << "ERR: " << err << std::endl;
670 }
671 TEST_CHECK(true == ret);
672 TEST_CHECK(1 == materials.size());
673 }
674
test_tr_and_d_issue43()675 void test_tr_and_d_issue43() {
676 tinyobj::attrib_t attrib;
677 std::vector<tinyobj::shape_t> shapes;
678 std::vector<tinyobj::material_t> materials;
679
680 std::string warn;
681 std::string err;
682 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
683 "../models/tr-and-d-issue-43.obj", gMtlBasePath);
684
685 if (!warn.empty()) {
686 std::cout << "WARN: " << warn << std::endl;
687 }
688
689 if (!err.empty()) {
690 std::cerr << "ERR: " << err << std::endl;
691 }
692 TEST_CHECK(true == ret);
693 TEST_CHECK(2 == materials.size());
694
695 TEST_CHECK(FloatEquals(0.75f, materials[0].dissolve));
696 TEST_CHECK(FloatEquals(0.75f, materials[1].dissolve));
697 }
698
test_refl()699 void test_refl() {
700 tinyobj::attrib_t attrib;
701 std::vector<tinyobj::shape_t> shapes;
702 std::vector<tinyobj::material_t> materials;
703
704 std::string warn;
705 std::string err;
706 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
707 "../models/refl.obj", gMtlBasePath);
708
709 if (!warn.empty()) {
710 std::cout << "WARN: " << warn << std::endl;
711 }
712
713 if (!err.empty()) {
714 std::cerr << "ERR: " << err << std::endl;
715 }
716
717 PrintInfo(attrib, shapes, materials);
718
719 TEST_CHECK(true == ret);
720 TEST_CHECK(5 == materials.size());
721
722 TEST_CHECK(materials[0].reflection_texname.compare("reflection.tga") == 0);
723 }
724
test_map_Bump()725 void test_map_Bump() {
726 tinyobj::attrib_t attrib;
727 std::vector<tinyobj::shape_t> shapes;
728 std::vector<tinyobj::material_t> materials;
729
730 std::string warn;
731 std::string err;
732 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
733 "../models/map-bump.obj", gMtlBasePath);
734
735 if (!warn.empty()) {
736 std::cout << "WARN: " << warn << std::endl;
737 }
738
739 if (!err.empty()) {
740 std::cerr << "ERR: " << err << std::endl;
741 }
742
743 PrintInfo(attrib, shapes, materials);
744
745 TEST_CHECK(true == ret);
746 TEST_CHECK(2 == materials.size());
747
748 TEST_CHECK(materials[0].bump_texname.compare("bump.jpg") == 0);
749 }
750
test_g_ignored_issue138()751 void test_g_ignored_issue138() {
752 tinyobj::attrib_t attrib;
753 std::vector<tinyobj::shape_t> shapes;
754 std::vector<tinyobj::material_t> materials;
755
756 std::string warn;
757 std::string err;
758 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
759 "../models/issue-138.obj", gMtlBasePath);
760
761 if (!warn.empty()) {
762 std::cout << "WARN: " << warn << std::endl;
763 }
764
765 if (!err.empty()) {
766 std::cerr << "ERR: " << err << std::endl;
767 }
768
769 PrintInfo(attrib, shapes, materials);
770
771 TEST_CHECK(true == ret);
772 TEST_CHECK(2 == shapes.size());
773 TEST_CHECK(2 == materials.size());
774 }
775
test_vertex_col_ext_issue144()776 void test_vertex_col_ext_issue144() {
777 tinyobj::attrib_t attrib;
778 std::vector<tinyobj::shape_t> shapes;
779 std::vector<tinyobj::material_t> materials;
780
781 std::string warn;
782 std::string err;
783
784 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
785 "../models/cube-vertexcol.obj", gMtlBasePath);
786
787 if (!warn.empty()) {
788 std::cout << "WARN: " << warn << std::endl;
789 }
790
791 if (!err.empty()) {
792 std::cerr << "ERR: " << err << std::endl;
793 }
794
795 // PrintInfo(attrib, shapes, materials);
796
797 TEST_CHECK(true == ret);
798 TEST_CHECK((8 * 3) == attrib.colors.size());
799
800 TEST_CHECK(FloatEquals(0.0f, attrib.colors[3 * 0 + 0]));
801 TEST_CHECK(FloatEquals(0.0f, attrib.colors[3 * 0 + 1]));
802 TEST_CHECK(FloatEquals(0.0f, attrib.colors[3 * 0 + 2]));
803
804 TEST_CHECK(FloatEquals(0.0f, attrib.colors[3 * 1 + 0]));
805 TEST_CHECK(FloatEquals(0.0f, attrib.colors[3 * 1 + 1]));
806 TEST_CHECK(FloatEquals(1.0f, attrib.colors[3 * 1 + 2]));
807
808 TEST_CHECK(FloatEquals(1.0f, attrib.colors[3 * 4 + 0]));
809
810 TEST_CHECK(FloatEquals(1.0f, attrib.colors[3 * 7 + 0]));
811 TEST_CHECK(FloatEquals(1.0f, attrib.colors[3 * 7 + 1]));
812 TEST_CHECK(FloatEquals(1.0f, attrib.colors[3 * 7 + 2]));
813 }
814
test_norm_texopts()815 void test_norm_texopts() {
816 tinyobj::attrib_t attrib;
817 std::vector<tinyobj::shape_t> shapes;
818 std::vector<tinyobj::material_t> materials;
819
820 std::string warn;
821 std::string err;
822 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
823 "../models/norm-texopt.obj", gMtlBasePath);
824
825 if (!warn.empty()) {
826 std::cout << "WARN: " << warn << std::endl;
827 }
828
829 if (!err.empty()) {
830 std::cerr << "ERR: " << err << std::endl;
831 }
832
833 TEST_CHECK(true == ret);
834 TEST_CHECK(1 == shapes.size());
835 TEST_CHECK(1 == materials.size());
836 TEST_CHECK(FloatEquals(3.0f, materials[0].normal_texopt.bump_multiplier));
837 }
838
test_zero_face_idx_value_issue140()839 void test_zero_face_idx_value_issue140() {
840 tinyobj::attrib_t attrib;
841 std::vector<tinyobj::shape_t> shapes;
842 std::vector<tinyobj::material_t> materials;
843
844 std::string warn;
845 std::string err;
846 bool ret =
847 tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
848 "../models/issue-140-zero-face-idx.obj", gMtlBasePath);
849
850 if (!warn.empty()) {
851 std::cout << "WARN: " << warn << std::endl;
852 }
853
854 if (!err.empty()) {
855 std::cerr << "ERR: " << err << std::endl;
856 }
857 TEST_CHECK(false == ret);
858 TEST_CHECK(!err.empty());
859 }
860
test_texture_name_whitespace_issue145()861 void test_texture_name_whitespace_issue145() {
862 tinyobj::attrib_t attrib;
863 std::vector<tinyobj::shape_t> shapes;
864 std::vector<tinyobj::material_t> materials;
865
866 std::string warn;
867 std::string err;
868 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
869 "../models/texture-filename-with-whitespace.obj",
870 gMtlBasePath);
871
872 if (!warn.empty()) {
873 std::cout << "WARN: " << warn << std::endl;
874 }
875
876 if (!err.empty()) {
877 std::cerr << "ERR: " << err << std::endl;
878 }
879
880 TEST_CHECK(true == ret);
881 TEST_CHECK(err.empty());
882 TEST_CHECK(2 < materials.size());
883
884 TEST_CHECK(0 == materials[0].diffuse_texname.compare("texture 01.png"));
885 TEST_CHECK(0 == materials[1].bump_texname.compare("bump 01.png"));
886 TEST_CHECK(FloatEquals(2.0f, materials[1].bump_texopt.bump_multiplier));
887 }
888
test_smoothing_group_issue162()889 void test_smoothing_group_issue162() {
890 tinyobj::attrib_t attrib;
891 std::vector<tinyobj::shape_t> shapes;
892 std::vector<tinyobj::material_t> materials;
893
894 std::string warn;
895 std::string err;
896 bool ret =
897 tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
898 "../models/issue-162-smoothing-group.obj", gMtlBasePath);
899
900 if (!warn.empty()) {
901 std::cout << "WARN: " << warn << std::endl;
902 }
903
904 if (!err.empty()) {
905 std::cerr << "ERR: " << err << std::endl;
906 }
907
908 TEST_CHECK(true == ret);
909 TEST_CHECK(2 == shapes.size());
910
911 TEST_CHECK(2 == shapes[0].mesh.smoothing_group_ids.size());
912 TEST_CHECK(1 == shapes[0].mesh.smoothing_group_ids[0]);
913 TEST_CHECK(1 == shapes[0].mesh.smoothing_group_ids[1]);
914
915 TEST_CHECK(10 == shapes[1].mesh.smoothing_group_ids.size());
916 TEST_CHECK(0 == shapes[1].mesh.smoothing_group_ids[0]);
917 TEST_CHECK(0 == shapes[1].mesh.smoothing_group_ids[1]);
918 TEST_CHECK(3 == shapes[1].mesh.smoothing_group_ids[2]);
919 TEST_CHECK(3 == shapes[1].mesh.smoothing_group_ids[3]);
920 TEST_CHECK(4 == shapes[1].mesh.smoothing_group_ids[4]);
921 TEST_CHECK(4 == shapes[1].mesh.smoothing_group_ids[5]);
922 TEST_CHECK(0 == shapes[1].mesh.smoothing_group_ids[6]);
923 TEST_CHECK(0 == shapes[1].mesh.smoothing_group_ids[7]);
924 TEST_CHECK(6 == shapes[1].mesh.smoothing_group_ids[8]);
925 TEST_CHECK(6 == shapes[1].mesh.smoothing_group_ids[9]);
926 }
927
test_invalid_face_definition()928 void test_invalid_face_definition() {
929 tinyobj::attrib_t attrib;
930 std::vector<tinyobj::shape_t> shapes;
931 std::vector<tinyobj::material_t> materials;
932
933 std::string warn;
934 std::string err;
935 bool ret =
936 tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
937 "../models/invalid-face-definition.obj", gMtlBasePath);
938
939 if (!warn.empty()) {
940 std::cout << "WARN: " << warn << std::endl;
941 }
942
943 if (!err.empty()) {
944 std::cerr << "ERR: " << err << std::endl;
945 }
946
947 TEST_CHECK(true == ret);
948 TEST_CHECK(1 == shapes.size());
949 TEST_CHECK(0 == shapes[0].mesh.indices.size());
950 }
951
test_Empty_mtl_basedir_issue177()952 void test_Empty_mtl_basedir_issue177() {
953 tinyobj::attrib_t attrib;
954 std::vector<tinyobj::shape_t> shapes;
955 std::vector<tinyobj::material_t> materials;
956
957 std::string warn;
958 std::string err;
959
960 // A case where the user explicitly provides an empty string
961 // Win32 specific?
962 const char* userBaseDir = "";
963 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
964 "issue-177.obj", userBaseDir);
965
966 // if mtl loading fails, we get an warning message here
967 ret &= warn.empty();
968
969 if (!warn.empty()) {
970 std::cout << "WARN: " << warn << std::endl;
971 }
972
973 if (!err.empty()) {
974 std::cerr << "ERR: " << err << std::endl;
975 }
976
977 TEST_CHECK(true == ret);
978 }
979
test_line_primitive()980 void test_line_primitive() {
981 tinyobj::attrib_t attrib;
982 std::vector<tinyobj::shape_t> shapes;
983 std::vector<tinyobj::material_t> materials;
984
985 std::string warn;
986 std::string err;
987 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
988 "../models/line-prim.obj", gMtlBasePath);
989
990 if (!warn.empty()) {
991 std::cout << "WARN: " << warn << std::endl;
992 }
993
994 if (!err.empty()) {
995 std::cerr << "ERR: " << err << std::endl;
996 }
997
998 TEST_CHECK(true == ret);
999 TEST_CHECK(1 == shapes.size());
1000 TEST_CHECK(8 == shapes[0].lines.indices.size());
1001 TEST_CHECK(2 == shapes[0].lines.num_line_vertices.size());
1002 }
1003
test_points_primitive()1004 void test_points_primitive() {
1005 tinyobj::attrib_t attrib;
1006 std::vector<tinyobj::shape_t> shapes;
1007 std::vector<tinyobj::material_t> materials;
1008
1009 std::string warn;
1010 std::string err;
1011 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
1012 "../models/points-prim.obj", gMtlBasePath);
1013
1014 if (!warn.empty()) {
1015 std::cout << "WARN: " << warn << std::endl;
1016 }
1017
1018 if (!err.empty()) {
1019 std::cerr << "ERR: " << err << std::endl;
1020 }
1021
1022 TEST_CHECK(true == ret);
1023 TEST_CHECK(1 == shapes.size());
1024 TEST_CHECK(8 == shapes[0].points.indices.size());
1025 }
1026
test_multiple_group_names()1027 void test_multiple_group_names() {
1028 tinyobj::attrib_t attrib;
1029 std::vector<tinyobj::shape_t> shapes;
1030 std::vector<tinyobj::material_t> materials;
1031
1032 std::string warn;
1033 std::string err;
1034 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
1035 "../models/cube.obj", gMtlBasePath);
1036
1037 if (!warn.empty()) {
1038 std::cout << "WARN: " << warn << std::endl;
1039 }
1040
1041 if (!err.empty()) {
1042 std::cerr << "ERR: " << err << std::endl;
1043 }
1044
1045 TEST_CHECK(true == ret);
1046 TEST_CHECK(6 == shapes.size());
1047 TEST_CHECK(0 == shapes[0].name.compare("front cube"));
1048 TEST_CHECK(0 == shapes[1].name.compare("back cube")); // multiple whitespaces
1049 // are aggregated as
1050 // single white space.
1051 }
1052
test_initialize_all_texopts()1053 void test_initialize_all_texopts() {
1054 tinyobj::attrib_t attrib;
1055 std::vector<tinyobj::shape_t> shapes;
1056 std::vector<tinyobj::material_t> materials;
1057
1058 std::string warn;
1059 std::string err;
1060 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
1061 "../models/cornell_box.obj", gMtlBasePath, false);
1062
1063 TEST_CHECK(ret == true);
1064 TEST_CHECK(0 < materials.size());
1065
1066 #define TEST_CHECK_DEFAULT_TEXOPT(texopt) \
1067 TEST_CHECK(tinyobj::TEXTURE_TYPE_NONE == texopt.type); \
1068 TEST_CHECK(0.0 == texopt.brightness); \
1069 TEST_CHECK(1.0 == texopt.contrast); \
1070 TEST_CHECK(false == texopt.clamp); \
1071 TEST_CHECK(true == texopt.blendu); \
1072 TEST_CHECK(true == texopt.blendv); \
1073 TEST_CHECK(1.0 == texopt.bump_multiplier); \
1074 for (int j = 0; j < 3; j++) { \
1075 TEST_CHECK(0.0 == texopt.origin_offset[j]); \
1076 TEST_CHECK(1.0 == texopt.scale[j]); \
1077 TEST_CHECK(0.0 == texopt.turbulence[j]); \
1078 }
1079 for (size_t i = 0; i < materials.size(); i++) {
1080 TEST_CHECK_DEFAULT_TEXOPT(materials[i].ambient_texopt);
1081 TEST_CHECK_DEFAULT_TEXOPT(materials[i].diffuse_texopt);
1082 TEST_CHECK_DEFAULT_TEXOPT(materials[i].specular_texopt);
1083 TEST_CHECK_DEFAULT_TEXOPT(materials[i].specular_highlight_texopt);
1084 TEST_CHECK_DEFAULT_TEXOPT(materials[i].bump_texopt);
1085 TEST_CHECK_DEFAULT_TEXOPT(materials[i].displacement_texopt);
1086 TEST_CHECK_DEFAULT_TEXOPT(materials[i].alpha_texopt);
1087 TEST_CHECK_DEFAULT_TEXOPT(materials[i].reflection_texopt);
1088 TEST_CHECK_DEFAULT_TEXOPT(materials[i].roughness_texopt);
1089 TEST_CHECK_DEFAULT_TEXOPT(materials[i].metallic_texopt);
1090 TEST_CHECK_DEFAULT_TEXOPT(materials[i].sheen_texopt);
1091 TEST_CHECK_DEFAULT_TEXOPT(materials[i].emissive_texopt);
1092 TEST_CHECK_DEFAULT_TEXOPT(materials[i].normal_texopt);
1093 }
1094 #undef TEST_CHECK_DEFAULT_TEXOPT
1095 }
1096
test_colorspace_issue184()1097 void test_colorspace_issue184() {
1098 tinyobj::attrib_t attrib;
1099 std::vector<tinyobj::shape_t> shapes;
1100 std::vector<tinyobj::material_t> materials;
1101
1102 std::string warn;
1103 std::string err;
1104 bool ret =
1105 tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
1106 "../models/colorspace-issue-184.obj", gMtlBasePath);
1107
1108 if (!warn.empty()) {
1109 std::cout << "WARN: " << warn << std::endl;
1110 }
1111
1112 if (!err.empty()) {
1113 std::cerr << "ERR: " << err << std::endl;
1114 }
1115
1116 TEST_CHECK(true == ret);
1117 TEST_CHECK(1 == shapes.size());
1118 TEST_CHECK(1 == materials.size());
1119 TEST_CHECK(0 == materials[0].diffuse_texopt.colorspace.compare("sRGB"));
1120 TEST_CHECK(0 == materials[0].specular_texopt.colorspace.size());
1121 TEST_CHECK(0 == materials[0].bump_texopt.colorspace.compare("linear"));
1122 }
1123
test_leading_decimal_dots_issue201()1124 void test_leading_decimal_dots_issue201() {
1125 tinyobj::attrib_t attrib;
1126 std::vector<tinyobj::shape_t> shapes;
1127 std::vector<tinyobj::material_t> materials;
1128
1129 std::string warn;
1130 std::string err;
1131 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
1132 "../models/leading-decimal-dot-issue-201.obj",
1133 gMtlBasePath);
1134
1135 if (!warn.empty()) {
1136 std::cout << "WARN: " << warn << std::endl;
1137 }
1138
1139 if (!err.empty()) {
1140 std::cerr << "ERR: " << err << std::endl;
1141 }
1142
1143 TEST_CHECK(true == ret);
1144 TEST_CHECK(1 == shapes.size());
1145 TEST_CHECK(1 == materials.size());
1146 TEST_CHECK(FloatEquals(0.8e-1f, attrib.vertices[0]));
1147 TEST_CHECK(FloatEquals(-.7e+2f, attrib.vertices[1]));
1148 TEST_CHECK(FloatEquals(.575869f, attrib.vertices[3]));
1149 TEST_CHECK(FloatEquals(-.666304f, attrib.vertices[4]));
1150 TEST_CHECK(FloatEquals(.940448f, attrib.vertices[6]));
1151 }
1152
test_mtl_default_search_path_v2_API_issue208()1153 void test_mtl_default_search_path_v2_API_issue208() {
1154 tinyobj::ObjReader reader;
1155
1156 bool ret = reader.ParseFromFile("../models/cornell_box.obj");
1157
1158 std::cout << "WARN: " << reader.Warning() << "\n";
1159
1160 TEST_CHECK(ret == true);
1161 TEST_CHECK(reader.Warning().empty());
1162 }
1163
test_leading_zero_in_exponent_notation_issue210()1164 void test_leading_zero_in_exponent_notation_issue210() {
1165 tinyobj::attrib_t attrib;
1166 std::vector<tinyobj::shape_t> shapes;
1167 std::vector<tinyobj::material_t> materials;
1168
1169 std::string warn;
1170 std::string err;
1171 bool ret = tinyobj::LoadObj(
1172 &attrib, &shapes, &materials, &warn, &err,
1173 "../models/leading-zero-in-exponent-notation-issue-210.obj",
1174 gMtlBasePath);
1175
1176 if (!warn.empty()) {
1177 std::cout << "WARN: " << warn << std::endl;
1178 }
1179
1180 if (!err.empty()) {
1181 std::cerr << "ERR: " << err << std::endl;
1182 }
1183
1184 TEST_CHECK(true == ret);
1185 TEST_CHECK(1 == shapes.size());
1186 TEST_CHECK(1 == materials.size());
1187 TEST_CHECK(FloatEquals(0.8e-001f, attrib.vertices[0]));
1188 TEST_CHECK(FloatEquals(-.7e+02f, attrib.vertices[1]));
1189
1190 std::cout << "exp " << 0.8e-01 << std::endl;
1191 std::cout << "bora " << attrib.vertices[0] << std::endl;
1192 }
1193
test_usemtl_then_o_issue235()1194 void test_usemtl_then_o_issue235() {
1195 tinyobj::attrib_t attrib;
1196 std::vector<tinyobj::shape_t> shapes;
1197 std::vector<tinyobj::material_t> materials;
1198
1199 std::string warn;
1200 std::string err;
1201 bool ret = tinyobj::LoadObj(
1202 &attrib, &shapes, &materials, &warn, &err,
1203 "../models/issue-235-usemtl-then-o.obj",
1204 gMtlBasePath);
1205
1206 if (!warn.empty()) {
1207 std::cout << "WARN: " << warn << std::endl;
1208 }
1209
1210 if (!err.empty()) {
1211 std::cerr << "ERR: " << err << std::endl;
1212 }
1213
1214 TEST_CHECK(true == ret);
1215 TEST_CHECK(2 == shapes.size());
1216 TEST_CHECK(2 == materials.size());
1217 TEST_CHECK(4 == shapes[1].mesh.indices[0].vertex_index);
1218 }
1219
test_mtl_searchpaths_issue244()1220 void test_mtl_searchpaths_issue244() {
1221 tinyobj::attrib_t attrib;
1222 std::vector<tinyobj::shape_t> shapes;
1223 std::vector<tinyobj::material_t> materials;
1224
1225 // .mtl is located at ./assets/issue-244.mtl
1226 #if _WIN32
1227 std::string search_paths("../;../models;./assets");
1228 #else
1229 std::string search_paths("../:../models:./assets");
1230 #endif
1231
1232 std::string warn;
1233 std::string err;
1234 bool ret = tinyobj::LoadObj(
1235 &attrib, &shapes, &materials, &warn, &err,
1236 "../models/issue-244-mtl-searchpaths.obj",
1237 search_paths.c_str());
1238
1239 TEST_CHECK(warn.empty());
1240
1241 if (!warn.empty()) {
1242 std::cout << "WARN: " << warn << std::endl;
1243 }
1244
1245 if (!err.empty()) {
1246 std::cerr << "ERR: " << err << std::endl;
1247 }
1248
1249 TEST_CHECK(true == ret);
1250 TEST_CHECK(2 == shapes.size());
1251 TEST_CHECK(2 == materials.size());
1252 TEST_CHECK(4 == shapes[1].mesh.indices[0].vertex_index);
1253 }
1254
test_usemtl_whitespace_issue246()1255 void test_usemtl_whitespace_issue246() {
1256 tinyobj::attrib_t attrib;
1257 std::vector<tinyobj::shape_t> shapes;
1258 std::vector<tinyobj::material_t> materials;
1259
1260 std::string warn;
1261 std::string err;
1262 bool ret = tinyobj::LoadObj(
1263 &attrib, &shapes, &materials, &warn, &err,
1264 "../models/issue-246-usemtl-whitespace.obj",
1265 gMtlBasePath);
1266
1267 TEST_CHECK(warn.empty());
1268
1269 if (!warn.empty()) {
1270 std::cout << "WARN: " << warn << std::endl;
1271 }
1272
1273 if (!err.empty()) {
1274 std::cerr << "ERR: " << err << std::endl;
1275 }
1276
1277 TEST_CHECK(true == ret);
1278 TEST_CHECK(1 == shapes.size());
1279 TEST_CHECK(1 == materials.size());
1280 TEST_CHECK(0 == shapes[0].mesh.material_ids[0]);
1281 }
1282
test_texres_texopt_issue248()1283 void test_texres_texopt_issue248() {
1284 tinyobj::attrib_t attrib;
1285 std::vector<tinyobj::shape_t> shapes;
1286 std::vector<tinyobj::material_t> materials;
1287
1288 std::string warn;
1289 std::string err;
1290 bool ret = tinyobj::LoadObj(
1291 &attrib, &shapes, &materials, &warn, &err,
1292 "../models/issue-248-texres-texopt.obj",
1293 gMtlBasePath);
1294
1295 TEST_CHECK(warn.empty());
1296
1297 if (!warn.empty()) {
1298 std::cout << "WARN: " << warn << std::endl;
1299 }
1300
1301 if (!err.empty()) {
1302 std::cerr << "ERR: " << err << std::endl;
1303 }
1304
1305 TEST_CHECK(true == ret);
1306 TEST_CHECK(1 < materials.size());
1307 TEST_CHECK(512 == materials[0].diffuse_texopt.texture_resolution);
1308 TEST_CHECK("input.jpg" == materials[0].diffuse_texname);
1309 }
1310
test_mtl_filename_with_whitespace_issue46()1311 void test_mtl_filename_with_whitespace_issue46() {
1312 tinyobj::attrib_t attrib;
1313 std::vector<tinyobj::shape_t> shapes;
1314 std::vector<tinyobj::material_t> materials;
1315
1316 std::string warn;
1317 std::string err;
1318 bool ret =
1319 tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
1320 "../models/mtl filename with whitespace issue46.obj",
1321 gMtlBasePath);
1322
1323 if (!warn.empty()) {
1324 std::cout << "WARN: " << warn << std::endl;
1325 }
1326
1327 if (!err.empty()) {
1328 std::cerr << "ERR: " << err << std::endl;
1329 }
1330 TEST_CHECK(true == ret);
1331 TEST_CHECK(1 == materials.size());
1332 TEST_CHECK("green" == materials[0].name);
1333 }
1334
test_face_missing_issue295()1335 void test_face_missing_issue295() {
1336 tinyobj::attrib_t attrib;
1337 std::vector<tinyobj::shape_t> shapes;
1338 std::vector<tinyobj::material_t> materials;
1339
1340 std::string warn;
1341 std::string err;
1342 bool ret = tinyobj::LoadObj(
1343 &attrib, &shapes, &materials, &warn, &err,
1344 "../models/issue-295-trianguation-failure.obj",
1345 gMtlBasePath, /* triangualte */true);
1346
1347 TEST_CHECK(warn.empty());
1348
1349 if (!warn.empty()) {
1350 std::cout << "WARN: " << warn << std::endl;
1351 }
1352
1353 if (!err.empty()) {
1354 std::cerr << "ERR: " << err << std::endl;
1355 }
1356
1357 TEST_CHECK(true == ret);
1358 TEST_CHECK(1 == shapes.size());
1359
1360 // 14 quad faces are triangulated into 28 triangles.
1361 TEST_CHECK(28 == shapes[0].mesh.num_face_vertices.size());
1362 TEST_CHECK(28 == shapes[0].mesh.smoothing_group_ids.size());
1363 TEST_CHECK(28 == shapes[0].mesh.material_ids.size());
1364 TEST_CHECK((3 * 28) == shapes[0].mesh.indices.size()); // 28 triangle faces x 3
1365 }
1366
1367 // Fuzzer test.
1368 // Just check if it does not crash.
1369 // Disable by default since Windows filesystem can't create filename of afl
1370 // testdata
1371 #if 0
1372
1373 void test_afl000000", "[AFL]() {
1374 tinyobj::attrib_t attrib;
1375 std::vector<tinyobj::shape_t> shapes;
1376 std::vector<tinyobj::material_t> materials;
1377
1378 std::string err;
1379 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "./afl/id:000000,sig:11,src:000000,op:havoc,rep:128", gMtlBasePath);
1380
1381 TEST_CHECK(true == ret);
1382 }
1383
1384 void test_afl000001", "[AFL]() {
1385 tinyobj::attrib_t attrib;
1386 std::vector<tinyobj::shape_t> shapes;
1387 std::vector<tinyobj::material_t> materials;
1388
1389 std::string err;
1390 bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "./afl/id:000001,sig:11,src:000000,op:havoc,rep:64", gMtlBasePath);
1391
1392 TEST_CHECK(true == ret);
1393 }
1394 #endif
1395
1396 #if 0
1397 int
1398 main(
1399 int argc,
1400 char **argv)
1401 {
1402 if (argc > 1) {
1403 const char* basepath = NULL;
1404 if (argc > 2) {
1405 basepath = argv[2];
1406 }
1407 assert(true == TestLoadObj(argv[1], basepath));
1408 } else {
1409 //assert(true == TestLoadObj("cornell_box.obj"));
1410 //assert(true == TestLoadObj("cube.obj"));
1411 assert(true == TestStreamLoadObj());
1412 assert(true == TestLoadObj("catmark_torus_creases0.obj", NULL, false));
1413 }
1414
1415 return 0;
1416 }
1417 #endif
1418
1419 TEST_LIST = {
1420 {"cornell_box", test_cornell_box},
1421 {"catmark_torus_creases0", test_catmark_torus_creases0},
1422 {"pbr", test_pbr},
1423 {"stream_load", test_stream_load},
1424 {"stream_load_from_file_skipping_materials",
1425 test_stream_load_from_file_skipping_materials},
1426 {"stream_load_from_file_with_materials",
1427 test_stream_load_from_file_with_materials},
1428 {"trailing_whitespace_in_mtl_issue92",
1429 test_trailing_whitespace_in_mtl_issue92},
1430 {"transmittance_filter_issue95", test_transmittance_filter_issue95},
1431 {"transmittance_filter_Tf_issue95", test_transmittance_filter_Tf_issue95},
1432 {"transmittance_filter_Kt_issue95", test_transmittance_filter_Kt_issue95},
1433 {"usemtl_at_last_line_issue104", test_usemtl_at_last_line_issue104},
1434 {"texture_opts_issue85", test_texture_opts_issue85},
1435 {"mtllib_multiple_filenames_issue112",
1436 test_mtllib_multiple_filenames_issue112},
1437 {"tr_and_d_issue43", test_tr_and_d_issue43},
1438 {"refl", test_refl},
1439 {"map_bump", test_map_Bump},
1440 {"g_ignored_issue138", test_g_ignored_issue138},
1441 {"vertex_col_ext_issue144", test_vertex_col_ext_issue144},
1442 {"norm_texopts", test_norm_texopts},
1443 {"zero_face_idx_value_issue140", test_zero_face_idx_value_issue140},
1444 {"texture_name_whitespace_issue145", test_texture_name_whitespace_issue145},
1445 {"smoothing_group_issue162", test_smoothing_group_issue162},
1446 {"invalid_face_definition", test_invalid_face_definition},
1447 {"Empty_mtl_basedir_issue177", test_Empty_mtl_basedir_issue177},
1448 {"line_primitive", test_line_primitive},
1449 {"points_primitive", test_points_primitive},
1450 {"multiple_group_names", test_multiple_group_names},
1451 {"initialize_all_texopts", test_initialize_all_texopts},
1452 {"colorspace_issue184", test_colorspace_issue184},
1453 {"leading_decimal_dots_issue201", test_leading_decimal_dots_issue201},
1454 {"mtl_default_search_path_v2_API_issue208",
1455 test_mtl_default_search_path_v2_API_issue208},
1456 {"leading_zero_in_exponent_notation_issue210",
1457 test_leading_zero_in_exponent_notation_issue210},
1458 {"usemtl_then_o_issue235",
1459 test_usemtl_then_o_issue235},
1460 {"mtl_searchpaths_issue244",
1461 test_mtl_searchpaths_issue244},
1462 {"usemtl_whitespece_issue246",
1463 test_usemtl_whitespace_issue246},
1464 {"texres_texopt_issue248",
1465 test_texres_texopt_issue248},
1466 {"test_mtl_filename_with_whitespace_issue46",
1467 test_mtl_filename_with_whitespace_issue46},
1468 {"test_face_missing_issue295",
1469 test_face_missing_issue295},
1470 {NULL, NULL}};
1471