Blender V5.0
obj_importer.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <string>
10
11#include "BLI_bounds.hh"
12#include "BLI_listbase.h"
13#include "BLI_map.hh"
14#include "BLI_math_vector.h"
15#include "BLI_set.hh"
16#include "BLI_sort.hh"
17#include "BLI_string.h"
18#include "BLI_string_ref.hh"
19
20#include "BKE_context.hh"
22#include "BKE_geometry_set.hh"
23#include "BKE_instances.hh"
24#include "BKE_layer.hh"
25#include "BKE_lib_id.hh"
26#include "BKE_object.hh"
27
29
31
32#include "obj_export_mtl.hh"
34#include "obj_import_mesh.hh"
35#include "obj_import_nurbs.hh"
36#include "obj_import_objects.hh"
37#include "obj_importer.hh"
38
39namespace blender::io::obj {
40
42 Collection *target,
43 const std::string &geom_name,
44 const OBJImportParams &import_params)
45{
46 if (target == nullptr || import_params.collection_separator == 0) {
47 return target;
48 }
49 size_t subname_start = 0;
50 size_t sep_pos = geom_name.find(import_params.collection_separator);
51 if (sep_pos == std::string::npos) {
52 return target;
53 }
54 while (sep_pos != std::string::npos) {
55 /* Get current sub-name, find or create collection with that name. */
56 if (sep_pos > subname_start) {
57 std::string subname = geom_name.substr(subname_start, sep_pos - subname_start);
58 bool found = false;
59 LISTBASE_FOREACH (CollectionChild *, child, &target->children) {
60 if (GS(child->collection->id.name) == ID_GR &&
61 STREQ(child->collection->id.name + 2, subname.c_str()))
62 {
63 target = child->collection;
64 found = true;
65 break;
66 }
67 }
68 if (!found) {
69 target = BKE_collection_add(bmain, target, subname.c_str());
70 }
71 }
72
73 /* Proceed to next sub-name component. */
74 subname_start = sep_pos + 1;
75 if (subname_start >= geom_name.size()) {
76 break;
77 }
78 sep_pos = geom_name.find(import_params.collection_separator, subname_start);
79 }
80 return target;
81}
82
83static void geometry_to_blender_geometry_set(const OBJImportParams &import_params,
84 const Span<std::unique_ptr<Geometry>> all_geometries,
85 const GlobalVertices &global_vertices,
86 Vector<bke::GeometrySet> &geometries)
87{
88 for (const std::unique_ptr<Geometry> &geometry : all_geometries) {
89 bke::GeometrySet geometry_set;
90
91 if (geometry->geom_type_ == GEOM_MESH) {
92 MeshFromGeometry mesh_ob_from_geometry{*geometry, global_vertices};
93 Mesh *mesh = mesh_ob_from_geometry.create_mesh(import_params);
94 geometry_set = bke::GeometrySet::from_mesh(mesh);
95 }
96 else if (geometry->geom_type_ == GEOM_CURVE) {
97 CurveFromGeometry curve_ob_from_geometry(*geometry, global_vertices);
98 Curves *curves_id = curve_ob_from_geometry.create_curve(import_params);
99 geometry_set = bke::GeometrySet::from_curves(curves_id);
100 }
101
102 geometry_set.name = geometry->geometry_name_;
103 geometries.append(std::move(geometry_set));
104 }
105}
106
111 Scene *scene,
112 ViewLayer *view_layer,
113 const OBJImportParams &import_params,
114 MutableSpan<std::unique_ptr<Geometry>> all_geometries,
115 const GlobalVertices &global_vertices,
116 Map<std::string, std::unique_ptr<MTLMaterial>> &materials,
117 Map<std::string, Material *> &created_materials)
118{
120
121 /* Sort objects by name: creating many objects is much faster if the creation
122 * order is sorted by name. */
124 all_geometries.begin(), all_geometries.end(), [](const auto &a, const auto &b) {
125 const char *na = a ? a->geometry_name_.c_str() : "";
126 const char *nb = b ? b->geometry_name_.c_str() : "";
127 return BLI_strcasecmp(na, nb) < 0;
128 });
129
130 /* Create all the objects. */
131 Vector<Object *> objects;
132 objects.reserve(all_geometries.size());
133 Set<Collection *> collections;
134 for (const std::unique_ptr<Geometry> &geometry : all_geometries) {
135 Object *obj = nullptr;
136 if (geometry->geom_type_ == GEOM_MESH) {
137 MeshFromGeometry mesh_ob_from_geometry{*geometry, global_vertices};
138 obj = mesh_ob_from_geometry.create_mesh_object(
139 bmain, materials, created_materials, import_params);
140 }
141 else if (geometry->geom_type_ == GEOM_CURVE) {
142 CurveFromGeometry curve_ob_from_geometry(*geometry, global_vertices);
143 obj = curve_ob_from_geometry.create_curve_object(bmain, import_params);
144 }
145 if (obj != nullptr) {
146 Collection *target_collection = find_or_create_collection(
147 bmain, lc->collection, geometry->geometry_name_, import_params);
148 collections.add(target_collection);
149
150 BKE_collection_object_add(bmain, target_collection, obj);
151 objects.append(obj);
152 }
153 }
154
155 /* Clamp object size if needed. */
156 if (import_params.clamp_size > 0.0f) {
157 std::optional<Bounds<float3>> bounds = std::nullopt;
158 for (Object *obj : objects) {
160 }
161 if (bounds.has_value()) {
162 const float max_diff = math::reduce_max(bounds->max - bounds->min);
163 if (import_params.clamp_size < max_diff * import_params.global_scale) {
164 const float scale = import_params.clamp_size / max_diff;
165 for (Object *obj : objects) {
166 copy_v3_fl(obj->scale, scale);
167 }
168 }
169 }
170 }
171
172 /* Do object selections in a separate loop (allows just one view layer sync). */
173 BKE_view_layer_synced_ensure(scene, view_layer);
174 for (Object *obj : objects) {
175 Base *base = BKE_view_layer_base_find(view_layer, obj);
177
180 DEG_id_tag_update_ex(bmain, &obj->id, flags);
181 }
182 for (Collection *col : collections) {
184 }
185
188}
189
190void importer_geometry(const OBJImportParams &import_params,
191 Vector<bke::GeometrySet> &geometries,
192 size_t read_buffer_size)
193{
194 /* List of geometries to be parsed from OBJ file. */
195 Vector<std::unique_ptr<Geometry>> all_geometries;
196 /* Container for vertex and UV vertex coordinates. */
197 GlobalVertices global_vertices;
198
199 OBJParser obj_parser{import_params, read_buffer_size};
200 obj_parser.parse(all_geometries, global_vertices);
201
202 geometry_to_blender_geometry_set(import_params, all_geometries, global_vertices, geometries);
203}
204
205void importer_main(bContext *C, const OBJImportParams &import_params)
206{
207 Main *bmain = CTX_data_main(C);
208 Scene *scene = CTX_data_scene(C);
209 ViewLayer *view_layer = CTX_data_view_layer(C);
210 importer_main(bmain, scene, view_layer, import_params);
211}
212
213void importer_main(Main *bmain,
214 Scene *scene,
215 ViewLayer *view_layer,
216 const OBJImportParams &import_params,
217 size_t read_buffer_size)
218{
219 /* List of geometries to be parsed from OBJ file. */
220 Vector<std::unique_ptr<Geometry>> all_geometries;
221 /* Container for vertex and UV vertex coordinates. */
222 GlobalVertices global_vertices;
223 /* List of MTLMaterial instances to be parsed from MTL file. */
225 Map<std::string, Material *> created_materials;
226
227 OBJParser obj_parser{import_params, read_buffer_size};
228 obj_parser.parse(all_geometries, global_vertices);
229
230 /* Parse all referenced MTL files */
231 for (StringRefNull mtl_library : obj_parser.mtl_libraries()) {
232 MTLParser mtl_parser{mtl_library, import_params.filepath};
233 mtl_parser.parse_and_store(materials);
234 }
235
236 if (import_params.clear_selection) {
237 BKE_view_layer_base_deselect_all(scene, view_layer);
238 }
239
240 /* Create Blender objects from the parsed geometries */
242 scene,
243 view_layer,
244 import_params,
245 all_geometries,
246 global_vertices,
247 materials,
248 created_materials);
249}
250} // namespace blender::io::obj
Collection * BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
LayerCollection * BKE_layer_collection_get_active(ViewLayer *view_layer)
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
void BKE_view_layer_base_deselect_all(const Scene *scene, ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
void BKE_view_layer_base_select_and_set_active(ViewLayer *view_layer, Base *selbase)
General operations, lookup, etc. for blender objects.
std::optional< blender::Bounds< blender::float3 > > BKE_object_boundbox_get(const Object *ob)
#define LISTBASE_FOREACH(type, var, list)
MINLINE void copy_v3_fl(float r[3], float f)
#define STREQ(a, b)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1054
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1118
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:1077
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1104
@ ID_GR
Object groups, one object can be in many groups at once.
#define C
Definition RandGen.cpp:29
bool add(const Key &key)
Definition BLI_set.hh:248
void append(const T &value)
void reserve(const int64_t min_capacity)
Object * create_curve_object(Main *bmain, const OBJImportParams &import_params)
Curves * create_curve(const OBJImportParams &import_params)
void parse_and_store(Map< std::string, std::unique_ptr< MTLMaterial > > &r_materials)
Mesh * create_mesh(const OBJImportParams &import_params)
Object * create_mesh_object(Main *bmain, Map< std::string, std::unique_ptr< MTLMaterial > > &materials, Map< std::string, Material * > &created_materials, const OBJImportParams &import_params)
Span< std::string > mtl_libraries() const
void parse(Vector< std::unique_ptr< Geometry > > &r_all_geometries, GlobalVertices &r_global_vertices)
#define GS(x)
uint col
DEG_id_tag_update_ex(cb_data->bmain, cb_data->owner_id, ID_RECALC_TAG_FOR_UNDO|ID_RECALC_SYNC_TO_EVAL)
Bounds< T > merge(const Bounds< T > &a, const Bounds< T > &b)
Definition BLI_bounds.hh:26
static Collection * find_or_create_collection(Main *bmain, Collection *target, const std::string &geom_name, const OBJImportParams &import_params)
static void geometry_to_blender_objects(Main *bmain, Scene *scene, ViewLayer *view_layer, const OBJImportParams &import_params, MutableSpan< std::unique_ptr< Geometry > > all_geometries, const GlobalVertices &global_vertices, Map< std::string, std::unique_ptr< MTLMaterial > > &materials, Map< std::string, Material * > &created_materials)
void importer_geometry(const OBJImportParams &import_params, Vector< bke::GeometrySet > &geometries, size_t read_buffer_size)
static void geometry_to_blender_geometry_set(const OBJImportParams &import_params, const Span< std::unique_ptr< Geometry > > all_geometries, const GlobalVertices &global_vertices, Vector< bke::GeometrySet > &geometries)
void importer_main(bContext *C, const OBJImportParams &import_params)
T reduce_max(const VecBase< T, Size > &a)
void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end)
Definition BLI_sort.hh:23
struct Collection * collection
char filepath[FILE_MAX]
static GeometrySet from_curves(Curves *curves, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
static GeometrySet from_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)