Changeset View
Changeset View
Standalone View
Standalone View
source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
| Context not available. | |||||
| } | } | ||||
| static void geom_add_vertex(Geometry *geom, | static void geom_add_vertex(Geometry *geom, | ||||
| const StringRef line, | const char *p, | ||||
| const char *end, | |||||
| GlobalVertices &r_global_vertices) | GlobalVertices &r_global_vertices) | ||||
| { | { | ||||
| float3 vert; | float3 vert; | ||||
| parse_floats(line, 0.0f, vert, 3); | parse_floats(p, end, 0.0f, vert, 3); | ||||
| r_global_vertices.vertices.append(vert); | r_global_vertices.vertices.append(vert); | ||||
| geom->vertex_count_++; | geom->vertex_count_++; | ||||
| } | } | ||||
| static void geom_add_vertex_normal(Geometry *geom, | static void geom_add_vertex_normal(Geometry *geom, | ||||
| const StringRef line, | const char *p, | ||||
| const char *end, | |||||
| GlobalVertices &r_global_vertices) | GlobalVertices &r_global_vertices) | ||||
| { | { | ||||
| float3 normal; | float3 normal; | ||||
| parse_floats(line, 0.0f, normal, 3); | parse_floats(p, end, 0.0f, normal, 3); | ||||
| r_global_vertices.vertex_normals.append(normal); | r_global_vertices.vertex_normals.append(normal); | ||||
| geom->has_vertex_normals_ = true; | geom->has_vertex_normals_ = true; | ||||
| } | } | ||||
| static void geom_add_uv_vertex(const StringRef line, GlobalVertices &r_global_vertices) | static void geom_add_uv_vertex(const char *p, const char *end, GlobalVertices &r_global_vertices) | ||||
| { | { | ||||
| float2 uv; | float2 uv; | ||||
| parse_floats(line, 0.0f, uv, 2); | parse_floats(p, end, 0.0f, uv, 2); | ||||
| r_global_vertices.uv_vertices.append(uv); | r_global_vertices.uv_vertices.append(uv); | ||||
| } | } | ||||
| static void geom_add_edge(Geometry *geom, | static void geom_add_edge(Geometry *geom, | ||||
| StringRef line, | const char *p, | ||||
| const char *end, | |||||
| const VertexIndexOffset &offsets, | const VertexIndexOffset &offsets, | ||||
| GlobalVertices &r_global_vertices) | GlobalVertices &r_global_vertices) | ||||
| { | { | ||||
| int edge_v1, edge_v2; | int edge_v1, edge_v2; | ||||
| line = parse_int(line, -1, edge_v1); | p = parse_int(p, end, -1, edge_v1); | ||||
| line = parse_int(line, -1, edge_v2); | p = parse_int(p, end, -1, edge_v2); | ||||
| /* Always keep stored indices non-negative and zero-based. */ | /* Always keep stored indices non-negative and zero-based. */ | ||||
| edge_v1 += edge_v1 < 0 ? r_global_vertices.vertices.size() : -offsets.get_index_offset() - 1; | edge_v1 += edge_v1 < 0 ? r_global_vertices.vertices.size() : -offsets.get_index_offset() - 1; | ||||
| edge_v2 += edge_v2 < 0 ? r_global_vertices.vertices.size() : -offsets.get_index_offset() - 1; | edge_v2 += edge_v2 < 0 ? r_global_vertices.vertices.size() : -offsets.get_index_offset() - 1; | ||||
| Context not available. | |||||
| } | } | ||||
| static void geom_add_polygon(Geometry *geom, | static void geom_add_polygon(Geometry *geom, | ||||
| StringRef line, | const char *p, | ||||
| const char *end, | |||||
| const GlobalVertices &global_vertices, | const GlobalVertices &global_vertices, | ||||
| const VertexIndexOffset &offsets, | const VertexIndexOffset &offsets, | ||||
| const int material_index, | const int material_index, | ||||
| Context not available. | |||||
| curr_face.start_index_ = orig_corners_size; | curr_face.start_index_ = orig_corners_size; | ||||
| bool face_valid = true; | bool face_valid = true; | ||||
| line = drop_whitespace(line); | p = drop_whitespace(p, end); | ||||
| while (!line.is_empty() && face_valid) { | while (p < end && face_valid) { | ||||
| PolyCorner corner; | PolyCorner corner; | ||||
| bool got_uv = false, got_normal = false; | bool got_uv = false, got_normal = false; | ||||
| /* Parse vertex index. */ | /* Parse vertex index. */ | ||||
| line = parse_int(line, INT32_MAX, corner.vert_index, false); | p = parse_int(p, end, INT32_MAX, corner.vert_index, false); | ||||
| face_valid &= corner.vert_index != INT32_MAX; | face_valid &= corner.vert_index != INT32_MAX; | ||||
| if (!line.is_empty() && line[0] == '/') { | if (p < end && *p == '/') { | ||||
| /* Parse UV index. */ | /* Parse UV index. */ | ||||
| line = line.drop_prefix(1); | ++p; | ||||
| if (!line.is_empty() && line[0] != '/') { | if (p < end && *p != '/') { | ||||
| line = parse_int(line, INT32_MAX, corner.uv_vert_index, false); | p = parse_int(p, end, INT32_MAX, corner.uv_vert_index, false); | ||||
| got_uv = corner.uv_vert_index != INT32_MAX; | got_uv = corner.uv_vert_index != INT32_MAX; | ||||
| } | } | ||||
| /* Parse normal index. */ | /* Parse normal index. */ | ||||
| if (!line.is_empty() && line[0] == '/') { | if (p < end && *p == '/') { | ||||
| line = line.drop_prefix(1); | ++p; | ||||
| line = parse_int(line, INT32_MAX, corner.vertex_normal_index, false); | p = parse_int(p, end, INT32_MAX, corner.vertex_normal_index, false); | ||||
| got_normal = corner.uv_vert_index != INT32_MAX; | got_normal = corner.uv_vert_index != INT32_MAX; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| curr_face.corner_count_++; | curr_face.corner_count_++; | ||||
| /* Skip whitespace to get to the next face corner. */ | /* Skip whitespace to get to the next face corner. */ | ||||
| line = drop_whitespace(line); | p = drop_whitespace(p, end); | ||||
| } | } | ||||
| if (face_valid) { | if (face_valid) { | ||||
| Context not available. | |||||
| } | } | ||||
| static Geometry *geom_set_curve_type(Geometry *geom, | static Geometry *geom_set_curve_type(Geometry *geom, | ||||
| const StringRef rest_line, | const char *p, | ||||
| const char *end, | |||||
| const GlobalVertices &global_vertices, | const GlobalVertices &global_vertices, | ||||
| const StringRef group_name, | const StringRef group_name, | ||||
| VertexIndexOffset &r_offsets, | VertexIndexOffset &r_offsets, | ||||
| Vector<std::unique_ptr<Geometry>> &r_all_geometries) | Vector<std::unique_ptr<Geometry>> &r_all_geometries) | ||||
| { | { | ||||
| if (rest_line.find("bspline") == StringRef::not_found) { | p = drop_whitespace(p, end); | ||||
| std::cerr << "Curve type not supported:'" << rest_line << "'" << std::endl; | if (!StringRef(p, end).startswith("bspline")) { | ||||
| std::cerr << "Curve type not supported: '" << std::string(p, end) << "'" << std::endl; | |||||
| return geom; | return geom; | ||||
| } | } | ||||
| geom = create_geometry( | geom = create_geometry( | ||||
| Context not available. | |||||
| return geom; | return geom; | ||||
| } | } | ||||
| static void geom_set_curve_degree(Geometry *geom, const StringRef line) | static void geom_set_curve_degree(Geometry *geom, const char *p, const char *end) | ||||
| { | { | ||||
| parse_int(line, 3, geom->nurbs_element_.degree); | parse_int(p, end, 3, geom->nurbs_element_.degree); | ||||
| } | } | ||||
| static void geom_add_curve_vertex_indices(Geometry *geom, | static void geom_add_curve_vertex_indices(Geometry *geom, | ||||
| StringRef line, | const char *p, | ||||
| const char *end, | |||||
| const GlobalVertices &global_vertices) | const GlobalVertices &global_vertices) | ||||
| { | { | ||||
| /* Curve lines always have "0.0" and "1.0", skip over them. */ | /* Curve lines always have "0.0" and "1.0", skip over them. */ | ||||
| float dummy[2]; | float dummy[2]; | ||||
| line = parse_floats(line, 0, dummy, 2); | p = parse_floats(p, end, 0, dummy, 2); | ||||
| /* Parse indices. */ | /* Parse indices. */ | ||||
| while (!line.is_empty()) { | while (p < end) { | ||||
| int index; | int index; | ||||
| line = parse_int(line, INT32_MAX, index); | p = parse_int(p, end, INT32_MAX, index); | ||||
| if (index == INT32_MAX) { | if (index == INT32_MAX) { | ||||
| return; | return; | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| static void geom_add_curve_parameters(Geometry *geom, StringRef line) | static void geom_add_curve_parameters(Geometry *geom, const char *p, const char *end) | ||||
| { | { | ||||
| line = drop_whitespace(line); | p = drop_whitespace(p, end); | ||||
| if (line.is_empty()) { | if (p == end) { | ||||
| std::cerr << "Invalid OBJ curve parm line: '" << line << "'" << std::endl; | std::cerr << "Invalid OBJ curve parm line" << std::endl; | ||||
| return; | return; | ||||
| } | } | ||||
| if (line[0] != 'u') { | if (*p != 'u') { | ||||
| std::cerr << "OBJ curve surfaces are not supported: '" << line[0] << "'" << std::endl; | std::cerr << "OBJ curve surfaces are not supported: '" << *p << "'" << std::endl; | ||||
| return; | return; | ||||
| } | } | ||||
| line = line.drop_prefix(1); | ++p; | ||||
| while (!line.is_empty()) { | while (p < end) { | ||||
| float val; | float val; | ||||
| line = parse_float(line, FLT_MAX, val); | p = parse_float(p, end, FLT_MAX, val); | ||||
| if (val != FLT_MAX) { | if (val != FLT_MAX) { | ||||
| geom->nurbs_element_.parm.append(val); | geom->nurbs_element_.parm.append(val); | ||||
| } | } | ||||
| Context not available. | |||||
| static void geom_update_group(const StringRef rest_line, std::string &r_group_name) | static void geom_update_group(const StringRef rest_line, std::string &r_group_name) | ||||
| { | { | ||||
| if (rest_line.find("off") != string::npos || rest_line.find("null") != string::npos || | if (rest_line.find("off") != string::npos || rest_line.find("null") != string::npos || | ||||
| rest_line.find("default") != string::npos) { | rest_line.find("default") != string::npos) { | ||||
| /* Set group for future elements like faces or curves to empty. */ | /* Set group for future elements like faces or curves to empty. */ | ||||
| Context not available. | |||||
| r_group_name = rest_line; | r_group_name = rest_line; | ||||
| } | } | ||||
| static void geom_update_smooth_group(StringRef line, bool &r_state_shaded_smooth) | static void geom_update_smooth_group(const char *p, const char *end, bool &r_state_shaded_smooth) | ||||
| { | { | ||||
| line = drop_whitespace(line); | p = drop_whitespace(p, end); | ||||
| /* Some implementations use "0" and "null" too, in addition to "off". */ | /* Some implementations use "0" and "null" too, in addition to "off". */ | ||||
| const StringRef line = StringRef(p, end); | |||||
| if (line == "0" || line.startswith("off") || line.startswith("null")) { | if (line == "0" || line.startswith("off") || line.startswith("null")) { | ||||
| r_state_shaded_smooth = false; | r_state_shaded_smooth = false; | ||||
| return; | return; | ||||
| } | } | ||||
| int smooth = 0; | int smooth = 0; | ||||
| parse_int(line, 0, smooth); | parse_int(p, end, 0, smooth); | ||||
| r_state_shaded_smooth = smooth != 0; | r_state_shaded_smooth = smooth != 0; | ||||
| } | } | ||||
| Context not available. | |||||
| } | } | ||||
| /* If line starts with keyword followed by whitespace, returns true and drops it from the line. */ | /* If line starts with keyword followed by whitespace, returns true and drops it from the line. */ | ||||
| static bool parse_keyword(StringRef &line, StringRef keyword) | static bool parse_keyword(const char *&p, const char *end, StringRef keyword) | ||||
| { | { | ||||
| const size_t keyword_len = keyword.size(); | const size_t keyword_len = keyword.size(); | ||||
| if (line.size() < keyword_len + 1) { | if (end - p < keyword_len + 1) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (!line.startswith(keyword)) { | if (memcmp(p, keyword.data(), keyword_len) != 0) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Treat any ASCII control character as white-space; | /* Treat any ASCII control character as white-space; | ||||
| * don't use `isspace()` for performance reasons. */ | * don't use `isspace()` for performance reasons. */ | ||||
| if (line[keyword_len] > ' ') { | if (p[keyword_len] > ' ') { | ||||
| return false; | return false; | ||||
| } | } | ||||
| line = line.drop_prefix(keyword_len + 1); | p += keyword_len + 1; | ||||
| return true; | return true; | ||||
| } | } | ||||
| Context not available. | |||||
| StringRef buffer_str{buffer.data(), (int64_t)last_nl}; | StringRef buffer_str{buffer.data(), (int64_t)last_nl}; | ||||
| while (!buffer_str.is_empty()) { | while (!buffer_str.is_empty()) { | ||||
| StringRef line = read_next_line(buffer_str); | StringRef line = read_next_line(buffer_str); | ||||
| line = drop_whitespace(line); | const char *p = line.begin(), *end = line.end(); | ||||
| p = drop_whitespace(p, end); | |||||
| ++line_number; | ++line_number; | ||||
| if (line.is_empty()) { | if (p == end) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Most common things that start with 'v': vertices, normals, UVs. */ | /* Most common things that start with 'v': vertices, normals, UVs. */ | ||||
| if (line[0] == 'v') { | if (*p == 'v') { | ||||
| if (parse_keyword(line, "v")) { | if (parse_keyword(p, end, "v")) { | ||||
| geom_add_vertex(curr_geom, line, r_global_vertices); | geom_add_vertex(curr_geom, p, end, r_global_vertices); | ||||
| } | } | ||||
| else if (parse_keyword(line, "vn")) { | else if (parse_keyword(p, end, "vn")) { | ||||
| geom_add_vertex_normal(curr_geom, line, r_global_vertices); | geom_add_vertex_normal(curr_geom, p, end, r_global_vertices); | ||||
| } | } | ||||
| else if (parse_keyword(line, "vt")) { | else if (parse_keyword(p, end, "vt")) { | ||||
| geom_add_uv_vertex(line, r_global_vertices); | geom_add_uv_vertex(p, end, r_global_vertices); | ||||
| } | } | ||||
| } | } | ||||
| /* Faces. */ | /* Faces. */ | ||||
| else if (parse_keyword(line, "f")) { | else if (parse_keyword(p, end, "f")) { | ||||
| geom_add_polygon(curr_geom, | geom_add_polygon(curr_geom, | ||||
| line, | p, | ||||
| end, | |||||
| r_global_vertices, | r_global_vertices, | ||||
| offsets, | offsets, | ||||
| state_material_index, | state_material_index, | ||||
| Context not available. | |||||
| state_shaded_smooth); | state_shaded_smooth); | ||||
| } | } | ||||
| /* Faces. */ | /* Faces. */ | ||||
| else if (parse_keyword(line, "l")) { | else if (parse_keyword(p, end, "l")) { | ||||
| geom_add_edge(curr_geom, line, offsets, r_global_vertices); | geom_add_edge(curr_geom, p, end, offsets, r_global_vertices); | ||||
| } | } | ||||
| /* Objects. */ | /* Objects. */ | ||||
| else if (parse_keyword(line, "o")) { | else if (parse_keyword(p, end, "o")) { | ||||
| state_shaded_smooth = false; | state_shaded_smooth = false; | ||||
| state_group_name = ""; | state_group_name = ""; | ||||
| state_material_name = ""; | state_material_name = ""; | ||||
| curr_geom = create_geometry( | curr_geom = create_geometry(curr_geom, | ||||
| curr_geom, GEOM_MESH, line.trim(), r_global_vertices, r_all_geometries, offsets); | GEOM_MESH, | ||||
| StringRef(p, end).trim(), | |||||
| r_global_vertices, | |||||
| r_all_geometries, | |||||
| offsets); | |||||
| } | } | ||||
| /* Groups. */ | /* Groups. */ | ||||
| else if (parse_keyword(line, "g")) { | else if (parse_keyword(p, end, "g")) { | ||||
| geom_update_group(line.trim(), state_group_name); | geom_update_group(StringRef(p, end).trim(), state_group_name); | ||||
| int new_index = curr_geom->group_indices_.size(); | int new_index = curr_geom->group_indices_.size(); | ||||
| state_group_index = curr_geom->group_indices_.lookup_or_add(state_group_name, new_index); | state_group_index = curr_geom->group_indices_.lookup_or_add(state_group_name, new_index); | ||||
| if (new_index == state_group_index) { | if (new_index == state_group_index) { | ||||
| Context not available. | |||||
| } | } | ||||
| } | } | ||||
| /* Smoothing groups. */ | /* Smoothing groups. */ | ||||
| else if (parse_keyword(line, "s")) { | else if (parse_keyword(p, end, "s")) { | ||||
| geom_update_smooth_group(line, state_shaded_smooth); | geom_update_smooth_group(p, end, state_shaded_smooth); | ||||
| } | } | ||||
| /* Materials and their libraries. */ | /* Materials and their libraries. */ | ||||
| else if (parse_keyword(line, "usemtl")) { | else if (parse_keyword(p, end, "usemtl")) { | ||||
| state_material_name = line.trim(); | state_material_name = StringRef(p, end).trim(); | ||||
| int new_mat_index = curr_geom->material_indices_.size(); | int new_mat_index = curr_geom->material_indices_.size(); | ||||
| state_material_index = curr_geom->material_indices_.lookup_or_add(state_material_name, | state_material_index = curr_geom->material_indices_.lookup_or_add(state_material_name, | ||||
| new_mat_index); | new_mat_index); | ||||
| Context not available. | |||||
| curr_geom->material_order_.append(state_material_name); | curr_geom->material_order_.append(state_material_name); | ||||
| } | } | ||||
| } | } | ||||
| else if (parse_keyword(line, "mtllib")) { | else if (parse_keyword(p, end, "mtllib")) { | ||||
| add_mtl_library(line.trim()); | add_mtl_library(StringRef(p, end).trim()); | ||||
| } | } | ||||
| /* Comments. */ | /* Comments. */ | ||||
| else if (line.startswith("#")) { | else if (*p == '#') { | ||||
| /* Nothing to do. */ | /* Nothing to do. */ | ||||
| } | } | ||||
| /* Curve related things. */ | /* Curve related things. */ | ||||
| else if (parse_keyword(line, "cstype")) { | else if (parse_keyword(p, end, "cstype")) { | ||||
| curr_geom = geom_set_curve_type( | curr_geom = geom_set_curve_type( | ||||
| curr_geom, line, r_global_vertices, state_group_name, offsets, r_all_geometries); | curr_geom, p, end, r_global_vertices, state_group_name, offsets, r_all_geometries); | ||||
| } | } | ||||
| else if (parse_keyword(line, "deg")) { | else if (parse_keyword(p, end, "deg")) { | ||||
| geom_set_curve_degree(curr_geom, line); | geom_set_curve_degree(curr_geom, p, end); | ||||
| } | } | ||||
| else if (parse_keyword(line, "curv")) { | else if (parse_keyword(p, end, "curv")) { | ||||
| geom_add_curve_vertex_indices(curr_geom, line, r_global_vertices); | geom_add_curve_vertex_indices(curr_geom, p, end, r_global_vertices); | ||||
| } | } | ||||
| else if (parse_keyword(line, "parm")) { | else if (parse_keyword(p, end, "parm")) { | ||||
| geom_add_curve_parameters(curr_geom, line); | geom_add_curve_parameters(curr_geom, p, end); | ||||
| } | } | ||||
| else if (line.startswith("end")) { | else if (StringRef(p, end).startswith("end")) { | ||||
| /* End of curve definition, nothing else to do. */ | /* End of curve definition, nothing else to do. */ | ||||
| } | } | ||||
| else { | else { | ||||
| std::cout << "OBJ element not recognized: '" << line << "'" << std::endl; | std::cout << "OBJ element not recognized: '" << std::string(p, end) << "'" << std::endl; | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||
| add_default_mtl_library(); | add_default_mtl_library(); | ||||
| } | } | ||||
| static eMTLSyntaxElement mtl_line_start_to_enum(StringRef &line) | static eMTLSyntaxElement mtl_line_start_to_enum(const char *&p, const char *end) | ||||
| { | { | ||||
| if (parse_keyword(line, "map_Kd")) { | if (parse_keyword(p, end, "map_Kd")) { | ||||
| return eMTLSyntaxElement::map_Kd; | return eMTLSyntaxElement::map_Kd; | ||||
| } | } | ||||
| if (parse_keyword(line, "map_Ks")) { | if (parse_keyword(p, end, "map_Ks")) { | ||||
| return eMTLSyntaxElement::map_Ks; | return eMTLSyntaxElement::map_Ks; | ||||
| } | } | ||||
| if (parse_keyword(line, "map_Ns")) { | if (parse_keyword(p, end, "map_Ns")) { | ||||
| return eMTLSyntaxElement::map_Ns; | return eMTLSyntaxElement::map_Ns; | ||||
| } | } | ||||
| if (parse_keyword(line, "map_d")) { | if (parse_keyword(p, end, "map_d")) { | ||||
| return eMTLSyntaxElement::map_d; | return eMTLSyntaxElement::map_d; | ||||
| } | } | ||||
| if (parse_keyword(line, "refl")) { | if (parse_keyword(p, end, "refl")) { | ||||
| return eMTLSyntaxElement::map_refl; | return eMTLSyntaxElement::map_refl; | ||||
| } | } | ||||
| if (parse_keyword(line, "map_refl")) { | if (parse_keyword(p, end, "map_refl")) { | ||||
| return eMTLSyntaxElement::map_refl; | return eMTLSyntaxElement::map_refl; | ||||
| } | } | ||||
| if (parse_keyword(line, "map_Ke")) { | if (parse_keyword(p, end, "map_Ke")) { | ||||
| return eMTLSyntaxElement::map_Ke; | return eMTLSyntaxElement::map_Ke; | ||||
| } | } | ||||
| if (parse_keyword(line, "bump")) { | if (parse_keyword(p, end, "bump")) { | ||||
| return eMTLSyntaxElement::map_Bump; | return eMTLSyntaxElement::map_Bump; | ||||
| } | } | ||||
| if (parse_keyword(line, "map_Bump") || parse_keyword(line, "map_bump")) { | if (parse_keyword(p, end, "map_Bump") || parse_keyword(p, end, "map_bump")) { | ||||
| return eMTLSyntaxElement::map_Bump; | return eMTLSyntaxElement::map_Bump; | ||||
| } | } | ||||
| return eMTLSyntaxElement::string; | return eMTLSyntaxElement::string; | ||||
| Context not available. | |||||
| {"-texres", 1}, | {"-texres", 1}, | ||||
| }; | }; | ||||
| static bool parse_texture_option(StringRef &line, MTLMaterial *material, tex_map_XX &tex_map) | static bool parse_texture_option(const char *&p, | ||||
| const char *end, | |||||
| MTLMaterial *material, | |||||
| tex_map_XX &tex_map) | |||||
| { | { | ||||
| line = drop_whitespace(line); | p = drop_whitespace(p, end); | ||||
| if (parse_keyword(line, "-o")) { | if (parse_keyword(p, end, "-o")) { | ||||
| line = parse_floats(line, 0.0f, tex_map.translation, 3); | p = parse_floats(p, end, 0.0f, tex_map.translation, 3); | ||||
| return true; | return true; | ||||
| } | } | ||||
| if (parse_keyword(line, "-s")) { | if (parse_keyword(p, end, "-s")) { | ||||
| line = parse_floats(line, 1.0f, tex_map.scale, 3); | p = parse_floats(p, end, 1.0f, tex_map.scale, 3); | ||||
| return true; | return true; | ||||
| } | } | ||||
| if (parse_keyword(line, "-bm")) { | if (parse_keyword(p, end, "-bm")) { | ||||
| line = parse_float(line, 1.0f, material->map_Bump_strength); | p = parse_float(p, end, 1.0f, material->map_Bump_strength); | ||||
| return true; | return true; | ||||
| } | } | ||||
| if (parse_keyword(line, "-type")) { | if (parse_keyword(p, end, "-type")) { | ||||
| line = drop_whitespace(line); | p = drop_whitespace(p, end); | ||||
| /* Only sphere is supported. */ | /* Only sphere is supported. */ | ||||
| tex_map.projection_type = SHD_PROJ_SPHERE; | tex_map.projection_type = SHD_PROJ_SPHERE; | ||||
| const StringRef line = StringRef(p, end); | |||||
| if (!line.startswith("sphere")) { | if (!line.startswith("sphere")) { | ||||
| std::cerr << "OBJ import: only sphere MTL projection type is supported: '" << line << "'" | std::cerr << "OBJ import: only sphere MTL projection type is supported: '" << line << "'" | ||||
| << std::endl; | << std::endl; | ||||
| } | } | ||||
| line = drop_non_whitespace(line); | p = drop_non_whitespace(p, end); | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* Check for unsupported options and skip them. */ | /* Check for unsupported options and skip them. */ | ||||
| for (const auto &opt : unsupported_texture_options) { | for (const auto &opt : unsupported_texture_options) { | ||||
| if (parse_keyword(line, opt.first)) { | if (parse_keyword(p, end, opt.first)) { | ||||
| /* Drop the arguments. */ | /* Drop the arguments. */ | ||||
| for (int i = 0; i < opt.second; ++i) { | for (int i = 0; i < opt.second; ++i) { | ||||
| line = drop_whitespace(line); | p = drop_whitespace(p, end); | ||||
| line = drop_non_whitespace(line); | p = drop_non_whitespace(p, end); | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| Context not available. | |||||
| return false; | return false; | ||||
| } | } | ||||
| static void parse_texture_map(StringRef line, MTLMaterial *material, const char *mtl_dir_path) | static void parse_texture_map(const char *p, | ||||
| const char *end, | |||||
| MTLMaterial *material, | |||||
| const char *mtl_dir_path) | |||||
| { | { | ||||
| const StringRef line = StringRef(p, end); | |||||
| bool is_map = line.startswith("map_"); | bool is_map = line.startswith("map_"); | ||||
| bool is_refl = line.startswith("refl"); | bool is_refl = line.startswith("refl"); | ||||
| bool is_bump = line.startswith("bump"); | bool is_bump = line.startswith("bump"); | ||||
| if (!is_map && !is_refl && !is_bump) { | if (!is_map && !is_refl && !is_bump) { | ||||
| return; | return; | ||||
| } | } | ||||
| eMTLSyntaxElement key = mtl_line_start_to_enum(line); | eMTLSyntaxElement key = mtl_line_start_to_enum(p, end); | ||||
| if (key == eMTLSyntaxElement::string || !material->texture_maps.contains(key)) { | if (key == eMTLSyntaxElement::string || !material->texture_maps.contains(key)) { | ||||
| /* No supported texture map found. */ | /* No supported texture map found. */ | ||||
| std::cerr << "OBJ import: MTL texture map type not supported: '" << line << "'" << std::endl; | std::cerr << "OBJ import: MTL texture map type not supported: '" << line << "'" << std::endl; | ||||
| Context not available. | |||||
| tex_map.mtl_dir_path = mtl_dir_path; | tex_map.mtl_dir_path = mtl_dir_path; | ||||
| /* Parse texture map options. */ | /* Parse texture map options. */ | ||||
| while (parse_texture_option(line, material, tex_map)) { | while (parse_texture_option(p, end, material, tex_map)) { | ||||
| } | } | ||||
| /* What remains is the image path. */ | /* What remains is the image path. */ | ||||
| line = line.trim(); | tex_map.image_path = StringRef(p, end).trim(); | ||||
| tex_map.image_path = line; | |||||
| } | } | ||||
| Span<std::string> OBJParser::mtl_libraries() const | Span<std::string> OBJParser::mtl_libraries() const | ||||
| Context not available. | |||||
| 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()) { | while (!buffer_str.is_empty()) { | ||||
| StringRef line = read_next_line(buffer_str); | const StringRef line = read_next_line(buffer_str); | ||||
| line = drop_whitespace(line); | const char *p = line.begin(), *end = line.end(); | ||||
| if (line.is_empty()) { | p = drop_whitespace(p, end); | ||||
| if (p == end) { | |||||
| continue; | continue; | ||||
| } | } | ||||
| if (parse_keyword(line, "newmtl")) { | if (parse_keyword(p, end, "newmtl")) { | ||||
| line = line.trim(); | StringRef mat_name = StringRef(p, end).trim(); | ||||
| if (r_materials.contains(line)) { | if (r_materials.contains(mat_name)) { | ||||
| material = nullptr; | material = nullptr; | ||||
| } | } | ||||
| else { | else { | ||||
| material = r_materials.lookup_or_add(string(line), std::make_unique<MTLMaterial>()).get(); | material = | ||||
| r_materials.lookup_or_add(string(mat_name), std::make_unique<MTLMaterial>()).get(); | |||||
| } | } | ||||
| } | } | ||||
| else if (material != nullptr) { | else if (material != nullptr) { | ||||
| if (parse_keyword(line, "Ns")) { | if (parse_keyword(p, end, "Ns")) { | ||||
| parse_float(line, 324.0f, material->Ns); | parse_float(p, end, 324.0f, material->Ns); | ||||
| } | } | ||||
| else if (parse_keyword(line, "Ka")) { | else if (parse_keyword(p, end, "Ka")) { | ||||
| parse_floats(line, 0.0f, material->Ka, 3); | parse_floats(p, end, 0.0f, material->Ka, 3); | ||||
| } | } | ||||
| else if (parse_keyword(line, "Kd")) { | else if (parse_keyword(p, end, "Kd")) { | ||||
| parse_floats(line, 0.8f, material->Kd, 3); | parse_floats(p, end, 0.8f, material->Kd, 3); | ||||
| } | } | ||||
| else if (parse_keyword(line, "Ks")) { | else if (parse_keyword(p, end, "Ks")) { | ||||
| parse_floats(line, 0.5f, material->Ks, 3); | parse_floats(p, end, 0.5f, material->Ks, 3); | ||||
| } | } | ||||
| else if (parse_keyword(line, "Ke")) { | else if (parse_keyword(p, end, "Ke")) { | ||||
| parse_floats(line, 0.0f, material->Ke, 3); | parse_floats(p, end, 0.0f, material->Ke, 3); | ||||
| } | } | ||||
| else if (parse_keyword(line, "Ni")) { | else if (parse_keyword(p, end, "Ni")) { | ||||
| parse_float(line, 1.45f, material->Ni); | parse_float(p, end, 1.45f, material->Ni); | ||||
| } | } | ||||
| else if (parse_keyword(line, "d")) { | else if (parse_keyword(p, end, "d")) { | ||||
| parse_float(line, 1.0f, material->d); | parse_float(p, end, 1.0f, material->d); | ||||
| } | } | ||||
| else if (parse_keyword(line, "illum")) { | else if (parse_keyword(p, end, "illum")) { | ||||
| /* Some files incorrectly use a float (T60135). */ | /* Some files incorrectly use a float (T60135). */ | ||||
| float val; | float val; | ||||
| parse_float(line, 1.0f, val); | parse_float(p, end, 1.0f, val); | ||||
| material->illum = val; | material->illum = val; | ||||
| } | } | ||||
| else { | else { | ||||
| parse_texture_map(line, material, mtl_dir_path_); | parse_texture_map(p, end, material, mtl_dir_path_); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Context not available. | |||||