Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 059248f

Browse files
committed
Support multiple search paths(separated by ';' in Win32, ':' in Posix) for .mtl(v1 API). Fixes tinyobjloader#244
1 parent a5cd78e commit 059248f

File tree

4 files changed

+131
-12
lines changed

4 files changed

+131
-12
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# .mtl is located at tests/assets
2+
mtllib issue-244.mtl
3+
4+
v -1.000000 1.202466 1.000000
5+
v 1.000000 1.202466 1.000000
6+
v -1.000000 1.202466 -1.000000
7+
v 1.000000 1.202466 -1.000000
8+
vn 0.0000 1.0000 0.0000
9+
v -1.000000 0.000000 1.000000
10+
v 1.000000 0.000000 1.000000
11+
v -1.000000 0.000000 -1.000000
12+
v 1.000000 0.000000 -1.000000
13+
vn 0.0000 1.0000 0.0000
14+
15+
usemtl None
16+
o Plane.001
17+
f 1//1 2//1 4//1
18+
19+
# Following geometry is ignored without fix for #235
20+
usemtl None1
21+
o Plane
22+
f 5//2 6//2 8//2

tests/assets/issue-244.mtl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
newmtl None
2+
Ka 0 0 0
3+
Kd 0 0 1
4+
Ks 0 0 0
5+
6+
newmtl None1
7+
Ka 0 0 0
8+
Kd 1 0 0
9+
Ks 0 0 0
10+
11+

tests/tester.cc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,41 @@ void test_usemtl_then_o_issue235() {
12171217
TEST_CHECK(4 == shapes[1].mesh.indices[0].vertex_index);
12181218
}
12191219

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+
12201255
// Fuzzer test.
12211256
// Just check if it does not crash.
12221257
// Disable by default since Windows filesystem can't create filename of afl
@@ -1310,4 +1345,6 @@ TEST_LIST = {
13101345
test_leading_zero_in_exponent_notation_issue210},
13111346
{"usemtl_then_o_issue235",
13121347
test_usemtl_then_o_issue235},
1348+
{"mtl_searchpaths_issue244",
1349+
test_mtl_searchpaths_issue244},
13131350
{NULL, NULL}};

tiny_obj_loader.h

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ THE SOFTWARE.
2626
// version 2.0.0 : Add new object oriented API. 1.x API is still provided.
2727
// * Support line primitive.
2828
// * Support points primitive.
29+
// * Support multiple search path for .mtl(v1 API).
2930
// version 1.4.0 : Modifed ParseTextureNameAndOption API
3031
// version 1.3.1 : Make ParseTextureNameAndOption API public
3132
// version 1.3.0 : Separate warning and error message(breaking API of LoadObj)
@@ -436,6 +437,7 @@ class MaterialReader {
436437
///
437438
class MaterialFileReader : public MaterialReader {
438439
public:
440+
// Path could contain separator(';' in Windows, ':' in Posix)
439441
explicit MaterialFileReader(const std::string &mtl_basedir)
440442
: m_mtlBaseDir(mtl_basedir) {}
441443
virtual ~MaterialFileReader() {}
@@ -1634,6 +1636,21 @@ static void SplitString(const std::string &s, char delim,
16341636
}
16351637
}
16361638

1639+
static std::string JoinPath(const std::string &dir,
1640+
const std::string &filename) {
1641+
if (dir.empty()) {
1642+
return filename;
1643+
} else {
1644+
// check '/'
1645+
char lastChar = *dir.rbegin();
1646+
if (lastChar != '/') {
1647+
return dir + std::string("/") + filename;
1648+
} else {
1649+
return dir + filename;
1650+
}
1651+
}
1652+
}
1653+
16371654
void LoadMtl(std::map<std::string, int> *material_map,
16381655
std::vector<material_t> *materials, std::istream *inStream,
16391656
std::string *warning, std::string *err) {
@@ -2015,27 +2032,59 @@ bool MaterialFileReader::operator()(const std::string &matId,
20152032
std::vector<material_t> *materials,
20162033
std::map<std::string, int> *matMap,
20172034
std::string *warn, std::string *err) {
2018-
std::string filepath;
2019-
20202035
if (!m_mtlBaseDir.empty()) {
2021-
filepath = std::string(m_mtlBaseDir) + matId;
2022-
} else {
2023-
filepath = matId;
2024-
}
2036+
#if _WIN32
2037+
char sep = ';';
2038+
#else
2039+
char sep = ':';
2040+
#endif
2041+
2042+
// https://stackoverflow.com/questions/5167625/splitting-a-c-stdstring-using-tokens-e-g
2043+
std::vector<std::string> paths;
2044+
std::istringstream f(m_mtlBaseDir);
2045+
2046+
std::string s;
2047+
while (getline(f, s, sep)) {
2048+
paths.push_back(s);
2049+
}
2050+
2051+
for (size_t i = 0; i < paths.size(); i++) {
2052+
std::string filepath = JoinPath(paths[i], matId);
2053+
2054+
std::ifstream matIStream(filepath.c_str());
2055+
if (matIStream) {
2056+
LoadMtl(matMap, materials, &matIStream, warn, err);
2057+
2058+
return true;
2059+
}
2060+
}
20252061

2026-
std::ifstream matIStream(filepath.c_str());
2027-
if (!matIStream) {
20282062
std::stringstream ss;
2029-
ss << "Material file [ " << filepath << " ] not found." << std::endl;
2063+
ss << "Material file [ " << matId
2064+
<< " ] not found in a path : " << m_mtlBaseDir << std::endl;
20302065
if (warn) {
20312066
(*warn) += ss.str();
20322067
}
20332068
return false;
2034-
}
20352069

2036-
LoadMtl(matMap, materials, &matIStream, warn, err);
2070+
} else {
2071+
std::string filepath = matId;
2072+
std::ifstream matIStream(filepath.c_str());
2073+
if (matIStream) {
2074+
LoadMtl(matMap, materials, &matIStream, warn, err);
20372075

2038-
return true;
2076+
return true;
2077+
}
2078+
2079+
std::stringstream ss;
2080+
ss << "Material file [ " << filepath
2081+
<< " ] not found in a path : " << m_mtlBaseDir << std::endl;
2082+
if (warn) {
2083+
(*warn) += ss.str();
2084+
}
2085+
2086+
return false;
2087+
}
20392088
}
20402089

20412090
bool MaterialStreamReader::operator()(const std::string &matId,

0 commit comments

Comments
 (0)