diff --git a/experimental/tinyobj_loader_opt.h b/experimental/tinyobj_loader_opt.h index c7175e3..c926245 100644 --- a/experimental/tinyobj_loader_opt.h +++ b/experimental/tinyobj_loader_opt.h @@ -1492,7 +1492,7 @@ bool parseObj(attrib_t *attrib, std::vector *shapes, attrib->texcoords.resize(num_vt * 2); attrib->indices.resize(num_f); attrib->face_num_verts.resize(num_indices); - attrib->material_ids.resize(num_indices); + attrib->material_ids.resize(num_indices, -1); size_t v_offsets[kMaxThreads]; size_t n_offsets[kMaxThreads]; @@ -1523,22 +1523,44 @@ bool parseObj(attrib_t *attrib, std::vector *shapes, size_t t_count = t_offsets[t]; size_t f_count = f_offsets[t]; size_t face_count = face_offsets[t]; - int material_id = -1; // -1 = default unknown material. + int material_id = -1; // -1 = default unknown material. for (size_t i = 0; i < commands[t].size(); i++) { if (commands[t][i].type == COMMAND_EMPTY) { continue; } else if (commands[t][i].type == COMMAND_USEMTL) { if (commands[t][i].material_name && - commands[t][i].material_name_len > 0) { - std::string material_name(commands[t][i].material_name, - commands[t][i].material_name_len); - - if (material_map.find(material_name) != material_map.end()) { - material_id = material_map[material_name]; - } else { - // Assign invalid material ID - material_id = -1; + commands[t][i].material_name_len > 0 && + // check if there are still faces after this command + face_count < num_indices) { + // Find next face + bool found = false; + size_t i_start = i + 1, t_next, i_next; + for (t_next = t; t_next < num_threads; t_next++) { + for (i_next = i_start; i_next < commands[t_next].size(); i_next++) { + if (commands[t_next][i_next].type == COMMAND_F) { + found = true; + break; + } + } + if (found) + break; + i_start = 0; + } + // Assign material to this face + if (found) { + std::string material_name(commands[t][i].material_name, + commands[t][i].material_name_len); + for (size_t k = 0; k < commands[t_next][i_next].f_num_verts.size(); k++) { + if (material_map.find(material_name) != material_map.end()) { + attrib->material_ids[face_count + k] = material_map[material_name]; + } else { + // Assign invalid material ID + // Set a different value than the default, to + // prevent following faces from being assigned a valid material + attrib->material_ids[face_count + k] = -2; + } + } } } } else if (commands[t][i].type == COMMAND_V) { @@ -1565,7 +1587,6 @@ bool parseObj(attrib_t *attrib, std::vector *shapes, index_t(vertex_index, texcoord_index, normal_index); } for (size_t k = 0; k < commands[t][i].f_num_verts.size(); k++) { - attrib->material_ids[face_count + k] = material_id; attrib->face_num_verts[face_count + k] = commands[t][i].f_num_verts[k]; } @@ -1580,19 +1601,13 @@ bool parseObj(attrib_t *attrib, std::vector *shapes, for (size_t t = 0; t < workers->size(); t++) { workers[t].join(); } - if(material_map.size()>1&& num_threads>1) { - for (size_t t = 0; t < num_threads; t++) { - size_t face_count = face_offsets[t]; - if (-1 == attrib->material_ids[face_count]) { - int prev_material_id = attrib->material_ids[face_count - 1]; - size_t max_face_offset = (t == num_threads - 1) ? attrib->material_ids.size() : face_offsets[t + 1]; - for (int i = face_count; imaterial_ids[i] != -1) break; - attrib->material_ids[i] = prev_material_id; - } - } - } - } + + // To each face with uninitialized material id, + // assign the material id of the last face preceding it that has one + for (size_t face_count = 1; face_count < num_indices; ++face_count) + if (attrib->material_ids[face_count] == -1) + attrib->material_ids[face_count] = attrib->material_ids[face_count - 1]; + auto t_end = std::chrono::high_resolution_clock::now(); ms_merge = t_end - t_start; }