Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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.cc416
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 &params, 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()) {