diff options
Diffstat (limited to 'source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc')
-rw-r--r-- | source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc | 137 |
1 files changed, 98 insertions, 39 deletions
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc index a32fd90594d..7d5f023af4b 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc @@ -10,9 +10,11 @@ #include "BLI_string_ref.hh" #include "BLI_vector.hh" +#include "obj_export_mtl.hh" #include "obj_import_file_reader.hh" #include "obj_import_string_utils.hh" +#include <algorithm> #include <charconv> namespace blender::io::obj { @@ -101,10 +103,10 @@ static void geom_add_mrgb_colors(const char *p, const char *end, GlobalVertices while (p + mrgb_length <= end) { uint32_t value = 0; std::from_chars_result res = std::from_chars(p, p + mrgb_length, value, 16); - if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) { + if (ELEM(res.ec, std::errc::invalid_argument, std::errc::result_out_of_range)) { return; } - unsigned char srgb[4]; + uchar srgb[4]; srgb[0] = (value >> 16) & 0xFF; srgb[1] = (value >> 8) & 0xFF; srgb[2] = value & 0xFF; @@ -162,7 +164,7 @@ static void geom_add_edge(Geometry *geom, edge_v1 += edge_v1 < 0 ? r_global_vertices.vertices.size() : -1; edge_v2 += edge_v2 < 0 ? r_global_vertices.vertices.size() : -1; BLI_assert(edge_v1 >= 0 && edge_v2 >= 0); - geom->edges_.append({static_cast<uint>(edge_v1), static_cast<uint>(edge_v2)}); + geom->edges_.append({uint(edge_v1), uint(edge_v2)}); geom->track_vertex_index(edge_v1); geom->track_vertex_index(edge_v2); } @@ -214,7 +216,7 @@ static void geom_add_polygon(Geometry *geom, fprintf(stderr, "Invalid vertex index %i (valid range [0, %zu)), ignoring face\n", corner.vert_index, - (size_t)global_vertices.vertices.size()); + size_t(global_vertices.vertices.size())); face_valid = false; } else { @@ -226,7 +228,7 @@ static void geom_add_polygon(Geometry *geom, fprintf(stderr, "Invalid UV index %i (valid range [0, %zu)), ignoring face\n", corner.uv_vert_index, - (size_t)global_vertices.uv_vertices.size()); + size_t(global_vertices.uv_vertices.size())); face_valid = false; } } @@ -242,7 +244,7 @@ static void geom_add_polygon(Geometry *geom, fprintf(stderr, "Invalid normal index %i (valid range [0, %zu)), ignoring face\n", corner.vertex_normal_index, - (size_t)global_vertices.vertex_normals.size()); + size_t(global_vertices.vertex_normals.size())); face_valid = false; } } @@ -394,6 +396,22 @@ static bool parse_keyword(const char *&p, const char *end, StringRef keyword) return true; } +/* Special case: if there were no faces/edges in any geometries, + * treat all the vertices as a point cloud. */ +static void use_all_vertices_if_no_faces(Geometry *geom, + const Vector<std::unique_ptr<Geometry>> &all_geometries, + const GlobalVertices &global_vertices) +{ + if (!global_vertices.vertices.is_empty() && geom && geom->geom_type_ == GEOM_MESH) { + if (std::all_of( + all_geometries.begin(), all_geometries.end(), [](const std::unique_ptr<Geometry> &g) { + return g->get_vertex_count() == 0; + })) { + geom->track_all_vertices(global_vertices.vertices.size()); + } + } +} + void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, GlobalVertices &r_global_vertices) { @@ -467,7 +485,7 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, /* Parse the buffer (until last newline) that we have so far, * line by line. */ - StringRef buffer_str{buffer.data(), (int64_t)last_nl}; + StringRef buffer_str{buffer.data(), int64_t(last_nl)}; while (!buffer_str.is_empty()) { StringRef line = read_next_line(buffer_str); const char *p = line.begin(), *end = line.end(); @@ -490,6 +508,15 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, } /* Faces. */ else if (parse_keyword(p, end, "f")) { + /* If we don't have a material index assigned yet, get one. + * It means "usemtl" state came from the previous object. */ + if (state_material_index == -1 && !state_material_name.empty() && + curr_geom->material_indices_.is_empty()) { + curr_geom->material_indices_.add_new(state_material_name, 0); + curr_geom->material_order_.append(state_material_name); + state_material_index = 0; + } + geom_add_polygon(curr_geom, p, end, @@ -506,7 +533,10 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, else if (parse_keyword(p, end, "o")) { state_shaded_smooth = false; state_group_name = ""; - state_material_name = ""; + /* Reset object-local material index that's used in face infos. + * NOTE: do not reset the material name; that has to carry over + * into the next object if needed. */ + state_material_index = -1; curr_geom = create_geometry( curr_geom, GEOM_MESH, StringRef(p, end).trim(), r_all_geometries); } @@ -571,39 +601,44 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries, buffer_offset = left_size; } + use_all_vertices_if_no_faces(curr_geom, r_all_geometries, r_global_vertices); add_default_mtl_library(); } -static eMTLSyntaxElement mtl_line_start_to_enum(const char *&p, const char *end) +static MTLTexMapType mtl_line_start_to_texture_type(const char *&p, const char *end) { if (parse_keyword(p, end, "map_Kd")) { - return eMTLSyntaxElement::map_Kd; + return MTLTexMapType::Color; } if (parse_keyword(p, end, "map_Ks")) { - return eMTLSyntaxElement::map_Ks; + return MTLTexMapType::Specular; } if (parse_keyword(p, end, "map_Ns")) { - return eMTLSyntaxElement::map_Ns; + return MTLTexMapType::SpecularExponent; } if (parse_keyword(p, end, "map_d")) { - return eMTLSyntaxElement::map_d; + return MTLTexMapType::Alpha; } - if (parse_keyword(p, end, "refl")) { - return eMTLSyntaxElement::map_refl; - } - if (parse_keyword(p, end, "map_refl")) { - return eMTLSyntaxElement::map_refl; + if (parse_keyword(p, end, "refl") || parse_keyword(p, end, "map_refl")) { + return MTLTexMapType::Reflection; } if (parse_keyword(p, end, "map_Ke")) { - return eMTLSyntaxElement::map_Ke; + return MTLTexMapType::Emission; + } + if (parse_keyword(p, end, "bump") || parse_keyword(p, end, "map_Bump") || + parse_keyword(p, end, "map_bump")) { + return MTLTexMapType::Normal; } - if (parse_keyword(p, end, "bump")) { - return eMTLSyntaxElement::map_Bump; + if (parse_keyword(p, end, "map_Pr")) { + return MTLTexMapType::Roughness; } - if (parse_keyword(p, end, "map_Bump") || parse_keyword(p, end, "map_bump")) { - return eMTLSyntaxElement::map_Bump; + if (parse_keyword(p, end, "map_Pm")) { + return MTLTexMapType::Metallic; } - return eMTLSyntaxElement::string; + if (parse_keyword(p, end, "map_Ps")) { + return MTLTexMapType::Sheen; + } + return MTLTexMapType::Count; } static const std::pair<StringRef, int> unsupported_texture_options[] = { @@ -621,7 +656,7 @@ static const std::pair<StringRef, int> unsupported_texture_options[] = { static bool parse_texture_option(const char *&p, const char *end, MTLMaterial *material, - tex_map_XX &tex_map) + MTLTexMap &tex_map) { p = drop_whitespace(p, end); if (parse_keyword(p, end, "-o")) { @@ -633,7 +668,7 @@ static bool parse_texture_option(const char *&p, return true; } if (parse_keyword(p, end, "-bm")) { - p = parse_float(p, end, 1.0f, material->map_Bump_strength, true, true); + p = parse_float(p, end, 1.0f, material->normal_strength, true, true); return true; } if (parse_keyword(p, end, "-type")) { @@ -675,13 +710,13 @@ static void parse_texture_map(const char *p, if (!is_map && !is_refl && !is_bump) { return; } - eMTLSyntaxElement key = mtl_line_start_to_enum(p, end); - if (key == eMTLSyntaxElement::string || !material->texture_maps.contains(key)) { + MTLTexMapType key = mtl_line_start_to_texture_type(p, end); + if (key == MTLTexMapType::Count) { /* No supported texture map found. */ std::cerr << "OBJ import: MTL texture map type not supported: '" << line << "'" << std::endl; return; } - tex_map_XX &tex_map = material->texture_maps.lookup(key); + MTLTexMap &tex_map = material->tex_map_of_type(key); tex_map.mtl_dir_path = mtl_dir_path; /* Parse texture map options. */ @@ -730,7 +765,7 @@ MTLParser::MTLParser(StringRefNull mtl_library, StringRefNull obj_filepath) { char obj_file_dir[FILE_MAXDIR]; BLI_split_dir_part(obj_filepath.data(), obj_file_dir, FILE_MAXDIR); - BLI_path_join(mtl_file_path_, FILE_MAX, obj_file_dir, mtl_library.data(), NULL); + BLI_path_join(mtl_file_path_, FILE_MAX, obj_file_dir, mtl_library.data()); BLI_split_dir_part(mtl_file_path_, mtl_dir_path_, FILE_MAXDIR); } @@ -745,7 +780,7 @@ void MTLParser::parse_and_store(Map<string, std::unique_ptr<MTLMaterial>> &r_mat MTLMaterial *material = nullptr; - StringRef buffer_str{(const char *)buffer, (int64_t)buffer_len}; + StringRef buffer_str{(const char *)buffer, int64_t(buffer_len)}; while (!buffer_str.is_empty()) { const StringRef line = read_next_line(buffer_str); const char *p = line.begin(), *end = line.end(); @@ -766,31 +801,55 @@ void MTLParser::parse_and_store(Map<string, std::unique_ptr<MTLMaterial>> &r_mat } else if (material != nullptr) { if (parse_keyword(p, end, "Ns")) { - parse_float(p, end, 324.0f, material->Ns); + parse_float(p, end, 324.0f, material->spec_exponent); } else if (parse_keyword(p, end, "Ka")) { - parse_floats(p, end, 0.0f, material->Ka, 3); + parse_floats(p, end, 0.0f, material->ambient_color, 3); } else if (parse_keyword(p, end, "Kd")) { - parse_floats(p, end, 0.8f, material->Kd, 3); + parse_floats(p, end, 0.8f, material->color, 3); } else if (parse_keyword(p, end, "Ks")) { - parse_floats(p, end, 0.5f, material->Ks, 3); + parse_floats(p, end, 0.5f, material->spec_color, 3); } else if (parse_keyword(p, end, "Ke")) { - parse_floats(p, end, 0.0f, material->Ke, 3); + parse_floats(p, end, 0.0f, material->emission_color, 3); } else if (parse_keyword(p, end, "Ni")) { - parse_float(p, end, 1.45f, material->Ni); + parse_float(p, end, 1.45f, material->ior); } else if (parse_keyword(p, end, "d")) { - parse_float(p, end, 1.0f, material->d); + parse_float(p, end, 1.0f, material->alpha); } else if (parse_keyword(p, end, "illum")) { /* Some files incorrectly use a float (T60135). */ float val; parse_float(p, end, 1.0f, val); - material->illum = val; + material->illum_mode = val; + } + else if (parse_keyword(p, end, "Pr")) { + parse_float(p, end, 0.5f, material->roughness); + } + else if (parse_keyword(p, end, "Pm")) { + parse_float(p, end, 0.0f, material->metallic); + } + else if (parse_keyword(p, end, "Ps")) { + parse_float(p, end, 0.0f, material->sheen); + } + else if (parse_keyword(p, end, "Pc")) { + parse_float(p, end, 0.0f, material->cc_thickness); + } + else if (parse_keyword(p, end, "Pcr")) { + parse_float(p, end, 0.0f, material->cc_roughness); + } + else if (parse_keyword(p, end, "aniso")) { + parse_float(p, end, 0.0f, material->aniso); + } + else if (parse_keyword(p, end, "anisor")) { + parse_float(p, end, 0.0f, material->aniso_rot); + } + else if (parse_keyword(p, end, "Kt") || parse_keyword(p, end, "Tf")) { + parse_floats(p, end, 0.0f, material->transmit_color, 3); } else { parse_texture_map(p, end, material, mtl_dir_path_); |