Change API and handle no-mtl-file case correctly. Fixes #58.

This commit is contained in:
Syoyo Fujita
2015-11-07 23:08:39 +09:00
parent 475bc83ef3
commit e7e7eed616
7 changed files with 500 additions and 50 deletions

View File

@@ -86,9 +86,12 @@ main(
for (int i = 0; i < num_objfiles; i++) { for (int i = 0; i < num_objfiles; i++) {
std::cout << "Loading " << argv[i+1] << " ... " << std::flush; std::cout << "Loading " << argv[i+1] << " ... " << std::flush;
std::string err = tinyobj::LoadObj(shapes[i], materials[i], argv[i+1]); std::string err;
bool ret = tinyobj::LoadObj(shapes[i], materials[i], err, argv[i+1]);
if (!err.empty()) { if (!err.empty()) {
std::cerr << err << std::endl; std::cerr << err << std::endl;
}
if (!ret) {
exit(1); exit(1);
} }

145
missing_material_file.obj Normal file
View File

@@ -0,0 +1,145 @@
# cornell_box.obj and cornell_box.mtl are grabbed from Intel's embree project.
# original cornell box data
# comment
# empty line including some space
#mtllib no_material.mtl
o floor
usemtl white
v 552.8 0.0 0.0
v 0.0 0.0 0.0
v 0.0 0.0 559.2
v 549.6 0.0 559.2
v 130.0 0.0 65.0
v 82.0 0.0 225.0
v 240.0 0.0 272.0
v 290.0 0.0 114.0
v 423.0 0.0 247.0
v 265.0 0.0 296.0
v 314.0 0.0 456.0
v 472.0 0.0 406.0
f 1 2 3 4
f 8 7 6 5
f 12 11 10 9
o light
usemtl light
v 343.0 548.0 227.0
v 343.0 548.0 332.0
v 213.0 548.0 332.0
v 213.0 548.0 227.0
f -4 -3 -2 -1
o ceiling
usemtl white
v 556.0 548.8 0.0
v 556.0 548.8 559.2
v 0.0 548.8 559.2
v 0.0 548.8 0.0
f -4 -3 -2 -1
o back_wall
usemtl white
v 549.6 0.0 559.2
v 0.0 0.0 559.2
v 0.0 548.8 559.2
v 556.0 548.8 559.2
f -4 -3 -2 -1
o front_wall
usemtl blue
v 549.6 0.0 0
v 0.0 0.0 0
v 0.0 548.8 0
v 556.0 548.8 0
#f -1 -2 -3 -4
o green_wall
usemtl green
v 0.0 0.0 559.2
v 0.0 0.0 0.0
v 0.0 548.8 0.0
v 0.0 548.8 559.2
f -4 -3 -2 -1
o red_wall
usemtl red
v 552.8 0.0 0.0
v 549.6 0.0 559.2
v 556.0 548.8 559.2
v 556.0 548.8 0.0
f -4 -3 -2 -1
o short_block
usemtl white
v 130.0 165.0 65.0
v 82.0 165.0 225.0
v 240.0 165.0 272.0
v 290.0 165.0 114.0
f -4 -3 -2 -1
v 290.0 0.0 114.0
v 290.0 165.0 114.0
v 240.0 165.0 272.0
v 240.0 0.0 272.0
f -4 -3 -2 -1
v 130.0 0.0 65.0
v 130.0 165.0 65.0
v 290.0 165.0 114.0
v 290.0 0.0 114.0
f -4 -3 -2 -1
v 82.0 0.0 225.0
v 82.0 165.0 225.0
v 130.0 165.0 65.0
v 130.0 0.0 65.0
f -4 -3 -2 -1
v 240.0 0.0 272.0
v 240.0 165.0 272.0
v 82.0 165.0 225.0
v 82.0 0.0 225.0
f -4 -3 -2 -1
o tall_block
usemtl white
v 423.0 330.0 247.0
v 265.0 330.0 296.0
v 314.0 330.0 456.0
v 472.0 330.0 406.0
f -4 -3 -2 -1
usemtl white
v 423.0 0.0 247.0
v 423.0 330.0 247.0
v 472.0 330.0 406.0
v 472.0 0.0 406.0
f -4 -3 -2 -1
v 472.0 0.0 406.0
v 472.0 330.0 406.0
v 314.0 330.0 456.0
v 314.0 0.0 456.0
f -4 -3 -2 -1
v 314.0 0.0 456.0
v 314.0 330.0 456.0
v 265.0 330.0 296.0
v 265.0 0.0 296.0
f -4 -3 -2 -1
v 265.0 0.0 296.0
v 265.0 330.0 296.0
v 423.0 330.0 247.0
v 423.0 0.0 247.0
f -4 -3 -2 -1

133
no_material.obj Normal file
View File

@@ -0,0 +1,133 @@
# cornell_box.obj and cornell_box.mtl are grabbed from Intel's embree project.
# original cornell box data
# comment
# empty line including some space
o floor
v 552.8 0.0 0.0
v 0.0 0.0 0.0
v 0.0 0.0 559.2
v 549.6 0.0 559.2
v 130.0 0.0 65.0
v 82.0 0.0 225.0
v 240.0 0.0 272.0
v 290.0 0.0 114.0
v 423.0 0.0 247.0
v 265.0 0.0 296.0
v 314.0 0.0 456.0
v 472.0 0.0 406.0
f 1 2 3 4
f 8 7 6 5
f 12 11 10 9
o light
v 343.0 548.0 227.0
v 343.0 548.0 332.0
v 213.0 548.0 332.0
v 213.0 548.0 227.0
f -4 -3 -2 -1
o ceiling
v 556.0 548.8 0.0
v 556.0 548.8 559.2
v 0.0 548.8 559.2
v 0.0 548.8 0.0
f -4 -3 -2 -1
o back_wall
v 549.6 0.0 559.2
v 0.0 0.0 559.2
v 0.0 548.8 559.2
v 556.0 548.8 559.2
f -4 -3 -2 -1
o front_wall
v 549.6 0.0 0
v 0.0 0.0 0
v 0.0 548.8 0
v 556.0 548.8 0
#f -1 -2 -3 -4
o green_wall
v 0.0 0.0 559.2
v 0.0 0.0 0.0
v 0.0 548.8 0.0
v 0.0 548.8 559.2
f -4 -3 -2 -1
o red_wall
v 552.8 0.0 0.0
v 549.6 0.0 559.2
v 556.0 548.8 559.2
v 556.0 548.8 0.0
f -4 -3 -2 -1
o short_block
v 130.0 165.0 65.0
v 82.0 165.0 225.0
v 240.0 165.0 272.0
v 290.0 165.0 114.0
f -4 -3 -2 -1
v 290.0 0.0 114.0
v 290.0 165.0 114.0
v 240.0 165.0 272.0
v 240.0 0.0 272.0
f -4 -3 -2 -1
v 130.0 0.0 65.0
v 130.0 165.0 65.0
v 290.0 165.0 114.0
v 290.0 0.0 114.0
f -4 -3 -2 -1
v 82.0 0.0 225.0
v 82.0 165.0 225.0
v 130.0 165.0 65.0
v 130.0 0.0 65.0
f -4 -3 -2 -1
v 240.0 0.0 272.0
v 240.0 165.0 272.0
v 82.0 165.0 225.0
v 82.0 0.0 225.0
f -4 -3 -2 -1
o tall_block
v 423.0 330.0 247.0
v 265.0 330.0 296.0
v 314.0 330.0 456.0
v 472.0 330.0 406.0
f -4 -3 -2 -1
v 423.0 0.0 247.0
v 423.0 330.0 247.0
v 472.0 330.0 406.0
v 472.0 0.0 406.0
f -4 -3 -2 -1
v 472.0 0.0 406.0
v 472.0 330.0 406.0
v 314.0 330.0 456.0
v 314.0 0.0 456.0
f -4 -3 -2 -1
v 314.0 0.0 456.0
v 314.0 330.0 456.0
v 265.0 330.0 296.0
v 265.0 0.0 296.0
f -4 -3 -2 -1
v 265.0 0.0 296.0
v 265.0 330.0 296.0
v 423.0 330.0 247.0
v 423.0 0.0 247.0
f -4 -3 -2 -1

145
test-nan.obj Normal file
View File

@@ -0,0 +1,145 @@
# cornell_box.obj and cornell_box.mtl are grabbed from Intel's embree project.
# original cornell box data
# comment
# empty line including some space
mtllib cornell_box.mtl
o floor
usemtl white
v nan -nan nan
v inf -inf inf
v 1.#IND -1.#IND 1.#IND
v 1.#INF -1.#INF 1.#INF
v 130.0 0.0 65.0
v 82.0 0.0 225.0
v 240.0 0.0 272.0
v 290.0 0.0 114.0
v 423.0 0.0 247.0
v 265.0 0.0 296.0
v 314.0 0.0 456.0
v 472.0 0.0 406.0
f 1 2 3 4
f 8 7 6 5
f 12 11 10 9
o light
usemtl light
v 343.0 548.0 227.0
v 343.0 548.0 332.0
v 213.0 548.0 332.0
v 213.0 548.0 227.0
f -4 -3 -2 -1
o ceiling
usemtl white
v 556.0 548.8 0.0
v 556.0 548.8 559.2
v 0.0 548.8 559.2
v 0.0 548.8 0.0
f -4 -3 -2 -1
o back_wall
usemtl white
v 549.6 0.0 559.2
v 0.0 0.0 559.2
v 0.0 548.8 559.2
v 556.0 548.8 559.2
f -4 -3 -2 -1
o front_wall
usemtl blue
v 549.6 0.0 0
v 0.0 0.0 0
v 0.0 548.8 0
v 556.0 548.8 0
#f -1 -2 -3 -4
o green_wall
usemtl green
v 0.0 0.0 559.2
v 0.0 0.0 0.0
v 0.0 548.8 0.0
v 0.0 548.8 559.2
f -4 -3 -2 -1
o red_wall
usemtl red
v 552.8 0.0 0.0
v 549.6 0.0 559.2
v 556.0 548.8 559.2
v 556.0 548.8 0.0
f -4 -3 -2 -1
o short_block
usemtl white
v 130.0 165.0 65.0
v 82.0 165.0 225.0
v 240.0 165.0 272.0
v 290.0 165.0 114.0
f -4 -3 -2 -1
v 290.0 0.0 114.0
v 290.0 165.0 114.0
v 240.0 165.0 272.0
v 240.0 0.0 272.0
f -4 -3 -2 -1
v 130.0 0.0 65.0
v 130.0 165.0 65.0
v 290.0 165.0 114.0
v 290.0 0.0 114.0
f -4 -3 -2 -1
v 82.0 0.0 225.0
v 82.0 165.0 225.0
v 130.0 165.0 65.0
v 130.0 0.0 65.0
f -4 -3 -2 -1
v 240.0 0.0 272.0
v 240.0 165.0 272.0
v 82.0 165.0 225.0
v 82.0 0.0 225.0
f -4 -3 -2 -1
o tall_block
usemtl white
v 423.0 330.0 247.0
v 265.0 330.0 296.0
v 314.0 330.0 456.0
v 472.0 330.0 406.0
f -4 -3 -2 -1
usemtl white
v 423.0 0.0 247.0
v 423.0 330.0 247.0
v 472.0 330.0 406.0
v 472.0 0.0 406.0
f -4 -3 -2 -1
v 472.0 0.0 406.0
v 472.0 330.0 406.0
v 314.0 330.0 456.0
v 314.0 0.0 456.0
f -4 -3 -2 -1
v 314.0 0.0 456.0
v 314.0 330.0 456.0
v 265.0 330.0 296.0
v 265.0 0.0 296.0
f -4 -3 -2 -1
v 265.0 0.0 296.0
v 265.0 330.0 296.0
v 423.0 330.0 247.0
v 423.0 0.0 247.0
f -4 -3 -2 -1

21
test.cc
View File

@@ -67,10 +67,15 @@ TestLoadObj(
std::vector<tinyobj::shape_t> shapes; std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials; std::vector<tinyobj::material_t> materials;
std::string err = tinyobj::LoadObj(shapes, materials, filename, basepath);
std::string err;
bool ret = tinyobj::LoadObj(shapes, materials, err, filename, basepath);
if (!err.empty()) { if (!err.empty()) {
std::cerr << err << std::endl; std::cerr << err << std::endl;
}
if (!ret) {
return false; return false;
} }
@@ -152,12 +157,14 @@ std::string matStream(
public: public:
MaterialStringStreamReader(const std::string& matSStream): m_matSStream(matSStream) {} MaterialStringStreamReader(const std::string& matSStream): m_matSStream(matSStream) {}
virtual ~MaterialStringStreamReader() {} virtual ~MaterialStringStreamReader() {}
virtual std::string operator() ( virtual bool operator() (
const std::string& matId, const std::string& matId,
std::vector<material_t>& materials, std::vector<material_t>& materials,
std::map<std::string, int>& matMap) std::map<std::string, int>& matMap,
std::string& err)
{ {
return LoadMtl(matMap, materials, m_matSStream); LoadMtl(matMap, materials, m_matSStream);
return true;
} }
private: private:
@@ -167,10 +174,14 @@ std::string matStream(
MaterialStringStreamReader matSSReader(matStream); MaterialStringStreamReader matSSReader(matStream);
std::vector<tinyobj::shape_t> shapes; std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials; std::vector<tinyobj::material_t> materials;
std::string err = tinyobj::LoadObj(shapes, materials, objStream, matSSReader); std::string err;
bool ret = tinyobj::LoadObj(shapes, materials, err, objStream, matSSReader);
if (!err.empty()) { if (!err.empty()) {
std::cerr << err << std::endl; std::cerr << err << std::endl;
}
if (!ret) {
return false; return false;
} }

View File

@@ -5,6 +5,7 @@
// //
// //
// version 0.9.15: Change API to handle no mtl file case correctly(#58)
// version 0.9.14: Support specular highlight, bump, displacement and alpha map(#53) // version 0.9.14: Support specular highlight, bump, displacement and alpha map(#53)
// version 0.9.13: Report "Material file not found message" in `err`(#46) // version 0.9.13: Report "Material file not found message" in `err`(#46)
// version 0.9.12: Fix groups being ignored if they have 'usemtl' just before 'g' (#44) // version 0.9.12: Fix groups being ignored if they have 'usemtl' just before 'g' (#44)
@@ -415,10 +416,9 @@ static bool exportFaceGroupToShape(
return true; return true;
} }
std::string LoadMtl(std::map<std::string, int> &material_map, void LoadMtl(std::map<std::string, int> &material_map,
std::vector<material_t> &materials, std::vector<material_t> &materials,
std::istream &inStream) { std::istream &inStream) {
std::stringstream err;
// Create a default material anyway. // Create a default material anyway.
material_t material; material_t material;
@@ -643,13 +643,12 @@ std::string LoadMtl(std::map<std::string, int> &material_map,
material_map.insert( material_map.insert(
std::pair<std::string, int>(material.name, static_cast<int>(materials.size()))); std::pair<std::string, int>(material.name, static_cast<int>(materials.size())));
materials.push_back(material); materials.push_back(material);
return err.str();
} }
std::string MaterialFileReader::operator()(const std::string &matId, bool MaterialFileReader::operator()(const std::string &matId,
std::vector<material_t> &materials, std::vector<material_t> &materials,
std::map<std::string, int> &matMap) { std::map<std::string, int> &matMap,
std::string& err) {
std::string filepath; std::string filepath;
if (!m_mtlBasePath.empty()) { if (!m_mtlBasePath.empty()) {
@@ -659,27 +658,29 @@ std::string MaterialFileReader::operator()(const std::string &matId,
} }
std::ifstream matIStream(filepath.c_str()); std::ifstream matIStream(filepath.c_str());
std::string err = LoadMtl(matMap, materials, matIStream); LoadMtl(matMap, materials, matIStream);
if (!matIStream) { if (!matIStream) {
std::stringstream ss; std::stringstream ss;
ss << "WARN: Material file [ " << filepath << " ] not found. Created a default material."; ss << "WARN: Material file [ " << filepath << " ] not found. Created a default material.";
err += ss.str(); err += ss.str();
} }
return err; return true;
} }
std::string LoadObj(std::vector<shape_t> &shapes, bool LoadObj(std::vector<shape_t> &shapes, // [output]
std::vector<material_t> &materials, // [output] std::vector<material_t> &materials, // [output]
const char *filename, const char *mtl_basepath) { std::string &err,
const char *filename, const char *mtl_basepath) {
shapes.clear(); shapes.clear();
std::stringstream err; std::stringstream errss;
std::ifstream ifs(filename); std::ifstream ifs(filename);
if (!ifs) { if (!ifs) {
err << "Cannot open file [" << filename << "]" << std::endl; errss << "Cannot open file [" << filename << "]" << std::endl;
return err.str(); err = errss.str();
return false;
} }
std::string basePath; std::string basePath;
@@ -688,13 +689,14 @@ std::string LoadObj(std::vector<shape_t> &shapes,
} }
MaterialFileReader matFileReader(basePath); MaterialFileReader matFileReader(basePath);
return LoadObj(shapes, materials, ifs, matFileReader); return LoadObj(shapes, materials, err, ifs, matFileReader);
} }
std::string LoadObj(std::vector<shape_t> &shapes, bool LoadObj(std::vector<shape_t> &shapes, // [output]
std::vector<material_t> &materials, // [output] std::vector<material_t> &materials, // [output]
std::istream &inStream, MaterialReader &readMatFn) { std::string& err,
std::stringstream err; std::istream &inStream, MaterialReader &readMatFn) {
std::stringstream errss;
std::vector<float> v; std::vector<float> v;
std::vector<float> vn; std::vector<float> vn;
@@ -833,10 +835,13 @@ std::string LoadObj(std::vector<shape_t> &shapes,
sscanf(token, "%s", namebuf); sscanf(token, "%s", namebuf);
#endif #endif
std::string err_mtl = readMatFn(namebuf, materials, material_map); std::string err_mtl;
if (!err_mtl.empty()) { bool ok = readMatFn(namebuf, materials, material_map, err_mtl);
err += err_mtl;
if (!ok) {
faceGroup.clear(); // for safety faceGroup.clear(); // for safety
return err_mtl; return false;
} }
continue; continue;
@@ -913,6 +918,8 @@ std::string LoadObj(std::vector<shape_t> &shapes,
} }
faceGroup.clear(); // for safety faceGroup.clear(); // for safety
return err.str(); err += errss.str();
} return true;
} }
} // namespace

View File

@@ -54,9 +54,10 @@ public:
MaterialReader() {} MaterialReader() {}
virtual ~MaterialReader() {} virtual ~MaterialReader() {}
virtual std::string operator()(const std::string &matId, virtual bool operator()(const std::string &matId,
std::vector<material_t> &materials, std::vector<material_t> &materials,
std::map<std::string, int> &matMap) = 0; std::map<std::string, int> &matMap,
std::string &err) = 0;
}; };
class MaterialFileReader : public MaterialReader { class MaterialFileReader : public MaterialReader {
@@ -64,9 +65,10 @@ public:
MaterialFileReader(const std::string &mtl_basepath) MaterialFileReader(const std::string &mtl_basepath)
: m_mtlBasePath(mtl_basepath) {} : m_mtlBasePath(mtl_basepath) {}
virtual ~MaterialFileReader() {} virtual ~MaterialFileReader() {}
virtual std::string operator()(const std::string &matId, virtual bool operator()(const std::string &matId,
std::vector<material_t> &materials, std::vector<material_t> &materials,
std::map<std::string, int> &matMap); std::map<std::string, int> &matMap,
std::string &err);
private: private:
std::string m_mtlBasePath; std::string m_mtlBasePath;
@@ -75,23 +77,27 @@ private:
/// Loads .obj from a file. /// Loads .obj from a file.
/// 'shapes' will be filled with parsed shape data /// 'shapes' will be filled with parsed shape data
/// The function returns error string. /// The function returns error string.
/// Returns empty string when loading .obj success. /// Returns true when loading .obj become success.
/// Returns warning and error message into `err`
/// 'mtl_basepath' is optional, and used for base path for .mtl file. /// 'mtl_basepath' is optional, and used for base path for .mtl file.
std::string LoadObj(std::vector<shape_t> &shapes, // [output] bool LoadObj(std::vector<shape_t> &shapes, // [output]
std::vector<material_t> &materials, // [output] std::vector<material_t> &materials, // [output]
const char *filename, const char *mtl_basepath = NULL); std::string& err, // [output]
const char *filename, const char *mtl_basepath = NULL);
/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve /// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve
/// std::istream for materials. /// std::istream for materials.
/// Returns empty string when loading .obj success. /// Returns true when loading .obj become success.
std::string LoadObj(std::vector<shape_t> &shapes, // [output] /// Returns warning and error message into `err`
std::vector<material_t> &materials, // [output] bool LoadObj(std::vector<shape_t> &shapes, // [output]
std::istream &inStream, MaterialReader &readMatFn); std::vector<material_t> &materials, // [output]
std::string& err, // [output]
std::istream &inStream, MaterialReader &readMatFn);
/// Loads materials into std::map /// Loads materials into std::map
/// Returns an empty string if successful void LoadMtl(std::map<std::string, int> &material_map, // [output]
std::string LoadMtl(std::map<std::string, int> &material_map, std::vector<material_t> &materials, // [output]
std::vector<material_t> &materials, std::istream &inStream); std::istream &inStream);
} }
#endif // _TINY_OBJ_LOADER_H #endif // _TINY_OBJ_LOADER_H