@@ -501,6 +501,7 @@ class MaterialStreamReader : public MaterialReader {
501501// v2 API
502502struct ObjReaderConfig {
503503 bool triangulate; // triangulate polygon?
504+ bool triangulate_skip_quads; // Do not triangulate quads
504505
505506 // / Parse vertex color.
506507 // / If vertex color is not present, its filled with default value.
@@ -593,11 +594,12 @@ class ObjReader {
593594// / or not.
594595// / Option 'default_vcols_fallback' specifies whether vertex colors should
595596// / always be defined, even if no colors are given (fallback to white).
597+ // / 'triangulate_skip_quads' is optional, and can only be used together with the 'triangulate' option. It will not triangulate quads.
596598bool LoadObj (attrib_t *attrib, std::vector<shape_t > *shapes,
597599 std::vector<material_t > *materials, std::string *warn,
598600 std::string *err, const char *filename,
599601 const char *mtl_basedir = NULL , bool triangulate = true ,
600- bool default_vcols_fallback = true );
602+ bool default_vcols_fallback = true , bool triangulate_skip_quads = false );
601603
602604// / Loads .obj from a file with custom user callback.
603605// / .mtl is loaded as usual and parsed material_t data will be passed to
@@ -618,7 +620,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
618620 std::vector<material_t > *materials, std::string *warn,
619621 std::string *err, std::istream *inStream,
620622 MaterialReader *readMatFn = NULL , bool triangulate = true ,
621- bool default_vcols_fallback = true );
623+ bool default_vcols_fallback = true , bool triangulate_skip_quads = false );
622624
623625// / Loads materials into std::map
624626void LoadMtl (std::map<std::string, int > *material_map,
@@ -1366,7 +1368,7 @@ static int pnpoly(int nvert, T *vertx, T *verty, T testx, T testy) {
13661368static bool exportGroupsToShape (shape_t *shape, const PrimGroup &prim_group,
13671369 const std::vector<tag_t > &tags,
13681370 const int material_id, const std::string &name,
1369- bool triangulate,
1371+ bool triangulate, bool triangulate_skip_quads,
13701372 const std::vector<real_t > &v) {
13711373 if (prim_group.IsEmpty ()) {
13721374 return false ;
@@ -1391,7 +1393,8 @@ static bool exportGroupsToShape(shape_t *shape, const PrimGroup &prim_group,
13911393 vertex_index_t i1 (-1 );
13921394 vertex_index_t i2 = face.vertex_indices [1 ];
13931395
1394- if (triangulate) {
1396+ const bool do_triangulation = triangulate && (npolys > 4 || !triangulate_skip_quads);
1397+ if (do_triangulation) {
13951398 // find the two axes to work in
13961399 size_t axes[2 ] = {1 , 2 };
13971400 for (size_t k = 0 ; k < npolys; ++k) {
@@ -2174,7 +2177,7 @@ bool MaterialStreamReader::operator()(const std::string &matId,
21742177bool LoadObj (attrib_t *attrib, std::vector<shape_t > *shapes,
21752178 std::vector<material_t > *materials, std::string *warn,
21762179 std::string *err, const char *filename, const char *mtl_basedir,
2177- bool trianglulate, bool default_vcols_fallback) {
2180+ bool trianglulate, bool default_vcols_fallback, bool triangulate_skip_quads ) {
21782181 attrib->vertices .clear ();
21792182 attrib->normals .clear ();
21802183 attrib->texcoords .clear ();
@@ -2204,14 +2207,14 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
22042207 MaterialFileReader matFileReader (baseDir);
22052208
22062209 return LoadObj (attrib, shapes, materials, warn, err, &ifs, &matFileReader,
2207- trianglulate, default_vcols_fallback);
2210+ trianglulate, default_vcols_fallback, triangulate_skip_quads );
22082211}
22092212
22102213bool LoadObj (attrib_t *attrib, std::vector<shape_t > *shapes,
22112214 std::vector<material_t > *materials, std::string *warn,
22122215 std::string *err, std::istream *inStream,
22132216 MaterialReader *readMatFn /* = NULL*/ , bool triangulate,
2214- bool default_vcols_fallback) {
2217+ bool default_vcols_fallback, bool triangulate_skip_quads ) {
22152218 std::stringstream errss;
22162219
22172220 std::vector<real_t > v;
@@ -2485,7 +2488,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
24852488 // this time.
24862489 // just clear `faceGroup` after `exportGroupsToShape()` call.
24872490 exportGroupsToShape (&shape, prim_group, tags, material, name,
2488- triangulate, v);
2491+ triangulate, triangulate_skip_quads, v);
24892492 prim_group.faceGroup .clear ();
24902493 material = newMaterialId;
24912494 }
@@ -2548,7 +2551,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
25482551 if (token[0 ] == ' g' && IS_SPACE ((token[1 ]))) {
25492552 // flush previous face group.
25502553 bool ret = exportGroupsToShape (&shape, prim_group, tags, material, name,
2551- triangulate, v);
2554+ triangulate, triangulate_skip_quads, v);
25522555 (void )ret; // return value not used.
25532556
25542557 if (shape.mesh .indices .size () > 0 ) {
@@ -2600,7 +2603,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
26002603 if (token[0 ] == ' o' && IS_SPACE ((token[1 ]))) {
26012604 // flush previous face group.
26022605 bool ret = exportGroupsToShape (&shape, prim_group, tags, material, name,
2603- triangulate, v);
2606+ triangulate, triangulate_skip_quads, v);
26042607 (void )ret; // return value not used.
26052608
26062609 if (shape.mesh .indices .size () > 0 || shape.lines .indices .size () > 0 ||
@@ -2740,7 +2743,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
27402743 }
27412744
27422745 bool ret = exportGroupsToShape (&shape, prim_group, tags, material, name,
2743- triangulate, v);
2746+ triangulate, triangulate_skip_quads, v);
27442747 // exportGroupsToShape return false when `usemtl` is called in the last
27452748 // line.
27462749 // we also add `shape` to `shapes` when `shape.mesh` has already some
0 commit comments