Blender V5.0
object_visual_geometry_to_objects.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_context.hh"
6#include "BKE_curves.hh"
7#include "BKE_geometry_set.hh"
10#include "BKE_instances.hh"
11#include "BKE_layer.hh"
12#include "BKE_lib_id.hh"
13#include "BKE_main.hh"
14#include "BKE_material.hh"
15#include "BKE_mesh.h"
16#include "BKE_mesh.hh"
17#include "BKE_multires.hh"
18#include "BKE_object.hh"
19#include "BKE_pointcloud.hh"
20
22
24#include "DNA_curves_types.h"
26#include "DNA_material_types.h"
27#include "DNA_mesh_types.h"
29
30#include "ED_object.hh"
31#include "ED_screen.hh"
32
33#include "WM_api.hh"
34#include "WM_types.hh"
35
36#include "BLI_listbase.h"
37#include "BLI_map.hh"
38#include "BLI_math_matrix.h"
39#include "BLI_math_matrix.hh"
40
41#include "object_intern.hh"
42
43namespace blender::ed::object {
44
47{
48 float3 location;
49 math::EulerXYZ rotation;
50 float3 scale;
51 math::to_loc_rot_scale_safe<true>(transform, location, rotation, scale);
52 copy_v3_v3(ob.loc, location);
53 copy_v3_v3(ob.rot, float3(rotation.x().radian(), rotation.y().radian(), rotation.z().radian()));
54 copy_v3_v3(ob.scale, scale);
56}
57
60 Object *mesh_ob = nullptr;
61 Object *curves_ob = nullptr;
65
67 {
68 Vector<Object *> objects;
69 if (mesh_ob) {
70 objects.append(mesh_ob);
71 }
72 if (curves_ob) {
73 objects.append(curves_ob);
74 }
75 if (pointcloud_ob) {
76 objects.append(pointcloud_ob);
77 }
78 if (greasepencil_ob) {
79 objects.append(greasepencil_ob);
80 }
81 for (Object *instance_object : instance_objects) {
82 objects.append(instance_object);
83 }
84 return objects;
85 }
86};
87
88static void copy_materials_to_new_geometry_object(const Object &src_ob_eval,
89 const ID &src_data_eval,
90 Object &dst_ob_orig,
91 ID &dst_data_orig)
92{
93 const int materials_num = BKE_id_material_used_eval(src_data_eval);
94 if (materials_num == 0) {
95 return;
96 }
97 *BKE_id_material_len_p(&dst_data_orig) = materials_num;
98 dst_ob_orig.totcol = materials_num;
99
100 dst_ob_orig.matbits = MEM_calloc_arrayN<char>(materials_num, __func__);
101 dst_ob_orig.mat = MEM_calloc_arrayN<Material *>(materials_num, __func__);
102 Material ***dst_materials = BKE_id_material_array_p(&dst_data_orig);
103 *dst_materials = MEM_calloc_arrayN<Material *>(materials_num, __func__);
104
105 for (int i = 0; i < materials_num; i++) {
106 const Material *material_eval = BKE_object_material_get_eval(
107 src_ob_eval, src_data_eval, i + 1);
108 Material *material_orig = const_cast<Material *>(DEG_get_original(material_eval));
109 if (material_orig) {
110 (*dst_materials)[i] = material_orig;
111 id_us_plus(&material_orig->id);
112 }
113 }
114}
115
117 /* A collection that should be instanced. */
119 /* A transform that needs to be applied to instances of that collection. */
121};
122
125 private:
126 Main &bmain_;
127 Map<const ID *, Object *> new_object_by_generated_geometry_;
129 Vector<Collection *> new_instance_collections_;
130
131 public:
132 GeometryToObjectsBuilder(Main &bmain) : bmain_(bmain) {}
133
136 {
137 ComponentObjects component_objects = this->get_objects_for_geometry(src_ob_eval, geometry);
138 const StringRefNull name = geometry.name.empty() ? StringRefNull(BKE_id_name(src_ob_eval.id)) :
140 return this->collection_from_component_objects(component_objects, name);
141 }
142
145 {
146 const StringRefNull name = geometry.name.empty() ? StringRefNull(BKE_id_name(src_ob_eval.id)) :
148 ComponentObjects objects;
149 if (const Mesh *mesh = geometry.get_mesh()) {
150 if (mesh->verts_num > 0) {
151 objects.mesh_ob = this->ensure_object_for_mesh(src_ob_eval, *mesh, name);
152 }
153 }
154 if (const Curves *curves = geometry.get_curves()) {
155 if (curves->geometry.curve_num > 0) {
156 objects.curves_ob = this->ensure_object_for_curves(src_ob_eval, *curves, name);
157 }
158 }
159 if (const PointCloud *pointcloud = geometry.get_pointcloud()) {
160 if (pointcloud->totpoint > 0) {
161 objects.pointcloud_ob = this->ensure_object_for_pointcloud(src_ob_eval, *pointcloud, name);
162 }
163 }
164 if (const GreasePencil *greasepencil = geometry.get_grease_pencil()) {
165 if (greasepencil->layers().size() > 0) {
166 objects.greasepencil_ob = this->ensure_object_for_grease_pencil(
167 src_ob_eval, *greasepencil, name);
168 }
169 }
170 if (const bke::Instances *instances = geometry.get_instances()) {
171 objects.instance_objects = this->create_objects_for_instances(src_ob_eval, *instances);
172 }
173 return objects;
174 }
175
177 {
178 return new_instance_collections_;
179 }
180
181 private:
182 Collection *collection_from_component_objects(const ComponentObjects &component_objects,
183 const StringRefNull name)
184 {
185 Collection *collection = BKE_collection_add(&bmain_, nullptr, name.c_str());
186 for (Object *object : component_objects.all_objects()) {
187 BKE_collection_object_add(&bmain_, collection, object);
188 }
189 return collection;
190 }
191
192 Object *ensure_object_for_mesh(const Object &src_ob_eval,
193 const Mesh &src_mesh,
194 const StringRefNull name)
195 {
196 return new_object_by_generated_geometry_.lookup_or_add_cb(&src_mesh.id, [&]() {
197 Mesh *new_mesh = BKE_id_new<Mesh>(&bmain_, name.c_str());
198 Object *new_ob = BKE_object_add_only_object(&bmain_, OB_MESH, name.c_str());
199 new_ob->data = new_mesh;
200
201 BKE_mesh_nomain_to_mesh(BKE_mesh_copy_for_eval(src_mesh), new_mesh, new_ob);
202 new_mesh->attributes_for_write().remove_anonymous();
203 copy_materials_to_new_geometry_object(src_ob_eval, src_mesh.id, *new_ob, new_mesh->id);
204 bke::mesh_remove_invalid_attribute_strings(*new_mesh);
205 multires_customdata_delete(new_mesh);
206 return new_ob;
207 });
208 }
209
210 Object *ensure_object_for_curves(const Object &src_ob_eval,
211 const Curves &src_curves,
212 const StringRefNull name)
213 {
214 return new_object_by_generated_geometry_.lookup_or_add_cb(&src_curves.id, [&]() {
215 Curves *new_curves = BKE_id_new<Curves>(&bmain_, name.c_str());
216 Object *new_ob = BKE_object_add_only_object(&bmain_, OB_CURVES, name.c_str());
217 new_ob->data = new_curves;
218
219 new_curves->geometry.wrap() = src_curves.geometry.wrap();
220 new_curves->geometry.wrap().attributes_for_write().remove_anonymous();
221 copy_materials_to_new_geometry_object(src_ob_eval, src_curves.id, *new_ob, new_curves->id);
222 return new_ob;
223 });
224 }
225
226 Object *ensure_object_for_pointcloud(const Object &src_ob_eval,
227 const PointCloud &src_pointcloud,
228 const StringRefNull name)
229 {
230 return new_object_by_generated_geometry_.lookup_or_add_cb(&src_pointcloud.id, [&]() {
231 PointCloud *new_pointcloud = BKE_id_new<PointCloud>(&bmain_, name.c_str());
232 Object *new_ob = BKE_object_add_only_object(&bmain_, OB_POINTCLOUD, name.c_str());
233 new_ob->data = new_pointcloud;
234
235 BKE_pointcloud_nomain_to_pointcloud(BKE_pointcloud_copy_for_eval(&src_pointcloud),
236 new_pointcloud);
237 new_pointcloud->attributes_for_write().remove_anonymous();
238 copy_materials_to_new_geometry_object(
239 src_ob_eval, src_pointcloud.id, *new_ob, new_pointcloud->id);
240 return new_ob;
241 });
242 }
243
244 Object *ensure_object_for_grease_pencil(const Object &src_ob_eval,
245 const GreasePencil &src_grease_pencil,
246 const StringRefNull name)
247 {
248 return new_object_by_generated_geometry_.lookup_or_add_cb(&src_grease_pencil.id, [&]() {
249 GreasePencil *new_grease_pencil = BKE_id_new<GreasePencil>(&bmain_, name.c_str());
250 Object *new_ob = BKE_object_add_only_object(&bmain_, OB_GREASE_PENCIL, name.c_str());
251 new_ob->data = new_grease_pencil;
252
253 GreasePencil *greasepencil_to_move_from = BKE_grease_pencil_copy_for_eval(
254 &src_grease_pencil);
255 BKE_grease_pencil_nomain_to_grease_pencil(greasepencil_to_move_from, new_grease_pencil);
256 new_grease_pencil->attributes_for_write().remove_anonymous();
257 for (GreasePencilDrawingBase *base : new_grease_pencil->drawings()) {
258 if (base->type != GP_DRAWING) {
259 continue;
260 }
261 bke::greasepencil::Drawing &drawing =
262 reinterpret_cast<GreasePencilDrawing *>(base)->wrap();
263 drawing.strokes_for_write().attributes_for_write().remove_anonymous();
264 }
266 src_ob_eval, src_grease_pencil.id, *new_ob, new_grease_pencil->id);
267 return new_ob;
268 });
269 }
270
271 Vector<Object *> create_objects_for_instances(const Object &src_ob_eval,
272 const bke::Instances &src_instances)
273 {
274 if (std::optional<Vector<Object *>> simple_objects = this->create_objects_for_instances_simple(
275 src_ob_eval, src_instances))
276 {
277 return *simple_objects;
278 }
279
280 bke::Instances instances = src_instances;
281 instances.remove_unused_references();
282
283 /* Each instance will be a collection instance, so we need to get the collection for each
284 * #InstanceReference that is instanced. */
285 Vector<CollectionWithTransform> data_by_handle;
286 for (const bke::InstanceReference &reference : instances.references()) {
287 data_by_handle.append(
288 this->get_or_create_collection_for_instance_reference(src_ob_eval, reference));
289 }
290
291 const Span<int> handles = instances.reference_handles();
292 const Span<float4x4> transforms = instances.transforms();
293
294 Vector<Object *> objects;
295 for (const int instance_i : IndexRange(instances.instances_num())) {
296 const int handle = handles[instance_i];
297 if (!data_by_handle.index_range().contains(handle)) {
298 continue;
299 }
300 const CollectionWithTransform &instance = data_by_handle[handle];
301 if (!instance.collection) {
302 continue;
303 }
304 /* Create an empty object that then instances the collection. */
305 Object *instance_object = BKE_object_add_only_object(
306 &bmain_, OB_EMPTY, BKE_id_name(instance.collection->id));
307 instance_object->transflag = OB_DUPLICOLLECTION;
308 instance_object->instance_collection = instance.collection;
309 id_us_plus(&instance.collection->id);
310
311 const float4x4 &transform = transforms[instance_i];
312 set_local_object_transform(*instance_object, transform * instance.transform);
313
314 objects.append(instance_object);
315 }
316 return objects;
317 }
318
324 std::optional<Vector<Object *>> create_objects_for_instances_simple(
325 const Object &src_ob_eval, const bke::Instances &src_instances)
326 {
327 const Span<float4x4> transforms = src_instances.transforms();
328 const Span<int> handles = src_instances.reference_handles();
329 const Span<bke::InstanceReference> references = src_instances.references();
330
331 Vector<Object *> objects;
332 for (const int i : IndexRange(src_instances.instances_num())) {
333 const float4x4 &transform = transforms[i];
334 if (transform != float4x4::identity()) {
335 return std::nullopt;
336 }
337 const int handle = handles[i];
338 if (handle < 0 || handle >= references.size()) {
339 return std::nullopt;
340 }
341 const bke::InstanceReference &reference = references[handle];
342 switch (reference.type()) {
344 break;
345 }
347 Object &object_eval = reference.object();
348 Object *object_orig = DEG_get_original(&object_eval);
349 if (ELEM(object_orig, &src_ob_eval, nullptr)) {
350 return std::nullopt;
351 }
352 objects.append(object_orig);
353 break;
354 }
356 return std::nullopt;
357 }
359 const ComponentObjects component_objects = this->get_objects_for_geometry(
360 src_ob_eval, reference.geometry_set());
361 objects.extend(component_objects.all_objects());
362 break;
363 }
364 }
365 }
366
367 return objects;
368 }
369
370 CollectionWithTransform get_or_create_collection_for_instance_reference(
371 const Object &src_ob_eval, const bke::InstanceReference &reference)
372 {
373 if (const CollectionWithTransform *instance = collection_by_instance_.lookup_ptr(reference)) {
374 return *instance;
375 }
377 switch (reference.type()) {
379 break;
380 }
382 /* Create a collection for the object because we can't instance objects directly. */
383 Object &object_eval = reference.object();
384 Object *object_orig = DEG_get_original(&object_eval);
385
386 if (object_orig->type == OB_EMPTY && object_orig->instance_collection) {
387 instance.collection = object_orig->instance_collection;
388 }
389 else {
390 instance.collection = BKE_collection_add(&bmain_, nullptr, BKE_id_name(object_orig->id));
391 new_instance_collections_.append(instance.collection);
392 BKE_collection_object_add(&bmain_, instance.collection, object_orig);
393
394 /* Handle the object transform because it may not be the identity matrix. The location is
395 * handled by setting the collection instance offset to it. The rotation and scale are
396 * handled by offsetting the instance using the collection by the inverse amount. */
397 float4x4 object_transform;
398 BKE_object_to_mat4(object_orig, object_transform.ptr());
399 instance.transform = float4x4(math::invert(float3x3(object_transform)));
400 copy_v3_v3(instance.collection->instance_offset, object_transform.location());
401 }
402 break;
403 }
405 /* For collections, we don't need to create a new wrapper collection, we can just create
406 * objects that instance the existing collection. */
407 Collection &collection_eval = reference.collection();
408 Collection *collection_orig = DEG_get_original(&collection_eval);
409 instance.collection = collection_orig;
410 break;
411 }
413 instance.collection = this->build_collection_for_geometry(src_ob_eval,
414 reference.geometry_set());
415 new_instance_collections_.append(instance.collection);
416 break;
417 }
418 }
419 collection_by_instance_.add(reference, instance);
420 return instance;
421 }
422};
423
425 Scene *scene,
426 Object &object)
427{
428 VectorSet<Collection *> collections;
429 FOREACH_COLLECTION_BEGIN (&bmain, scene, Collection *, collection) {
430 if (BKE_collection_has_object(collection, &object)) {
431 collections.add(collection);
432 }
433 }
435 return collections.extract_vector();
436}
437
439{
440 Main &bmain = *CTX_data_main(C);
441 Scene &scene = *CTX_data_scene(C);
443 ViewLayer &active_view_layer = *CTX_data_view_layer(C);
444
445 Vector<Object *> selected_objects_orig;
446 CTX_DATA_BEGIN (C, Object *, src_ob_orig, selected_objects) {
447 selected_objects_orig.append(src_ob_orig);
448 }
450
451 /* Create all required objects and collections and add them to bmain. However, so far nothing is
452 * linked to the scene or view layer. That happens below. */
453 GeometryToObjectsBuilder op(bmain);
454 Vector<Object *> all_new_top_level_objects;
455 for (Object *src_ob_orig : selected_objects_orig) {
456 Object *src_ob_eval = DEG_get_evaluated(&depsgraph, src_ob_orig);
457 bke::GeometrySet geometry_eval = bke::object_get_evaluated_geometry_set(*src_ob_eval);
458 const ComponentObjects new_component_objects = op.get_objects_for_geometry(*src_ob_eval,
459 geometry_eval);
460 const Vector<Object *> top_level_objects = new_component_objects.all_objects();
461 all_new_top_level_objects.extend(top_level_objects);
462 /* Find the collections that the active object is in, because we want to add the new objects
463 * in the same place. */
464 const Vector<Collection *> collections_to_add_to = find_collections_containing_object(
465 bmain, &scene, *src_ob_orig);
466
467 float4x4 src_ob_local_transform;
468 BKE_object_to_mat4(src_ob_eval, src_ob_local_transform.ptr());
469
470 for (Object *object : top_level_objects) {
471 /* Link the new objects into some collections. */
472 for (Collection *collection_to_add_to : collections_to_add_to) {
473 BKE_collection_object_add(&bmain, collection_to_add_to, object);
474 }
475 /* Transform and parent the objects so that they align with the source object. */
476 float4x4 old_transform;
477 BKE_object_to_mat4(object, old_transform.ptr());
478 set_local_object_transform(*object, src_ob_local_transform * old_transform);
479 object->parent = src_ob_orig->parent;
480 copy_m4_m4(object->parentinv, src_ob_orig->parentinv);
481 }
482 }
483
484 const Span<Collection *> new_instance_collections = op.new_instance_collections();
485 for (Collection *new_collection : new_instance_collections) {
486 /* Add the new collections to the scene collection. This makes them more visible to the user,
487 * compared to having collection instances which use collections that are not in the scene. */
488 BKE_collection_child_add(&bmain, scene.master_collection, new_collection);
489 }
490 /* Ensure that the #Base for objects and #LayerCollection for collections are created. */
492
493 /* Deselect everything so that we can select the new objects. */
494 BKE_view_layer_base_deselect_all(&scene, &active_view_layer);
495 /* Select the new objects. */
496 for (Object *object : all_new_top_level_objects) {
497 Base *base = BKE_view_layer_base_find(&active_view_layer, object);
498 base->flag |= BASE_SELECTED;
499 }
500 /* Make one of the new objects active. */
501 if (!all_new_top_level_objects.is_empty()) {
502 Base *first_base = BKE_view_layer_base_find(&active_view_layer, all_new_top_level_objects[0]);
503 BKE_view_layer_base_select_and_set_active(&active_view_layer, first_base);
504 base_active_refresh(&bmain, &scene, &active_view_layer);
505 }
506 /* Exclude the new collections. This is done because they are only instanced by other objects but
507 * should not be visible by themselves. */
508 LISTBASE_FOREACH (ViewLayer *, view_layer, &scene.view_layers) {
509 for (Collection *new_collection : new_instance_collections) {
511 view_layer, new_collection);
512 BKE_layer_collection_set_flag(new_layer_collection, LAYER_COLLECTION_EXCLUDE, true);
513 }
514 }
515 BKE_view_layer_need_resync_tag(&active_view_layer);
517
523 return OPERATOR_FINISHED;
524}
525
527{
528 ot->name = "Visual Geometry to Objects";
529 ot->description = "Convert geometry and instances into editable objects and collections";
530 ot->idname = "OBJECT_OT_visual_geometry_to_objects";
531
534
536}
537
538} // namespace blender::ed::object
#define FOREACH_COLLECTION_BEGIN(_bmain, _scene, Type, _instance)
Collection * BKE_collection_add(Main *bmain, Collection *collection_parent, const char *name_custom)
bool BKE_collection_has_object(Collection *collection, const Object *ob)
bool BKE_collection_child_add(Main *bmain, Collection *parent, Collection *child)
#define FOREACH_COLLECTION_END
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
#define CTX_DATA_BEGIN(C, Type, instance, member)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
#define CTX_DATA_END
ViewLayer * CTX_data_view_layer(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
LayerCollection * BKE_layer_collection_first_from_scene_collection(const ViewLayer *view_layer, const Collection *collection)
void BKE_view_layer_base_deselect_all(const Scene *scene, ViewLayer *view_layer)
void BKE_scene_view_layers_synced_ensure(const Scene *scene)
void BKE_view_layer_need_resync_tag(ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
void BKE_layer_collection_set_flag(LayerCollection *lc, int flag, bool value)
void BKE_view_layer_base_select_and_set_active(ViewLayer *view_layer, Base *selbase)
void id_us_plus(ID *id)
Definition lib_id.cc:358
const char * BKE_id_name(const ID &id)
General operations, lookup, etc. for materials.
short * BKE_id_material_len_p(ID *id)
Material *** BKE_id_material_array_p(ID *id)
Material * BKE_object_material_get_eval(Object *ob, short act)
int BKE_id_material_used_eval(const ID &id)
General operations, lookup, etc. for blender objects.
Object * BKE_object_add_only_object(Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
void BKE_object_to_mat4(const Object *ob, float r_mat[4][4])
General operations for point clouds.
#define LISTBASE_FOREACH(type, var, list)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
T * DEG_get_original(T *id)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1104
@ ROT_MODE_EUL
Object groups, one object can be in many groups at once.
struct Collection Collection
struct GreasePencil GreasePencil
@ LAYER_COLLECTION_EXCLUDE
@ OB_EMPTY
@ OB_DUPLICOLLECTION
struct Object Object
struct PointCloud PointCloud
#define BASE_SELECTED(v3d, base)
@ OPERATOR_FINISHED
bool ED_operator_object_active(bContext *C)
#define C
Definition RandGen.cpp:29
#define ND_DRAW
Definition WM_types.hh:461
#define ND_OB_SELECT
Definition WM_types.hh:442
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_LAYER_CONTENT
Definition WM_types.hh:453
#define ND_LAYER
Definition WM_types.hh:450
#define NC_OBJECT
Definition WM_types.hh:379
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
constexpr bool contains(int64_t value) const
constexpr int64_t size() const
Definition BLI_span.hh:252
void append(const T &value)
IndexRange index_range() const
void extend(Span< T > array)
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:508
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:620
bool add(const Key &key)
void append(const T &value)
bool is_empty() const
void extend(Span< T > array)
ComponentObjects get_objects_for_geometry(const Object &src_ob_eval, const bke::GeometrySet &geometry)
Collection * build_collection_for_geometry(const Object &src_ob_eval, const bke::GeometrySet &geometry)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
GeometrySet object_get_evaluated_geometry_set(const Object &object, bool apply_subdiv=true)
static void set_local_object_transform(Object &ob, const float4x4 &transform)
static void copy_materials_to_new_geometry_object(const Object &src_ob_eval, const ID &src_data_eval, Object &dst_ob_orig, ID &dst_data_orig)
void base_active_refresh(Main *bmain, Scene *scene, ViewLayer *view_layer)
static wmOperatorStatus visual_geometry_to_objects_exec(bContext *C, wmOperator *)
static Vector< Collection * > find_collections_containing_object(Main &bmain, Scene *scene, Object &object)
void OBJECT_OT_visual_geometry_to_objects(wmOperatorType *ot)
EulerXYZBase< float > EulerXYZ
CartesianBasis invert(const CartesianBasis &basis)
void to_loc_rot_scale_safe(const MatBase< T, 4, 4 > &mat, VecBase< T, 3 > &r_location, RotationT &r_rotation, VecBase< T, 3 > &r_scale)
MatBase< float, 4, 4 > float4x4
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
const char * name
short flag
Definition DNA_ID.h:414
short transflag
struct Collection * instance_collection
struct Material ** mat
float loc[3]
char * matbits
float scale[3]
float rot[3]
struct Collection * master_collection
ListBase view_layers
const c_style_mat & ptr() const
i
Definition text_draw.cc:230
ParamHandle ** handles
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237