Skip to content

Commit 1a7bdc6

Browse files
committed
Parse multiple group names. Fixes #146
1 parent fd06fa4 commit 1a7bdc6

File tree

3 files changed

+47
-15
lines changed

3 files changed

+47
-15
lines changed

models/cube.obj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ v 2.000000 2.000000 0.000000
1313
g front cube
1414
usemtl white
1515
f 1 2 3 4
16-
g back cube
16+
# two white spaces between 'back' and 'cube'
17+
g back cube
1718
# expects white material
1819
f 8 7 6 5
1920
g right cube

tests/tester.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,24 @@ TEST_CASE("line-primitive", "[line]") {
807807
REQUIRE(6 == shapes[0].path.indices.size());
808808
}
809809

810+
TEST_CASE("multiple-group-names", "[group]") {
811+
tinyobj::attrib_t attrib;
812+
std::vector<tinyobj::shape_t> shapes;
813+
std::vector<tinyobj::material_t> materials;
814+
815+
std::string err;
816+
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/cube.obj", gMtlBasePath);
817+
818+
if (!err.empty()) {
819+
std::cerr << "[group] " << err << std::endl;
820+
}
821+
822+
REQUIRE(true == ret);
823+
REQUIRE(6 == shapes.size());
824+
REQUIRE(0 == shapes[0].name.compare("front cube"));
825+
REQUIRE(0 == shapes[1].name.compare("back cube")); // multiple whitespaces are aggregated as single white space.
826+
}
827+
810828
// Fuzzer test.
811829
// Just check if it does not crash.
812830
// Disable by default since Windows filesystem can't create filename of afl testdata

tiny_obj_loader.h

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ THE SOFTWARE.
2323
*/
2424

2525
//
26+
// version 1.2.2 : Parse multiple group names.
2627
// version 1.2.1 : Added initial support for line('l') primitive(PR #178)
2728
// version 1.2.0 : Hardened implementation(#175)
2829
// version 1.1.1 : Support smoothing groups(#162)
@@ -1790,10 +1791,13 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
17901791

17911792
shape_t shape;
17921793

1794+
size_t line_num = 0;
17931795
std::string linebuf;
17941796
while (inStream->peek() != -1) {
17951797
safeGetline(*inStream, linebuf);
17961798

1799+
line_num++;
1800+
17971801
// Trim newline '\r\n' or '\n'
17981802
if (linebuf.size() > 0) {
17991803
if (linebuf[linebuf.size() - 1] == '\n')
@@ -2001,21 +2005,38 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
20012005
faceGroup.clear();
20022006

20032007
std::vector<std::string> names;
2004-
names.reserve(2);
20052008

20062009
while (!IS_NEW_LINE(token[0])) {
20072010
std::string str = parseString(&token);
20082011
names.push_back(str);
20092012
token += strspn(token, " \t\r"); // skip tag
20102013
}
20112014

2012-
assert(names.size() > 0);
2015+
// names[0] must be 'g'
20132016

2014-
// names[0] must be 'g', so skip the 0th element.
2015-
if (names.size() > 1) {
2016-
name = names[1];
2017+
if (names.size() < 2) {
2018+
// 'g' with empty names
2019+
if (err) {
2020+
std::stringstream ss;
2021+
ss << "WARN: Empty group name. line: " << line_num << "\n";
2022+
(*err) += ss.str();
2023+
name = "";
2024+
}
20172025
} else {
2018-
name = "";
2026+
2027+
std::stringstream ss;
2028+
ss << names[1];
2029+
2030+
// tinyobjloader does not support multiple groups for a primitive.
2031+
// Currently we concatinate multiple group names with a space to get
2032+
// single group name.
2033+
2034+
for (size_t i = 2; i < names.size(); i++) {
2035+
ss << " " << names[i];
2036+
}
2037+
2038+
name = ss.str();
2039+
20192040
}
20202041

20212042
continue;
@@ -2169,7 +2190,6 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
21692190
std::vector<material_t> materials;
21702191
std::vector<std::string> names;
21712192
names.reserve(2);
2172-
std::string name;
21732193
std::vector<const char *> names_out;
21742194

21752195
std::string linebuf;
@@ -2346,13 +2366,6 @@ bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback,
23462366

23472367
assert(names.size() > 0);
23482368

2349-
// names[0] must be 'g', so skip the 0th element.
2350-
if (names.size() > 1) {
2351-
name = names[1];
2352-
} else {
2353-
name.clear();
2354-
}
2355-
23562369
if (callback.group_cb) {
23572370
if (names.size() > 1) {
23582371
// create const char* array.

0 commit comments

Comments
 (0)