diff options
Diffstat (limited to 'source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc')
-rw-r--r-- | source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc | 416 |
1 files changed, 239 insertions, 177 deletions
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc index d31353c4a76..87f87e37a7e 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -24,6 +24,7 @@ #include "BKE_blender_version.h" #include "BLI_path_util.h" +#include "BLI_task.hh" #include "obj_export_mesh.hh" #include "obj_export_mtl.hh" @@ -52,68 +53,75 @@ const char *DEFORM_GROUP_DISABLED = "off"; * So an empty material name is written. */ const char *MATERIAL_GROUP_DISABLED = ""; -void OBJWriter::write_vert_uv_normal_indices(Span<int> vert_indices, +void OBJWriter::write_vert_uv_normal_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> uv_indices, Span<int> normal_indices) const { BLI_assert(vert_indices.size() == uv_indices.size() && vert_indices.size() == normal_indices.size()); - file_handler_->write<eOBJSyntaxElement::poly_element_begin>(); + fh.write<eOBJSyntaxElement::poly_element_begin>(); for (int j = 0; j < vert_indices.size(); j++) { - file_handler_->write<eOBJSyntaxElement::vertex_uv_normal_indices>( - vert_indices[j] + index_offsets_.vertex_offset + 1, - uv_indices[j] + index_offsets_.uv_vertex_offset + 1, - normal_indices[j] + index_offsets_.normal_offset + 1); + fh.write<eOBJSyntaxElement::vertex_uv_normal_indices>( + vert_indices[j] + offsets.vertex_offset + 1, + uv_indices[j] + offsets.uv_vertex_offset + 1, + normal_indices[j] + offsets.normal_offset + 1); } - file_handler_->write<eOBJSyntaxElement::poly_element_end>(); + fh.write<eOBJSyntaxElement::poly_element_end>(); } -void OBJWriter::write_vert_normal_indices(Span<int> vert_indices, +void OBJWriter::write_vert_normal_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> /*uv_indices*/, Span<int> normal_indices) const { BLI_assert(vert_indices.size() == normal_indices.size()); - file_handler_->write<eOBJSyntaxElement::poly_element_begin>(); + fh.write<eOBJSyntaxElement::poly_element_begin>(); for (int j = 0; j < vert_indices.size(); j++) { - file_handler_->write<eOBJSyntaxElement::vertex_normal_indices>( - vert_indices[j] + index_offsets_.vertex_offset + 1, - normal_indices[j] + index_offsets_.normal_offset + 1); + fh.write<eOBJSyntaxElement::vertex_normal_indices>(vert_indices[j] + offsets.vertex_offset + 1, + normal_indices[j] + offsets.normal_offset + + 1); } - file_handler_->write<eOBJSyntaxElement::poly_element_end>(); + fh.write<eOBJSyntaxElement::poly_element_end>(); } -void OBJWriter::write_vert_uv_indices(Span<int> vert_indices, +void OBJWriter::write_vert_uv_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> uv_indices, Span<int> /*normal_indices*/) const { BLI_assert(vert_indices.size() == uv_indices.size()); - file_handler_->write<eOBJSyntaxElement::poly_element_begin>(); + fh.write<eOBJSyntaxElement::poly_element_begin>(); for (int j = 0; j < vert_indices.size(); j++) { - file_handler_->write<eOBJSyntaxElement::vertex_uv_indices>( - vert_indices[j] + index_offsets_.vertex_offset + 1, - uv_indices[j] + index_offsets_.uv_vertex_offset + 1); + fh.write<eOBJSyntaxElement::vertex_uv_indices>(vert_indices[j] + offsets.vertex_offset + 1, + uv_indices[j] + offsets.uv_vertex_offset + 1); } - file_handler_->write<eOBJSyntaxElement::poly_element_end>(); + fh.write<eOBJSyntaxElement::poly_element_end>(); } -void OBJWriter::write_vert_indices(Span<int> vert_indices, +void OBJWriter::write_vert_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + Span<int> vert_indices, Span<int> /*uv_indices*/, Span<int> /*normal_indices*/) const { - file_handler_->write<eOBJSyntaxElement::poly_element_begin>(); + fh.write<eOBJSyntaxElement::poly_element_begin>(); for (const int vert_index : vert_indices) { - file_handler_->write<eOBJSyntaxElement::vertex_indices>(vert_index + - index_offsets_.vertex_offset + 1); + fh.write<eOBJSyntaxElement::vertex_indices>(vert_index + offsets.vertex_offset + 1); } - file_handler_->write<eOBJSyntaxElement::poly_element_end>(); + fh.write<eOBJSyntaxElement::poly_element_end>(); } void OBJWriter::write_header() const { using namespace std::string_literals; - file_handler_->write<eOBJSyntaxElement::string>("# Blender "s + BKE_blender_version_string() + - "\n"); - file_handler_->write<eOBJSyntaxElement::string>("# www.blender.org\n"); + FormatHandler<eFileType::OBJ> fh; + fh.write<eOBJSyntaxElement::string>("# Blender "s + BKE_blender_version_string() + "\n"); + fh.write<eOBJSyntaxElement::string>("# www.blender.org\n"); + fh.write_to_file(outfile_); } void OBJWriter::write_mtllib_name(const StringRefNull mtl_filepath) const @@ -122,10 +130,13 @@ void OBJWriter::write_mtllib_name(const StringRefNull mtl_filepath) const char mtl_file_name[FILE_MAXFILE]; char mtl_dir_name[FILE_MAXDIR]; BLI_split_dirfile(mtl_filepath.data(), mtl_dir_name, mtl_file_name, FILE_MAXDIR, FILE_MAXFILE); - file_handler_->write<eOBJSyntaxElement::mtllib>(mtl_file_name); + FormatHandler<eFileType::OBJ> fh; + fh.write<eOBJSyntaxElement::mtllib>(mtl_file_name); + fh.write_to_file(outfile_); } -void OBJWriter::write_object_group(const OBJMesh &obj_mesh_data) const +void OBJWriter::write_object_group(FormatHandler<eFileType::OBJ> &fh, + const OBJMesh &obj_mesh_data) const { /* "o object_name" is not mandatory. A valid .OBJ file may contain neither * "o name" nor "g group_name". */ @@ -138,125 +149,104 @@ void OBJWriter::write_object_group(const OBJMesh &obj_mesh_data) const const char *object_material_name = obj_mesh_data.get_object_material_name(0); if (export_params_.export_materials && export_params_.export_material_groups && object_material_name) { - file_handler_->write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name + - "_" + object_material_name); - return; + fh.write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name + "_" + + object_material_name); + } + else { + fh.write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name); } - file_handler_->write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name); } -void OBJWriter::write_object_name(const OBJMesh &obj_mesh_data) const +void OBJWriter::write_object_name(FormatHandler<eFileType::OBJ> &fh, + const OBJMesh &obj_mesh_data) const { const char *object_name = obj_mesh_data.get_object_name(); if (export_params_.export_object_groups) { - write_object_group(obj_mesh_data); + write_object_group(fh, obj_mesh_data); return; } - file_handler_->write<eOBJSyntaxElement::object_name>(object_name); + fh.write<eOBJSyntaxElement::object_name>(object_name); } -void OBJWriter::write_vertex_coords(const OBJMesh &obj_mesh_data) const +/* Split up large meshes into multi-threaded jobs; each job processes + * this amount of items. */ +static const int chunk_size = 32768; +static int calc_chunk_count(int count) { - const int tot_vertices = obj_mesh_data.tot_vertices(); - for (int i = 0; i < tot_vertices; i++) { - float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); - file_handler_->write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]); - } + return (count + chunk_size - 1) / chunk_size; } -void OBJWriter::write_uv_coords(OBJMesh &r_obj_mesh_data) const +/* Write /tot_count/ items to OBJ file output. Each item is written + * by a /function/ that should be independent from other items. + * If the amount of items is large enough (> chunk_size), then writing + * will be done in parallel, into temporary FormatHandler buffers that + * will be written into the final /fh/ buffer at the end. + */ +template<typename Function> +void obj_parallel_chunked_output(FormatHandler<eFileType::OBJ> &fh, + int tot_count, + const Function &function) { - Vector<std::array<float, 2>> uv_coords; - /* UV indices are calculated and stored in an OBJMesh member here. */ - r_obj_mesh_data.store_uv_coords_and_indices(uv_coords); - - for (const std::array<float, 2> &uv_vertex : uv_coords) { - file_handler_->write<eOBJSyntaxElement::uv_vertex_coords>(uv_vertex[0], uv_vertex[1]); + if (tot_count <= 0) { + return; } -} - -void OBJWriter::write_poly_normals(OBJMesh &obj_mesh_data) -{ - obj_mesh_data.ensure_mesh_normals(); - Vector<float3> normals; - obj_mesh_data.store_normal_coords_and_indices(normals); - for (const float3 &normal : normals) { - file_handler_->write<eOBJSyntaxElement::normal>(normal[0], normal[1], normal[2]); + /* If we have just one chunk, process it directly into the output + * buffer - avoids all the job scheduling and temporary vector allocation + * overhead. */ + const int chunk_count = calc_chunk_count(tot_count); + if (chunk_count == 1) { + for (int i = 0; i < tot_count; i++) { + function(fh, i); + } + return; + } + /* Give each chunk its own temporary output buffer, and process them in parallel. */ + std::vector<FormatHandler<eFileType::OBJ>> buffers(chunk_count); + blender::threading::parallel_for(IndexRange(chunk_count), 1, [&](IndexRange range) { + for (const int r : range) { + int i_start = r * chunk_size; + int i_end = std::min(i_start + chunk_size, tot_count); + auto &buf = buffers[r]; + for (int i = i_start; i < i_end; i++) { + function(buf, i); + } + } + }); + /* Emit all temporary output buffers into the destination buffer. */ + for (auto &buf : buffers) { + fh.append_from(buf); } } -int OBJWriter::write_smooth_group(const OBJMesh &obj_mesh_data, - const int poly_index, - const int last_poly_smooth_group) const +void OBJWriter::write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, + const OBJMesh &obj_mesh_data) const { - int current_group = SMOOTH_GROUP_DISABLED; - if (!export_params_.export_smooth_groups && obj_mesh_data.is_ith_poly_smooth(poly_index)) { - /* Smooth group calculation is disabled, but polygon is smooth-shaded. */ - current_group = SMOOTH_GROUP_DEFAULT; - } - else if (obj_mesh_data.is_ith_poly_smooth(poly_index)) { - /* Smooth group calc is enabled and polygon is smooth–shaded, so find the group. */ - current_group = obj_mesh_data.ith_smooth_group(poly_index); - } - - if (current_group == last_poly_smooth_group) { - /* Group has already been written, even if it is "s 0". */ - return current_group; - } - file_handler_->write<eOBJSyntaxElement::smooth_group>(current_group); - return current_group; + const int tot_count = obj_mesh_data.tot_vertices(); + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) { + float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); + buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]); + }); } -int16_t OBJWriter::write_poly_material(const OBJMesh &obj_mesh_data, - const int poly_index, - const int16_t last_poly_mat_nr, - std::function<const char *(int)> matname_fn) const +void OBJWriter::write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &r_obj_mesh_data) const { - if (!export_params_.export_materials || obj_mesh_data.tot_materials() <= 0) { - return last_poly_mat_nr; - } - const int16_t current_mat_nr = obj_mesh_data.ith_poly_matnr(poly_index); - /* Whenever a polygon with a new material is encountered, write its material - * and/or group, otherwise pass. */ - if (last_poly_mat_nr == current_mat_nr) { - return current_mat_nr; - } - if (current_mat_nr == NOT_FOUND) { - file_handler_->write<eOBJSyntaxElement::poly_usemtl>(MATERIAL_GROUP_DISABLED); - return current_mat_nr; - } - if (export_params_.export_object_groups) { - write_object_group(obj_mesh_data); - } - const char *mat_name = matname_fn(current_mat_nr); - if (!mat_name) { - mat_name = MATERIAL_GROUP_DISABLED; - } - file_handler_->write<eOBJSyntaxElement::poly_usemtl>(mat_name); - - return current_mat_nr; + const Vector<float2> &uv_coords = r_obj_mesh_data.get_uv_coords(); + const int tot_count = uv_coords.size(); + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) { + const float2 &uv_vertex = uv_coords[i]; + buf.write<eOBJSyntaxElement::uv_vertex_coords>(uv_vertex[0], uv_vertex[1]); + }); } -int16_t OBJWriter::write_vertex_group(const OBJMesh &obj_mesh_data, - const int poly_index, - const int16_t last_poly_vertex_group) const +void OBJWriter::write_poly_normals(FormatHandler<eFileType::OBJ> &fh, OBJMesh &obj_mesh_data) { - if (!export_params_.export_vertex_groups) { - return last_poly_vertex_group; - } - const int16_t current_group = obj_mesh_data.get_poly_deform_group_index(poly_index); - - if (current_group == last_poly_vertex_group) { - /* No vertex group found in this polygon, just like in the last iteration. */ - return current_group; - } - if (current_group == NOT_FOUND) { - file_handler_->write<eOBJSyntaxElement::object_group>(DEFORM_GROUP_DISABLED); - return current_group; - } - file_handler_->write<eOBJSyntaxElement::object_group>( - obj_mesh_data.get_poly_deform_group_name(current_group)); - return current_group; + /* Poly normals should be calculated earlier via store_normal_coords_and_indices. */ + const Vector<float3> &normal_coords = obj_mesh_data.get_normal_coords(); + const int tot_count = normal_coords.size(); + obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) { + const float3 &normal = normal_coords[i]; + buf.write<eOBJSyntaxElement::normal>(normal[0], normal[1], normal[2]); + }); } OBJWriter::func_vert_uv_normal_indices OBJWriter::get_poly_element_writer( @@ -278,32 +268,85 @@ OBJWriter::func_vert_uv_normal_indices OBJWriter::get_poly_element_writer( return &OBJWriter::write_vert_indices; } -void OBJWriter::write_poly_elements(const OBJMesh &obj_mesh_data, - std::function<const char *(int)> matname_fn) +static int get_smooth_group(const OBJMesh &mesh, const OBJExportParams ¶ms, int poly_idx) { - int last_poly_smooth_group = NEGATIVE_INIT; - int16_t last_poly_vertex_group = NEGATIVE_INIT; - int16_t last_poly_mat_nr = NEGATIVE_INIT; + if (poly_idx < 0) { + return NEGATIVE_INIT; + } + int group = SMOOTH_GROUP_DISABLED; + if (mesh.is_ith_poly_smooth(poly_idx)) { + group = !params.export_smooth_groups ? SMOOTH_GROUP_DEFAULT : mesh.ith_smooth_group(poly_idx); + } + return group; +} +void OBJWriter::write_poly_elements(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + const OBJMesh &obj_mesh_data, + std::function<const char *(int)> matname_fn) +{ const func_vert_uv_normal_indices poly_element_writer = get_poly_element_writer( obj_mesh_data.tot_uv_vertices()); const int tot_polygons = obj_mesh_data.tot_polygons(); - for (int i = 0; i < tot_polygons; i++) { + obj_parallel_chunked_output(fh, tot_polygons, [&](FormatHandler<eFileType::OBJ> &buf, int i) { Vector<int> poly_vertex_indices = obj_mesh_data.calc_poly_vertex_indices(i); Span<int> poly_uv_indices = obj_mesh_data.calc_poly_uv_indices(i); Vector<int> poly_normal_indices = obj_mesh_data.calc_poly_normal_indices(i); - last_poly_smooth_group = write_smooth_group(obj_mesh_data, i, last_poly_smooth_group); - last_poly_vertex_group = write_vertex_group(obj_mesh_data, i, last_poly_vertex_group); - last_poly_mat_nr = write_poly_material(obj_mesh_data, i, last_poly_mat_nr, matname_fn); - (this->*poly_element_writer)(poly_vertex_indices, poly_uv_indices, poly_normal_indices); - } + /* Write smoothing group if different from previous. */ + { + const int prev_group = get_smooth_group(obj_mesh_data, export_params_, i - 1); + const int group = get_smooth_group(obj_mesh_data, export_params_, i); + if (group != prev_group) { + buf.write<eOBJSyntaxElement::smooth_group>(group); + } + } + + /* Write vertex group if different from previous. */ + if (export_params_.export_vertex_groups) { + const int16_t prev_group = i == 0 ? NEGATIVE_INIT : + obj_mesh_data.get_poly_deform_group_index(i - 1); + const int16_t group = obj_mesh_data.get_poly_deform_group_index(i); + if (group != prev_group) { + buf.write<eOBJSyntaxElement::object_group>( + group == NOT_FOUND ? DEFORM_GROUP_DISABLED : + obj_mesh_data.get_poly_deform_group_name(group)); + } + } + + /* Write material name and material group if different from previous. */ + if (export_params_.export_materials && obj_mesh_data.tot_materials() > 0) { + const int16_t prev_mat = i == 0 ? NEGATIVE_INIT : obj_mesh_data.ith_poly_matnr(i - 1); + const int16_t mat = obj_mesh_data.ith_poly_matnr(i); + if (mat != prev_mat) { + if (mat == NOT_FOUND) { + buf.write<eOBJSyntaxElement::poly_usemtl>(MATERIAL_GROUP_DISABLED); + } + else { + if (export_params_.export_object_groups) { + write_object_group(buf, obj_mesh_data); + } + const char *mat_name = matname_fn(mat); + if (!mat_name) { + mat_name = MATERIAL_GROUP_DISABLED; + } + buf.write<eOBJSyntaxElement::poly_usemtl>(mat_name); + } + } + } + + /* Write polygon elements. */ + (this->*poly_element_writer)( + buf, offsets, poly_vertex_indices, poly_uv_indices, poly_normal_indices); + }); } -void OBJWriter::write_edges_indices(const OBJMesh &obj_mesh_data) const +void OBJWriter::write_edges_indices(FormatHandler<eFileType::OBJ> &fh, + const IndexOffsets &offsets, + const OBJMesh &obj_mesh_data) const { - obj_mesh_data.ensure_mesh_edges(); + /* Note: ensure_mesh_edges should be called before. */ const int tot_edges = obj_mesh_data.tot_edges(); for (int edge_index = 0; edge_index < tot_edges; edge_index++) { const std::optional<std::array<int, 2>> vertex_indices = @@ -311,13 +354,13 @@ void OBJWriter::write_edges_indices(const OBJMesh &obj_mesh_data) const if (!vertex_indices) { continue; } - file_handler_->write<eOBJSyntaxElement::edge>( - (*vertex_indices)[0] + index_offsets_.vertex_offset + 1, - (*vertex_indices)[1] + index_offsets_.vertex_offset + 1); + fh.write<eOBJSyntaxElement::edge>((*vertex_indices)[0] + offsets.vertex_offset + 1, + (*vertex_indices)[1] + offsets.vertex_offset + 1); } } -void OBJWriter::write_nurbs_curve(const OBJCurve &obj_nurbs_data) const +void OBJWriter::write_nurbs_curve(FormatHandler<eFileType::OBJ> &fh, + const OBJCurve &obj_nurbs_data) const { const int total_splines = obj_nurbs_data.total_splines(); for (int spline_idx = 0; spline_idx < total_splines; spline_idx++) { @@ -325,15 +368,15 @@ void OBJWriter::write_nurbs_curve(const OBJCurve &obj_nurbs_data) const for (int vertex_idx = 0; vertex_idx < total_vertices; vertex_idx++) { const float3 vertex_coords = obj_nurbs_data.vertex_coordinates( spline_idx, vertex_idx, export_params_.scaling_factor); - file_handler_->write<eOBJSyntaxElement::vertex_coords>( + fh.write<eOBJSyntaxElement::vertex_coords>( vertex_coords[0], vertex_coords[1], vertex_coords[2]); } const char *nurbs_name = obj_nurbs_data.get_curve_name(); const int nurbs_degree = obj_nurbs_data.get_nurbs_degree(spline_idx); - file_handler_->write<eOBJSyntaxElement::object_group>(nurbs_name); - file_handler_->write<eOBJSyntaxElement::cstype>(); - file_handler_->write<eOBJSyntaxElement::nurbs_degree>(nurbs_degree); + fh.write<eOBJSyntaxElement::object_group>(nurbs_name); + fh.write<eOBJSyntaxElement::cstype>(); + fh.write<eOBJSyntaxElement::nurbs_degree>(nurbs_degree); /** * The numbers written here are indices into the vertex coordinates written * earlier, relative to the line that is going to be written. @@ -342,36 +385,42 @@ void OBJWriter::write_nurbs_curve(const OBJCurve &obj_nurbs_data) const * 0.0 1.0 -1 -2 -3 -4 -1 -2 -3 for a cyclic curve with 4 vertices. */ const int total_control_points = obj_nurbs_data.total_spline_control_points(spline_idx); - file_handler_->write<eOBJSyntaxElement::curve_element_begin>(); + fh.write<eOBJSyntaxElement::curve_element_begin>(); for (int i = 0; i < total_control_points; i++) { /* "+1" to keep indices one-based, even if they're negative: i.e., -1 refers to the * last vertex coordinate, -2 second last. */ - file_handler_->write<eOBJSyntaxElement::vertex_indices>(-((i % total_vertices) + 1)); + fh.write<eOBJSyntaxElement::vertex_indices>(-((i % total_vertices) + 1)); } - file_handler_->write<eOBJSyntaxElement::curve_element_end>(); + fh.write<eOBJSyntaxElement::curve_element_end>(); /** * In `parm u 0 0.1 ..` line:, (total control points + 2) equidistant numbers in the - * parameter range are inserted. + * parameter range are inserted. However for curves with endpoint flag, + * first degree+1 numbers are zeroes, and last degree+1 numbers are ones */ - file_handler_->write<eOBJSyntaxElement::nurbs_parameter_begin>(); + + const short flagsu = obj_nurbs_data.get_nurbs_flagu(spline_idx); + const bool cyclic = flagsu & CU_NURB_CYCLIC; + const bool endpoint = !cyclic && (flagsu & CU_NURB_ENDPOINT); + fh.write<eOBJSyntaxElement::nurbs_parameter_begin>(); for (int i = 1; i <= total_control_points + 2; i++) { - file_handler_->write<eOBJSyntaxElement::nurbs_parameters>(1.0f * i / - (total_control_points + 2 + 1)); + float parm = 1.0f * i / (total_control_points + 2 + 1); + if (endpoint) { + if (i <= nurbs_degree) { + parm = 0; + } + else if (i > total_control_points + 2 - nurbs_degree) { + parm = 1; + } + } + fh.write<eOBJSyntaxElement::nurbs_parameters>(parm); } - file_handler_->write<eOBJSyntaxElement::nurbs_parameter_end>(); + fh.write<eOBJSyntaxElement::nurbs_parameter_end>(); - file_handler_->write<eOBJSyntaxElement::nurbs_group_end>(); + fh.write<eOBJSyntaxElement::nurbs_group_end>(); } } -void OBJWriter::update_index_offsets(const OBJMesh &obj_mesh_data) -{ - index_offsets_.vertex_offset += obj_mesh_data.tot_vertices(); - index_offsets_.uv_vertex_offset += obj_mesh_data.tot_uv_vertices(); - index_offsets_.normal_offset += obj_mesh_data.tot_normal_indices(); -} - /* -------------------------------------------------------------------- */ /** \name .MTL writers. * \{ */ @@ -394,18 +443,31 @@ MTLWriter::MTLWriter(const char *obj_filepath) noexcept(false) if (!ok) { throw std::system_error(ENAMETOOLONG, std::system_category(), ""); } - file_handler_ = std::make_unique<FormattedFileHandler<eFileType::MTL>>(mtl_filepath_); + outfile_ = BLI_fopen(mtl_filepath_.c_str(), "wb"); + if (!outfile_) { + throw std::system_error(errno, std::system_category(), "Cannot open file " + mtl_filepath_); + } +} +MTLWriter::~MTLWriter() +{ + if (outfile_) { + fmt_handler_.write_to_file(outfile_); + if (std::fclose(outfile_)) { + std::cerr << "Error: could not close the file '" << mtl_filepath_ + << "' properly, it may be corrupted." << std::endl; + } + } } -void MTLWriter::write_header(const char *blen_filepath) const +void MTLWriter::write_header(const char *blen_filepath) { using namespace std::string_literals; const char *blen_basename = (blen_filepath && blen_filepath[0] != '\0') ? BLI_path_basename(blen_filepath) : "None"; - file_handler_->write<eMTLSyntaxElement::string>("# Blender "s + BKE_blender_version_string() + - " MTL File: '" + blen_basename + "'\n"); - file_handler_->write<eMTLSyntaxElement::string>("# www.blender.org\n"); + fmt_handler_.write<eMTLSyntaxElement::string>("# Blender "s + BKE_blender_version_string() + + " MTL File: '" + blen_basename + "'\n"); + fmt_handler_.write<eMTLSyntaxElement::string>("# www.blender.org\n"); } StringRefNull MTLWriter::mtl_file_path() const @@ -415,18 +477,18 @@ StringRefNull MTLWriter::mtl_file_path() const void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl_material) { - file_handler_->write<eMTLSyntaxElement::Ns>(mtl_material.Ns); - file_handler_->write<eMTLSyntaxElement::Ka>( + fmt_handler_.write<eMTLSyntaxElement::Ns>(mtl_material.Ns); + fmt_handler_.write<eMTLSyntaxElement::Ka>( mtl_material.Ka.x, mtl_material.Ka.y, mtl_material.Ka.z); - file_handler_->write<eMTLSyntaxElement::Kd>( + fmt_handler_.write<eMTLSyntaxElement::Kd>( mtl_material.Kd.x, mtl_material.Kd.y, mtl_material.Kd.z); - file_handler_->write<eMTLSyntaxElement::Ks>( + fmt_handler_.write<eMTLSyntaxElement::Ks>( mtl_material.Ks.x, mtl_material.Ks.y, mtl_material.Ks.z); - file_handler_->write<eMTLSyntaxElement::Ke>( + fmt_handler_.write<eMTLSyntaxElement::Ke>( mtl_material.Ke.x, mtl_material.Ke.y, mtl_material.Ke.z); - file_handler_->write<eMTLSyntaxElement::Ni>(mtl_material.Ni); - file_handler_->write<eMTLSyntaxElement::d>(mtl_material.d); - file_handler_->write<eMTLSyntaxElement::illum>(mtl_material.illum); + fmt_handler_.write<eMTLSyntaxElement::Ni>(mtl_material.Ni); + fmt_handler_.write<eMTLSyntaxElement::d>(mtl_material.d); + fmt_handler_.write<eMTLSyntaxElement::illum>(mtl_material.illum); } void MTLWriter::write_texture_map( @@ -449,8 +511,8 @@ void MTLWriter::write_texture_map( #define SYNTAX_DISPATCH(eMTLSyntaxElement) \ if (texture_map.key == eMTLSyntaxElement) { \ - file_handler_->write<eMTLSyntaxElement>(translation + scale + map_bump_strength, \ - texture_map.value.image_path); \ + fmt_handler_.write<eMTLSyntaxElement>(translation + scale + map_bump_strength, \ + texture_map.value.image_path); \ return; \ } @@ -474,8 +536,8 @@ void MTLWriter::write_materials() mtlmaterials_.end(), [](const MTLMaterial &a, const MTLMaterial &b) { return a.name < b.name; }); for (const MTLMaterial &mtlmat : mtlmaterials_) { - file_handler_->write<eMTLSyntaxElement::string>("\n"); - file_handler_->write<eMTLSyntaxElement::newmtl>(mtlmat.name); + fmt_handler_.write<eMTLSyntaxElement::string>("\n"); + fmt_handler_.write<eMTLSyntaxElement::newmtl>(mtlmat.name); write_bsdf_properties(mtlmat); for (const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map : mtlmat.texture_maps.items()) { |