10#include <system_error>
60 : export_params_(export_params), outfile_path_(filepath), outfile_(
nullptr)
64 throw std::system_error(errno, std::system_category(),
"Cannot open file " + outfile_path_);
69 if (outfile_ && std::fclose(outfile_)) {
71 "Error: could not close file '%s' properly, it may be corrupted.",
72 outfile_path_.c_str());
76void OBJWriter::write_vert_uv_normal_indices(
FormatHandler &fh,
84 vert_indices.
size() == normal_indices.
size());
88 const int n = vert_indices.
size();
91 for (
int j = 0; j < n; ++j) {
93 uv_indices[j] + uv_offset,
94 normal_indices[j] + normal_offset);
101 for (
int k = 0; k < n; ++k) {
102 int j = k == 0 ? 0 : n - k;
104 uv_indices[j] + uv_offset,
105 normal_indices[j] + normal_offset);
113 Span<int> vert_indices,
115 Span<int> normal_indices,
119 const int vertex_offset = offsets.vertex_offset + 1;
120 const int normal_offset = offsets.normal_offset + 1;
121 const int n = vert_indices.
size();
122 fh.write_obj_face_begin();
124 for (
int j = 0; j < n; ++j) {
125 fh.write_obj_face_v_normal(vert_indices[j] + vertex_offset,
126 normal_indices[j] + normal_offset);
130 for (
int k = 0; k < n; ++k) {
131 int j = k == 0 ? 0 : n - k;
132 fh.write_obj_face_v_normal(vert_indices[j] + vertex_offset,
133 normal_indices[j] + normal_offset);
136 fh.write_obj_face_end();
141 Span<int> vert_indices,
142 Span<int> uv_indices,
147 const int vertex_offset = offsets.vertex_offset + 1;
148 const int uv_offset = offsets.uv_vertex_offset + 1;
149 const int n = vert_indices.
size();
150 fh.write_obj_face_begin();
152 for (
int j = 0; j < n; ++j) {
153 fh.write_obj_face_v_uv(vert_indices[j] + vertex_offset, uv_indices[j] + uv_offset);
157 for (
int k = 0; k < n; ++k) {
158 int j = k == 0 ? 0 : n - k;
159 fh.write_obj_face_v_uv(vert_indices[j] + vertex_offset, uv_indices[j] + uv_offset);
162 fh.write_obj_face_end();
167 Span<int> vert_indices,
172 const int vertex_offset = offsets.vertex_offset + 1;
173 const int n = vert_indices.
size();
174 fh.write_obj_face_begin();
176 for (
int j = 0; j < n; ++j) {
177 fh.write_obj_face_v(vert_indices[j] + vertex_offset);
181 for (
int k = 0; k < n; ++k) {
182 int j = k == 0 ? 0 : n - k;
183 fh.write_obj_face_v(vert_indices[j] + vertex_offset);
186 fh.write_obj_face_end();
191 using namespace std::string_literals;
205 sizeof(mtl_dir_name),
207 sizeof(mtl_file_name));
215 std::replace(r_name.begin(), r_name.end(),
' ',
'_');
222 if (export_params_.export_object_groups) {
245template<
typename Function>
248 if (tot_count <= 0) {
255 if (chunk_count == 1) {
256 for (
int i = 0;
i < tot_count;
i++) {
264 for (
const int r : range) {
266 int i_end = std::min(i_start +
chunk_size, tot_count);
268 for (
int i = i_start;
i < i_end;
i++) {
281 bool write_colors)
const
291 if (write_colors && !
name.is_empty()) {
317 const float2 &uv_vertex = uv_coords[i];
318 buf.write_obj_uv(uv_vertex[0], uv_vertex[1]);
327 const float3 &normal = normal_coords[i];
328 buf.write_obj_normal(normal[0], normal[1], normal[2]);
332OBJWriter::func_vert_uv_normal_indices OBJWriter::get_face_element_writer(
333 const int total_uv_vertices)
const
336 if (export_params_.
export_uv && (total_uv_vertices > 0)) {
338 return &OBJWriter::write_vert_uv_normal_indices;
341 return &OBJWriter::write_vert_normal_indices;
344 if (export_params_.
export_uv && (total_uv_vertices > 0)) {
345 return &OBJWriter::write_vert_uv_indices;
348 return &OBJWriter::write_vert_indices;
368 const func_vert_uv_normal_indices face_element_writer = get_face_element_writer(
371 const int tot_faces = obj_mesh_data.
tot_faces();
391 const int prev_group =
get_smooth_group(obj_mesh_data, export_params_, prev_i);
393 if (group != prev_group) {
399 if (export_params_.export_vertex_groups) {
401 local_weights.
resize(tot_deform_groups);
404 prev_i, local_weights);
406 if (group != prev_group) {
413 if ((export_params_.export_materials || export_params_.export_material_groups) &&
416 const int16_t prev_mat = idx == 0 ?
NEGATIVE_INIT : std::max(0, material_indices[prev_i]);
417 const int16_t mat = std::max(0, material_indices[
i]);
418 if (mat != prev_mat) {
420 if (export_params_.export_materials) {
425 const char *mat_name = matname_fn(mat);
429 if (export_params_.export_material_groups) {
434 if (export_params_.export_materials) {
442 (this->*face_element_writer)(buf,
453 const OBJMesh &obj_mesh_data)
const
457 if (loose_edges.
count == 0) {
474 float axes_transform[3][3];
482 world_axes_transform[3][3] = object_to_world[3][3];
490 return world_axes_transform;
496 for (
int spline_idx = 0; spline_idx < total_splines; spline_idx++) {
520 dynamic_point_buffer);
525 vertex_coords.
size()) :
527 for (
const int64_t index : point_loop_range) {
529 float3 co = vertex_coords[index % vertex_coords.
size()];
545 index = -(point_loop_range.
size() - (index % point_loop_range.
size()));
552 for (
const float &u : knots_u) {
577 "array size mismatch");
585 return fmt::format(
"{} {} {}", numbers[0], numbers[1], numbers[2]);
594 STRNCPY(mtl_path, obj_filepath);
598 throw std::system_error(ENAMETOOLONG, std::system_category(),
"");
601 mtl_filepath_ = mtl_path;
602 outfile_ =
BLI_fopen(mtl_filepath_.c_str(),
"wb");
604 throw std::system_error(errno, std::system_category(),
"Cannot open file " + mtl_filepath_);
610 fmt_handler_.write_to_file(outfile_);
611 if (std::fclose(outfile_)) {
613 "Error: could not close file '%s' properly, it may be corrupted.",
614 mtl_filepath_.c_str());
621 using namespace std::string_literals;
622 const char *blen_basename = (blen_filepath && blen_filepath[0] !=
'\0') ?
626 blen_basename +
"'");
627 fmt_handler_.write_string(
"# www.blender.org");
632 return mtl_filepath_;
635void MTLWriter::write_bsdf_properties(
const MTLMaterial &mtl,
bool write_pbr)
656 fmt_handler_.write_mtl_float3(
659 fmt_handler_.write_mtl_float(
"Ni", mtl.
ior);
661 fmt_handler_.write_mtl_float(
"d", mtl.
alpha);
667 fmt_handler_.write_mtl_float(
"Pr", mtl.
roughness);
670 fmt_handler_.write_mtl_float(
"Pm", mtl.
metallic);
673 fmt_handler_.write_mtl_float(
"Ps", mtl.
sheen);
681 if (mtl.
aniso >= 0.0f) {
682 fmt_handler_.write_mtl_float(
"aniso", mtl.
aniso);
685 fmt_handler_.write_mtl_float(
"anisor", mtl.
aniso_rot);
689 fmt_handler_.write_mtl_float3(
695void MTLWriter::write_texture_map(
const MTLMaterial &mtl_material,
698 const char *blen_filedir,
699 const char *dest_dir,
701 Set<std::pair<std::string, std::string>> ©_set)
705 if (texture_map.translation !=
float3{0.0f, 0.0f, 0.0f}) {
708 if (texture_map.scale !=
float3{1.0f, 1.0f, 1.0f}) {
712 options.append(
" -bm ").append(std::to_string(mtl_material.normal_strength));
716 texture_map.image_path.c_str(), blen_filedir, dest_dir, path_mode, ©_set);
718 std::replace(path.begin(), path.end(),
'\\',
'/');
736 const char *dest_dir,
739 if (mtlmaterials_.is_empty()) {
748 std::sort(mtlmaterials_.begin(),
753 fmt_handler_.write_string(
"");
754 fmt_handler_.write_mtl_newmtl(mtlmat.name);
755 write_bsdf_properties(mtlmat, write_pbr);
757 const MTLTexMap &tex = mtlmat.texture_maps[key];
768 mtlmat, (
MTLTexMapType)key, tex, blen_filedir, dest_dir, path_mode, copy_set);
784 int mtlmat_index = material_map_.lookup_default(material, -1);
785 if (mtlmat_index != -1) {
786 mtl_indices[
i] = mtlmat_index;
790 mtl_indices[
i] = mtlmaterials_.
size() - 1;
791 material_map_.add_new(material, mtl_indices[
i]);
799 if (index < 0 || index >= mtlmaterials_.size()) {
802 return mtlmaterials_[index].name.c_str();
const char * BKE_blender_version_string(void)
#define BLI_STATIC_ASSERT(a, msg)
File and directory operations.
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
void unit_m3(float m[3][3])
void mul_m4_v3(const float M[4][4], float r[3])
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4])
bool mat3_from_axis_conversion(int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3])
MINLINE void mul_v3_fl(float r[3], float f)
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool BLI_path_extension_replace(char *path, size_t path_maxncpy, const char *ext) ATTR_NONNULL(1
void BLI_path_slash_native(char *path) ATTR_NONNULL(1)
int BLI_path_normalize(char *path) ATTR_NONNULL(1)
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
char * STRNCPY(char(&dst)[N], const char *src)
#define CLOG_ERROR(clg_ref,...)
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
constexpr int64_t size() const
constexpr IndexRange drop_back(int64_t n) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr int64_t size() const
constexpr const T & last(const int64_t n=0) const
constexpr IndexRange index_range() const
constexpr const char * data() const
T get(const int64_t index) const
void resize(const int64_t new_size)
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
virtual int total_splines() const =0
virtual int num_control_points_v(int spline_index) const =0
virtual const char * get_curve_name() const =0
virtual Span< float3 > vertex_coordinates(int spline_index, Vector< float3 > &dynamic_point_buffer) const =0
virtual Span< float > get_knots_u(int spline_index, Vector< float > &buffer) const =0
virtual int num_control_points_u(int spline_index) const =0
virtual int get_nurbs_degree_u(int spline_index) const =0
virtual const float4x4 & object_transform() const =0
MTLWriter(const char *obj_filepath, bool write_file) noexcept(false)
Vector< int > add_materials(const OBJMesh &mesh_to_export)
void write_header(const char *blen_filepath)
void write_materials(const char *blen_filepath, ePathReferenceMode path_mode, const char *dest_dir, bool write_pbr)
StringRefNull mtl_file_path() const
const char * mtlmaterial_name(int index)
const char * get_face_deform_group_name(int16_t def_group_index) const
int16_t get_face_deform_group_index(int face_index, MutableSpan< float > group_weights) const
bool is_ith_face_smooth(int face_index) const
int tot_deform_groups() const
int16_t tot_materials() const
StringRef get_object_mesh_name() const
Span< int > get_face_uv_indices(const int face_index) const
bool is_mirrored_transform() const
int remap_face_index(int i) const
int tot_uv_vertices() const
Array< const Material * > materials
Span< float3 > get_normal_coords() const
const float4x4 & get_world_axes_transform() const
StringRef get_object_name() const
Span< int > get_face_normal_indices(const int face_index) const
Span< int > calc_face_vert_indices(const int face_index) const
Span< float2 > get_uv_coords() const
int ith_smooth_group(int face_index) const
const Mesh * get_mesh() const
void write_normals(FormatHandler &fh, OBJMesh &obj_mesh_data)
OBJWriter(const char *filepath, const OBJExportParams &export_params) noexcept(false)
void write_mtllib_name(StringRefNull mtl_filepath) const
void write_uv_coords(FormatHandler &fh, OBJMesh &obj_mesh_data) const
void write_header() const
void write_nurbs_curve(FormatHandler &fh, const IOBJCurve &obj_nurbs_data) const
void write_face_elements(FormatHandler &fh, const IndexOffsets &offsets, const OBJMesh &obj_mesh_data, FunctionRef< const char *(int)> matname_fn)
void write_vertex_coords(FormatHandler &fh, const OBJMesh &obj_mesh_data, bool write_colors) const
void write_edges_indices(FormatHandler &fh, const IndexOffsets &offsets, const OBJMesh &obj_mesh_data) const
void write_object_name(FormatHandler &fh, const OBJMesh &obj_mesh_data) const
CCL_NAMESPACE_BEGIN struct Options options
static void spaces_to_underscores(std::string &r_name)
static bool is_pbr_map(MTLTexMapType type)
static const char * tex_map_type_to_string[]
const int SMOOTH_GROUP_DEFAULT
static const char * MATERIAL_GROUP_DISABLED
Span< float > valid_nurb_control_point_range(const int8_t order, const Span< float > knots, IndexRange &point_range)
MTLMaterial mtlmaterial_for_material(const Material *material)
static float4x4 compute_world_axes_transform(const OBJExportParams &export_params, const blender::float4x4 &object_to_world)
const int SMOOTH_GROUP_DISABLED
static int get_smooth_group(const OBJMesh &mesh, const OBJExportParams ¶ms, int face_idx)
void obj_parallel_chunked_output(FormatHandler &fh, int tot_count, const Function &function)
static bool is_non_pbr_map(MTLTexMapType type)
static std::string float3_to_string(const float3 &numbers)
static const int chunk_size
static int calc_chunk_count(int count)
static const char * DEFORM_GROUP_DISABLED
std::string path_reference(StringRefNull filepath, StringRefNull base_src, StringRefNull base_dst, ePathReferenceMode mode, Set< std::pair< std::string, std::string > > *copy_set)
void path_reference_copy(const Set< std::pair< std::string, std::string > > ©_set)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
char * active_color_attribute
const c_style_mat & ptr() const
blender::BitVector is_loose_bits
const MTLTexMap & tex_map_of_type(MTLTexMapType key) const