10#include <system_error>
57 : export_params_(export_params), outfile_path_(filepath), outfile_(
nullptr)
61 throw std::system_error(errno, std::system_category(),
"Cannot open file " + outfile_path_);
66 if (outfile_ && std::fclose(outfile_)) {
68 "Error: could not close file '%s' properly, it may be corrupted.",
69 outfile_path_.c_str());
73void OBJWriter::write_vert_uv_normal_indices(
FormatHandler &fh,
81 vert_indices.
size() == normal_indices.
size());
85 const int n = vert_indices.
size();
88 for (
int j = 0; j < n; ++j) {
90 uv_indices[j] + uv_offset,
91 normal_indices[j] + normal_offset);
98 for (
int k = 0; k < n; ++k) {
99 int j = k == 0 ? 0 : n - k;
101 uv_indices[j] + uv_offset,
102 normal_indices[j] + normal_offset);
110 Span<int> vert_indices,
112 Span<int> normal_indices,
116 const int vertex_offset = offsets.vertex_offset + 1;
117 const int normal_offset = offsets.normal_offset + 1;
118 const int n = vert_indices.
size();
119 fh.write_obj_face_begin();
121 for (
int j = 0; j < n; ++j) {
122 fh.write_obj_face_v_normal(vert_indices[j] + vertex_offset,
123 normal_indices[j] + normal_offset);
127 for (
int k = 0; k < n; ++k) {
128 int j = k == 0 ? 0 : n - k;
129 fh.write_obj_face_v_normal(vert_indices[j] + vertex_offset,
130 normal_indices[j] + normal_offset);
133 fh.write_obj_face_end();
138 Span<int> vert_indices,
139 Span<int> uv_indices,
144 const int vertex_offset = offsets.vertex_offset + 1;
145 const int uv_offset = offsets.uv_vertex_offset + 1;
146 const int n = vert_indices.
size();
147 fh.write_obj_face_begin();
149 for (
int j = 0; j < n; ++j) {
150 fh.write_obj_face_v_uv(vert_indices[j] + vertex_offset, uv_indices[j] + uv_offset);
154 for (
int k = 0; k < n; ++k) {
155 int j = k == 0 ? 0 : n - k;
156 fh.write_obj_face_v_uv(vert_indices[j] + vertex_offset, uv_indices[j] + uv_offset);
159 fh.write_obj_face_end();
164 Span<int> vert_indices,
169 const int vertex_offset = offsets.vertex_offset + 1;
170 const int n = vert_indices.
size();
171 fh.write_obj_face_begin();
173 for (
int j = 0; j < n; ++j) {
174 fh.write_obj_face_v(vert_indices[j] + vertex_offset);
178 for (
int k = 0; k < n; ++k) {
179 int j = k == 0 ? 0 : n - k;
180 fh.write_obj_face_v(vert_indices[j] + vertex_offset);
183 fh.write_obj_face_end();
188 using namespace std::string_literals;
202 sizeof(mtl_dir_name),
204 sizeof(mtl_file_name));
212 std::replace(r_name.begin(), r_name.end(),
' ',
'_');
219 if (export_params_.export_object_groups) {
242template<
typename Function>
245 if (tot_count <= 0) {
252 if (chunk_count == 1) {
253 for (
int i = 0;
i < tot_count;
i++) {
261 for (
const int r : range) {
263 int i_end = std::min(i_start +
chunk_size, tot_count);
265 for (
int i = i_start;
i < i_end;
i++) {
278 bool write_colors)
const
288 if (write_colors && !name.
is_empty()) {
314 const float2 &uv_vertex = uv_coords[i];
315 buf.write_obj_uv(uv_vertex[0], uv_vertex[1]);
324 const float3 &normal = normal_coords[i];
325 buf.write_obj_normal(normal[0], normal[1], normal[2]);
329OBJWriter::func_vert_uv_normal_indices OBJWriter::get_face_element_writer(
330 const int total_uv_vertices)
const
333 if (export_params_.
export_uv && (total_uv_vertices > 0)) {
335 return &OBJWriter::write_vert_uv_normal_indices;
338 return &OBJWriter::write_vert_normal_indices;
341 if (export_params_.
export_uv && (total_uv_vertices > 0)) {
342 return &OBJWriter::write_vert_uv_indices;
345 return &OBJWriter::write_vert_indices;
365 const func_vert_uv_normal_indices face_element_writer = get_face_element_writer(
368 const int tot_faces = obj_mesh_data.
tot_faces();
388 const int prev_group =
get_smooth_group(obj_mesh_data, export_params_, prev_i);
390 if (group != prev_group) {
396 if (export_params_.export_vertex_groups) {
398 local_weights.
resize(tot_deform_groups);
401 prev_i, local_weights);
403 if (group != prev_group) {
410 if ((export_params_.export_materials || export_params_.export_material_groups) &&
413 const int16_t prev_mat = idx == 0 ?
NEGATIVE_INIT : std::max(0, material_indices[prev_i]);
414 const int16_t mat = std::max(0, material_indices[
i]);
415 if (mat != prev_mat) {
417 if (export_params_.export_materials) {
422 const char *mat_name = matname_fn(mat);
426 if (export_params_.export_material_groups) {
431 if (export_params_.export_materials) {
439 (this->*face_element_writer)(buf,
450 const OBJMesh &obj_mesh_data)
const
454 if (loose_edges.
count == 0) {
471 for (
int spline_idx = 0; spline_idx < total_splines; spline_idx++) {
477 for (
int vertex_idx = 0; vertex_idx < total_vertices; vertex_idx++) {
479 spline_idx, vertex_idx, export_params_.global_scale);
503 for (
int i = 0;
i < num_points_u;
i++) {
511 for (
const float &u : knotsu) {
536 "array size mismatch");
544 return fmt::format(
"{} {} {}", numbers[0], numbers[1], numbers[2]);
553 STRNCPY(mtl_path, obj_filepath);
557 throw std::system_error(ENAMETOOLONG, std::system_category(),
"");
560 mtl_filepath_ = mtl_path;
561 outfile_ =
BLI_fopen(mtl_filepath_.c_str(),
"wb");
563 throw std::system_error(errno, std::system_category(),
"Cannot open file " + mtl_filepath_);
569 fmt_handler_.write_to_file(outfile_);
570 if (std::fclose(outfile_)) {
572 "Error: could not close file '%s' properly, it may be corrupted.",
573 mtl_filepath_.c_str());
580 using namespace std::string_literals;
581 const char *blen_basename = (blen_filepath && blen_filepath[0] !=
'\0') ?
585 blen_basename +
"'");
586 fmt_handler_.write_string(
"# www.blender.org");
591 return mtl_filepath_;
594void MTLWriter::write_bsdf_properties(
const MTLMaterial &mtl,
bool write_pbr)
615 fmt_handler_.write_mtl_float3(
618 fmt_handler_.write_mtl_float(
"Ni", mtl.
ior);
620 fmt_handler_.write_mtl_float(
"d", mtl.
alpha);
626 fmt_handler_.write_mtl_float(
"Pr", mtl.
roughness);
629 fmt_handler_.write_mtl_float(
"Pm", mtl.
metallic);
632 fmt_handler_.write_mtl_float(
"Ps", mtl.
sheen);
640 if (mtl.
aniso >= 0.0f) {
641 fmt_handler_.write_mtl_float(
"aniso", mtl.
aniso);
644 fmt_handler_.write_mtl_float(
"anisor", mtl.
aniso_rot);
648 fmt_handler_.write_mtl_float3(
654void MTLWriter::write_texture_map(
const MTLMaterial &mtl_material,
657 const char *blen_filedir,
658 const char *dest_dir,
660 Set<std::pair<std::string, std::string>> ©_set)
664 if (texture_map.translation !=
float3{0.0f, 0.0f, 0.0f}) {
667 if (texture_map.scale !=
float3{1.0f, 1.0f, 1.0f}) {
671 options.append(
" -bm ").append(std::to_string(mtl_material.normal_strength));
675 texture_map.image_path.c_str(), blen_filedir, dest_dir, path_mode, ©_set);
677 std::replace(path.begin(), path.end(),
'\\',
'/');
695 const char *dest_dir,
698 if (mtlmaterials_.is_empty()) {
707 std::sort(mtlmaterials_.begin(),
712 fmt_handler_.write_string(
"");
713 fmt_handler_.write_mtl_newmtl(mtlmat.name);
714 write_bsdf_properties(mtlmat, write_pbr);
716 const MTLTexMap &tex = mtlmat.texture_maps[key];
727 mtlmat, (
MTLTexMapType)key, tex, blen_filedir, dest_dir, path_mode, copy_set);
740 r_mtl_indices[
i] = -1;
743 int mtlmat_index = material_map_.lookup_default(material, -1);
744 if (mtlmat_index != -1) {
745 r_mtl_indices[
i] = mtlmat_index;
749 r_mtl_indices[
i] = mtlmaterials_.
size() - 1;
750 material_map_.add_new(material, r_mtl_indices[
i]);
753 return r_mtl_indices;
758 if (index < 0 || index >= mtlmaterials_.size()) {
761 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 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 int64_t size() const
constexpr const T & last(const int64_t n=0) const
constexpr IndexRange index_range() const
constexpr bool is_empty() 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, eCustomDataType data_type, const void *default_value=nullptr) const
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)
int total_spline_vertices(int spline_index) const
const Nurb * get_spline(int spline_index) const
float3 vertex_coordinates(int spline_index, int vertex_index, float global_scale) const
int get_nurbs_degree_u(int spline_index) const
int num_control_points_u(int spline_index) const
const char * get_curve_name() const
int total_splines() const
Span< float > get_knots_u(int spline_index, Vector< float > &buffer) const
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 OBJCurve &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
MTLMaterial mtlmaterial_for_material(const Material *material)
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
blender::BitVector is_loose_bits
const MTLTexMap & tex_map_of_type(MTLTexMapType key) const