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

obj_export_file_writer.hh « exporter « wavefront_obj « io « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 97c23484426467c672cfa39141b57f5dc059a3d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/* SPDX-License-Identifier: GPL-2.0-or-later */

/** \file
 * \ingroup obj
 */

#pragma once

#include "DNA_meshdata_types.h"

#include "BLI_map.hh"
#include "BLI_set.hh"
#include "BLI_vector.hh"

#include "IO_wavefront_obj.h"
#include "obj_export_io.hh"
#include "obj_export_mtl.hh"

namespace blender::io::obj {

class OBJCurve;
class OBJMesh;
/**
 * Total vertices/ UV vertices/ normals of previous Objects
 * should be added to the current Object's indices.
 */
struct IndexOffsets {
  int vertex_offset;
  int uv_vertex_offset;
  int normal_offset;
};

/**
 * Responsible for writing a .OBJ file.
 */
class OBJWriter : NonMovable, NonCopyable {
 private:
  const OBJExportParams &export_params_;
  std::string outfile_path_;
  FILE *outfile_;

 public:
  OBJWriter(const char *filepath, const OBJExportParams &export_params) noexcept(false)
      : export_params_(export_params), outfile_path_(filepath), outfile_(nullptr)
  {
    outfile_ = BLI_fopen(filepath, "wb");
    if (!outfile_) {
      throw std::system_error(errno, std::system_category(), "Cannot open file " + outfile_path_);
    }
  }
  ~OBJWriter()
  {
    if (outfile_ && std::fclose(outfile_)) {
      std::cerr << "Error: could not close the file '" << outfile_path_
                << "' properly, it may be corrupted." << std::endl;
    }
  }

  FILE *get_outfile() const
  {
    return outfile_;
  }

  void write_header() const;

  /**
   * Write object's name or group.
   */
  void write_object_name(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const;
  /**
   * Write file name of Material Library in .OBJ file.
   */
  void write_mtllib_name(const StringRefNull mtl_filepath) const;
  /**
   * Write vertex coordinates for all vertices as "v x y z" or "v x y z r g b".
   */
  void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
                           const OBJMesh &obj_mesh_data,
                           bool write_colors) const;
  /**
   * Write UV vertex coordinates for all vertices as `vt u v`.
   * \note UV indices are stored here, but written with polygons later.
   */
  void write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &obj_mesh_data) const;
  /**
   * Write loop normals for smooth-shaded polygons, and polygon normals otherwise, as "vn x y z".
   * \note Normal indices ares stored here, but written with polygons later.
   */
  void write_poly_normals(FormatHandler<eFileType::OBJ> &fh, OBJMesh &obj_mesh_data);
  /**
   * Write polygon elements with at least vertex indices, and conditionally with UV vertex
   * indices and polygon normal indices. Also write groups: smooth, vertex, material.
   * The matname_fn turns a 0-indexed material slot number in an Object into the
   * name used in the .obj file.
   * \note UV indices were stored while writing UV vertices.
   */
  void write_poly_elements(FormatHandler<eFileType::OBJ> &fh,
                           const IndexOffsets &offsets,
                           const OBJMesh &obj_mesh_data,
                           std::function<const char *(int)> matname_fn);
  /**
   * Write loose edges of a mesh as "l v1 v2".
   */
  void write_edges_indices(FormatHandler<eFileType::OBJ> &fh,
                           const IndexOffsets &offsets,
                           const OBJMesh &obj_mesh_data) const;
  /**
   * Write a NURBS curve to the .OBJ file in parameter form.
   */
  void write_nurbs_curve(FormatHandler<eFileType::OBJ> &fh, const OBJCurve &obj_nurbs_data) const;

 private:
  using func_vert_uv_normal_indices = void (OBJWriter::*)(FormatHandler<eFileType::OBJ> &fh,
                                                          const IndexOffsets &offsets,
                                                          Span<int> vert_indices,
                                                          Span<int> uv_indices,
                                                          Span<int> normal_indices,
                                                          bool flip) const;
  /**
   * \return Writer function with appropriate polygon-element syntax.
   */
  func_vert_uv_normal_indices get_poly_element_writer(int total_uv_vertices) const;

  /**
   * Write one line of polygon indices as "f v1/vt1/vn1 v2/vt2/vn2 ...".
   */
  void write_vert_uv_normal_indices(FormatHandler<eFileType::OBJ> &fh,
                                    const IndexOffsets &offsets,
                                    Span<int> vert_indices,
                                    Span<int> uv_indices,
                                    Span<int> normal_indices,
                                    bool flip) const;
  /**
   * Write one line of polygon indices as "f v1//vn1 v2//vn2 ...".
   */
  void write_vert_normal_indices(FormatHandler<eFileType::OBJ> &fh,
                                 const IndexOffsets &offsets,
                                 Span<int> vert_indices,
                                 Span<int> /*uv_indices*/,
                                 Span<int> normal_indices,
                                 bool flip) const;
  /**
   * Write one line of polygon indices as "f v1/vt1 v2/vt2 ...".
   */
  void write_vert_uv_indices(FormatHandler<eFileType::OBJ> &fh,
                             const IndexOffsets &offsets,
                             Span<int> vert_indices,
                             Span<int> uv_indices,
                             Span<int> /*normal_indices*/,
                             bool flip) const;
  /**
   * Write one line of polygon indices as "f v1 v2 ...".
   */
  void write_vert_indices(FormatHandler<eFileType::OBJ> &fh,
                          const IndexOffsets &offsets,
                          Span<int> vert_indices,
                          Span<int> /*uv_indices*/,
                          Span<int> /*normal_indices*/,
                          bool flip) const;
};

/**
 * Responsible for writing a .MTL file.
 */
class MTLWriter : NonMovable, NonCopyable {
 private:
  FormatHandler<eFileType::MTL> fmt_handler_;
  FILE *outfile_;
  std::string mtl_filepath_;
  Vector<MTLMaterial> mtlmaterials_;
  /* Map from a Material* to an index into mtlmaterials_. */
  Map<const Material *, int> material_map_;

 public:
  /*
   * Create the .MTL file.
   */
  MTLWriter(const char *obj_filepath) noexcept(false);
  ~MTLWriter();

  void write_header(const char *blen_filepath);
  /**
   * Write all of the material specifications to the MTL file.
   * For consistency of output from run to run (useful for testing),
   * the materials are sorted by name before writing.
   */
  void write_materials(const char *blen_filepath,
                       ePathReferenceMode path_mode,
                       const char *dest_dir);
  StringRefNull mtl_file_path() const;
  /**
   * Add the materials of the given object to #MTLWriter, de-duplicating
   * against ones that are already there.
   * Return a Vector of indices into mtlmaterials_ that hold the #MTLMaterial
   * that corresponds to each material slot, in order, of the given Object.
   * Indexes are returned rather than pointers to the MTLMaterials themselves
   * because the mtlmaterials_ Vector may move around when resized.
   */
  Vector<int> add_materials(const OBJMesh &mesh_to_export);
  const char *mtlmaterial_name(int index);

 private:
  /**
   * Write properties sourced from p-BSDF node or #Object.Material.
   */
  void write_bsdf_properties(const MTLMaterial &mtl_material);
  /**
   * Write a texture map in the form "map_XX -s 1. 1. 1. -o 0. 0. 0. [-bm 1.] path/to/image".
   */
  void write_texture_map(const MTLMaterial &mtl_material,
                         const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map,
                         const char *blen_filedir,
                         const char *dest_dir,
                         ePathReferenceMode mode,
                         Set<std::pair<std::string, std::string>> &copy_set);
};
}  // namespace blender::io::obj