Blender V4.5
object_add.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cctype>
10#include <cstdlib>
11#include <cstring>
12#include <optional>
13
14#include "DNA_anim_types.h"
15#include "DNA_camera_types.h"
17#include "DNA_curve_types.h"
19#include "DNA_key_types.h"
20#include "DNA_light_types.h"
22#include "DNA_material_types.h"
23#include "DNA_mesh_types.h"
24#include "DNA_meta_types.h"
25#include "DNA_modifier_types.h"
27#include "DNA_object_types.h"
29#include "DNA_scene_types.h"
30#include "DNA_vfont_types.h"
31
32#include "BLI_array_utils.hh"
33#include "BLI_ghash.h"
34#include "BLI_listbase.h"
35#include "BLI_math_matrix.h"
37#include "BLI_math_rotation.h"
39#include "BLI_rand.hh"
40#include "BLI_string.h"
41#include "BLI_string_utf8.h"
42#include "BLI_utildefines.h"
43#include "BLI_vector.hh"
44
45#include "BLT_translation.hh"
46
47#include "BKE_action.hh"
48#include "BKE_anim_data.hh"
50#include "BKE_armature.hh"
51#include "BKE_camera.h"
52#include "BKE_collection.hh"
53#include "BKE_constraint.h"
54#include "BKE_context.hh"
55#include "BKE_curve.hh"
57#include "BKE_curve_to_mesh.hh"
58#include "BKE_curves.h"
59#include "BKE_curves.hh"
60#include "BKE_customdata.hh"
61#include "BKE_deform.hh"
62#include "BKE_displist.h"
63#include "BKE_duplilist.hh"
64#include "BKE_effect.h"
65#include "BKE_geometry_set.hh"
68#include "BKE_gpencil_legacy.h"
70#include "BKE_grease_pencil.hh"
72#include "BKE_key.hh"
73#include "BKE_lattice.hh"
74#include "BKE_layer.hh"
75#include "BKE_lib_id.hh"
76#include "BKE_lib_override.hh"
77#include "BKE_lib_query.hh"
78#include "BKE_lib_remap.hh"
79#include "BKE_library.hh"
80#include "BKE_light.h"
81#include "BKE_lightprobe.h"
82#include "BKE_main.hh"
83#include "BKE_material.hh"
84#include "BKE_mball.hh"
85#include "BKE_mesh.hh"
86#include "BKE_mesh_runtime.hh"
87#include "BKE_modifier.hh"
88#include "BKE_nla.hh"
89#include "BKE_node.hh"
90#include "BKE_object.hh"
91#include "BKE_object_types.hh"
92#include "BKE_particle.h"
93#include "BKE_pointcloud.hh"
94#include "BKE_report.hh"
95#include "BKE_scene.hh"
96#include "BKE_speaker.h"
97#include "BKE_vfont.hh"
98#include "BKE_volume.hh"
99
100#include "DEG_depsgraph.hh"
101#include "DEG_depsgraph_build.hh"
102#include "DEG_depsgraph_query.hh"
103
104#include "GEO_join_geometries.hh"
105#include "GEO_mesh_to_curve.hh"
106
107#include "RNA_access.hh"
108#include "RNA_define.hh"
109#include "RNA_enum_types.hh"
110
111#include "UI_interface.hh"
112
113#include "WM_api.hh"
114#include "WM_types.hh"
115
116#include "ED_armature.hh"
117#include "ED_curve.hh"
118#include "ED_curves.hh"
119#include "ED_gpencil_legacy.hh"
120#include "ED_grease_pencil.hh"
121#include "ED_mball.hh"
122#include "ED_mesh.hh"
123#include "ED_node.hh"
124#include "ED_object.hh"
125#include "ED_outliner.hh"
126#include "ED_physics.hh"
127#include "ED_pointcloud.hh"
128#include "ED_render.hh"
129#include "ED_screen.hh"
130#include "ED_select_utils.hh"
131#include "ED_transform.hh"
132#include "ED_view3d.hh"
133
135
136#include "UI_resources.hh"
137
138#include "object_intern.hh"
139
141 {LA_LOCAL, "POINT", ICON_LIGHT_POINT, "Point", "Omnidirectional point light source"},
142 {LA_SUN, "SUN", ICON_LIGHT_SUN, "Sun", "Constant direction parallel ray light source"},
143 {LA_SPOT, "SPOT", ICON_LIGHT_SPOT, "Spot", "Directional cone light source"},
144 {LA_AREA, "AREA", ICON_LIGHT_AREA, "Area", "Directional area light source"},
145 {0, nullptr, 0, nullptr, nullptr},
146};
147
148namespace blender::ed::object {
149
150/* -------------------------------------------------------------------- */
153
154/* This is an exact copy of the define in `rna_light.cc`
155 * kept here because of linking order.
156 * Icons are only defined here. */
157
158/* copy from rna_object_force.cc */
160 {PFIELD_FORCE, "FORCE", ICON_FORCE_FORCE, "Force", ""},
161 {PFIELD_WIND, "WIND", ICON_FORCE_WIND, "Wind", ""},
162 {PFIELD_VORTEX, "VORTEX", ICON_FORCE_VORTEX, "Vortex", ""},
163 {PFIELD_MAGNET, "MAGNET", ICON_FORCE_MAGNETIC, "Magnetic", ""},
164 {PFIELD_HARMONIC, "HARMONIC", ICON_FORCE_HARMONIC, "Harmonic", ""},
165 {PFIELD_CHARGE, "CHARGE", ICON_FORCE_CHARGE, "Charge", ""},
166 {PFIELD_LENNARDJ, "LENNARDJ", ICON_FORCE_LENNARDJONES, "Lennard-Jones", ""},
167 {PFIELD_TEXTURE, "TEXTURE", ICON_FORCE_TEXTURE, "Texture", ""},
168 {PFIELD_GUIDE, "GUIDE", ICON_FORCE_CURVE, "Curve Guide", ""},
169 {PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""},
170 {PFIELD_TURBULENCE, "TURBULENCE", ICON_FORCE_TURBULENCE, "Turbulence", ""},
171 {PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", ""},
172 {PFIELD_FLUIDFLOW, "FLUID", ICON_FORCE_FLUIDFLOW, "Fluid Flow", ""},
173 {0, nullptr, 0, nullptr, nullptr},
174};
175
178 "SPHERE",
179 ICON_LIGHTPROBE_SPHERE,
180 "Sphere",
181 "Light probe that captures precise lighting from all directions at a single point in space"},
183 "PLANE",
184 ICON_LIGHTPROBE_PLANE,
185 "Plane",
186 "Light probe that captures incoming light from a single direction on a plane"},
188 "VOLUME",
189 ICON_LIGHTPROBE_VOLUME,
190 "Volume",
191 "Light probe that captures low frequency lighting inside a volume"},
192 {0, nullptr, 0, nullptr, nullptr},
193};
194
195enum {
199};
200
202 {ALIGN_WORLD, "WORLD", 0, "World", "Align the new object to the world"},
203 {ALIGN_VIEW, "VIEW", 0, "View", "Align the new object to the view"},
204 {ALIGN_CURSOR, "CURSOR", 0, "3D Cursor", "Use the 3D cursor orientation for the new object"},
205 {0, nullptr, 0, nullptr, nullptr},
206};
207
209
210/* -------------------------------------------------------------------- */
213
219{
220 PropertyRNA *prop;
221
222 prop = RNA_def_int(ot->srna,
223 "drop_x",
224 0,
225 INT_MIN,
226 INT_MAX,
227 "Drop X",
228 "X-coordinate (screen space) to place the new object under",
229 INT_MIN,
230 INT_MAX);
232 prop = RNA_def_int(ot->srna,
233 "drop_y",
234 0,
235 INT_MIN,
236 INT_MAX,
237 "Drop Y",
238 "Y-coordinate (screen space) to place the new object under",
239 INT_MIN,
240 INT_MAX);
242}
243
245{
246 return RNA_struct_property_is_set(op->ptr, "drop_x") &&
247 RNA_struct_property_is_set(op->ptr, "drop_y");
248}
249
254static bool object_add_drop_xy_get(bContext *C, wmOperator *op, int (*r_mval)[2])
255{
256 if (!object_add_drop_xy_is_set(op)) {
257 (*r_mval)[0] = 0.0f;
258 (*r_mval)[1] = 0.0f;
259 return false;
260 }
261
262 const ARegion *region = CTX_wm_region(C);
263 (*r_mval)[0] = RNA_int_get(op->ptr, "drop_x") - region->winrct.xmin;
264 (*r_mval)[1] = RNA_int_get(op->ptr, "drop_y") - region->winrct.ymin;
265
266 return true;
267}
268
274 wmOperator *op,
275 const wmEvent *event)
276{
277 if (!object_add_drop_xy_is_set(op)) {
278 RNA_int_set(op->ptr, "drop_x", event->xy[0]);
279 RNA_int_set(op->ptr, "drop_y", event->xy[1]);
280 }
281 return op->type->exec(C, op);
282}
283
285
286/* -------------------------------------------------------------------- */
289
290void location_from_view(bContext *C, float loc[3])
291{
292 const Scene *scene = CTX_data_scene(C);
293 copy_v3_v3(loc, scene->cursor.location);
294}
295
296void rotation_from_quat(float rot[3], const float viewquat[4], const char align_axis)
297{
298 BLI_assert(align_axis >= 'X' && align_axis <= 'Z');
299
300 switch (align_axis) {
301 case 'X': {
302 /* Same as 'rv3d->viewinv[1]' */
303 const float axis_y[4] = {0.0f, 1.0f, 0.0f};
304 float quat_y[4], quat[4];
305 axis_angle_to_quat(quat_y, axis_y, M_PI_2);
306 mul_qt_qtqt(quat, viewquat, quat_y);
307 quat_to_eul(rot, quat);
308 break;
309 }
310 case 'Y': {
311 quat_to_eul(rot, viewquat);
312 rot[0] -= float(M_PI_2);
313 break;
314 }
315 case 'Z': {
316 quat_to_eul(rot, viewquat);
317 break;
318 }
319 }
320}
321
322void rotation_from_view(bContext *C, float rot[3], const char align_axis)
323{
325 BLI_assert(align_axis >= 'X' && align_axis <= 'Z');
326 if (rv3d) {
327 float viewquat[4];
328 copy_qt_qt(viewquat, rv3d->viewquat);
329 viewquat[0] *= -1.0f;
330 rotation_from_quat(rot, viewquat, align_axis);
331 }
332 else {
333 zero_v3(rot);
334 }
335}
336
337void init_transform_on_add(Object *object, const float loc[3], const float rot[3])
338{
339 if (loc) {
340 copy_v3_v3(object->loc, loc);
341 }
342
343 if (rot) {
344 copy_v3_v3(object->rot, rot);
345 }
346
347 BKE_object_to_mat4(object, object->runtime->object_to_world.ptr());
348}
349
351 Object *obedit,
352 const float loc[3],
353 const float rot[3],
354 const float scale[3],
355 float r_primmat[4][4])
356{
357 Scene *scene = CTX_data_scene(C);
358 View3D *v3d = CTX_wm_view3d(C);
359 float mat[3][3], rmat[3][3], cmat[3][3], imat[3][3];
360
361 unit_m4(r_primmat);
362
363 eul_to_mat3(rmat, rot);
364 invert_m3(rmat);
365
366 /* inverse transform for initial rotation and object */
367 copy_m3_m4(mat, obedit->object_to_world().ptr());
368 mul_m3_m3m3(cmat, rmat, mat);
369 invert_m3_m3(imat, cmat);
370 copy_m4_m3(r_primmat, imat);
371
372 /* center */
373 copy_v3_v3(r_primmat[3], loc);
374 sub_v3_v3v3(r_primmat[3], r_primmat[3], obedit->object_to_world().location());
375 invert_m3_m3(imat, mat);
376 mul_m3_v3(imat, r_primmat[3]);
377
378 if (scale != nullptr) {
379 rescale_m4(r_primmat, scale);
380 }
381
382 {
383 const float dia = v3d ? ED_view3d_grid_scale(scene, v3d, nullptr) :
384 ED_scene_grid_scale(scene, nullptr);
385 return dia;
386 }
387
388 // return 1.0f;
389}
390
392
393/* -------------------------------------------------------------------- */
396
397static void view_align_update(Main * /*main*/, Scene * /*scene*/, PointerRNA *ptr)
398{
399 RNA_struct_idprops_unset(ptr, "rotation");
400}
401
403{
405 ot->srna, "size", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00);
406}
407
408void add_unit_props_radius_ex(wmOperatorType *ot, float default_value)
409{
411 ot->srna, "radius", default_value, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00);
412}
413
418
419void add_generic_props(wmOperatorType *ot, bool do_editmode)
420{
421 PropertyRNA *prop;
422
423 if (do_editmode) {
424 prop = RNA_def_boolean(ot->srna,
425 "enter_editmode",
426 false,
427 "Enter Edit Mode",
428 "Enter edit mode when adding this object");
430 }
431 /* NOTE: this property gets hidden for add-camera operator. */
432 prop = RNA_def_enum(
433 ot->srna, "align", align_options, ALIGN_WORLD, "Align", "The alignment of the new object");
435
436 prop = RNA_def_float_vector_xyz(ot->srna,
437 "location",
438 3,
439 nullptr,
442 "Location",
443 "Location for the newly added object",
444 -1000.0f,
445 1000.0f);
447 prop = RNA_def_float_rotation(ot->srna,
448 "rotation",
449 3,
450 nullptr,
453 "Rotation",
454 "Rotation for the newly added object",
455 DEG2RADF(-360.0f),
456 DEG2RADF(360.0f));
458
459 prop = RNA_def_float_vector_xyz(ot->srna,
460 "scale",
461 3,
462 nullptr,
465 "Scale",
466 "Scale for the newly added object",
467 -1000.0f,
468 1000.0f);
470}
471
473{
474 RNA_def_boolean(ot->srna, "calc_uvs", true, "Generate UVs", "Generate a default UV map");
475}
476
478 wmOperator *op,
479 const char view_align_axis,
480 float r_loc[3],
481 float r_rot[3],
482 float r_scale[3],
483 bool *r_enter_editmode,
484 ushort *r_local_view_bits,
485 bool *r_is_view_aligned)
486{
487 /* Edit Mode! (optional) */
488 {
489 bool _enter_editmode;
490 if (!r_enter_editmode) {
491 r_enter_editmode = &_enter_editmode;
492 }
493 /* Only to ensure the value is _always_ set.
494 * Typically the property will exist when the argument is non-null. */
495 *r_enter_editmode = false;
496
497 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "enter_editmode");
498 if (prop != nullptr) {
499 if (RNA_property_is_set(op->ptr, prop) && r_enter_editmode) {
500 *r_enter_editmode = RNA_property_boolean_get(op->ptr, prop);
501 }
502 else {
503 *r_enter_editmode = (U.flag & USER_ADD_EDITMODE) != 0;
504 RNA_property_boolean_set(op->ptr, prop, *r_enter_editmode);
505 }
506 }
507 }
508
509 if (r_local_view_bits) {
510 View3D *v3d = CTX_wm_view3d(C);
511 *r_local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uid : 0;
512 }
513
514 /* Location! */
515 {
516 float _loc[3];
517 if (!r_loc) {
518 r_loc = _loc;
519 }
520
521 if (RNA_struct_property_is_set(op->ptr, "location")) {
522 RNA_float_get_array(op->ptr, "location", r_loc);
523 }
524 else {
525 location_from_view(C, r_loc);
526 RNA_float_set_array(op->ptr, "location", r_loc);
527 }
528 }
529
530 /* Rotation! */
531 {
532 bool _is_view_aligned;
533 float _rot[3];
534 if (!r_is_view_aligned) {
535 r_is_view_aligned = &_is_view_aligned;
536 }
537 if (!r_rot) {
538 r_rot = _rot;
539 }
540
541 if (RNA_struct_property_is_set(op->ptr, "rotation")) {
542 /* If rotation is set, always use it. Alignment (and corresponding user preference)
543 * can be ignored since this is in world space anyways.
544 * To not confuse (e.g. on redo), don't set it to #ALIGN_WORLD in the op UI though. */
545 *r_is_view_aligned = false;
546 RNA_float_get_array(op->ptr, "rotation", r_rot);
547 }
548 else {
549 int alignment = ALIGN_WORLD;
550 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "align");
551
552 if (RNA_property_is_set(op->ptr, prop)) {
553 /* If alignment is set, always use it. */
554 *r_is_view_aligned = alignment == ALIGN_VIEW;
555 alignment = RNA_property_enum_get(op->ptr, prop);
556 }
557 else {
558 /* If alignment is not set, use User Preferences. */
559 *r_is_view_aligned = (U.flag & USER_ADD_VIEWALIGNED) != 0;
560 if (*r_is_view_aligned) {
562 alignment = ALIGN_VIEW;
563 }
564 else if ((U.flag & USER_ADD_CURSORALIGNED) != 0) {
566 alignment = ALIGN_CURSOR;
567 }
568 else {
570 alignment = ALIGN_WORLD;
571 }
572 }
573 switch (alignment) {
574 case ALIGN_WORLD:
575 RNA_float_get_array(op->ptr, "rotation", r_rot);
576 break;
577 case ALIGN_VIEW:
578 rotation_from_view(C, r_rot, view_align_axis);
579 RNA_float_set_array(op->ptr, "rotation", r_rot);
580 break;
581 case ALIGN_CURSOR: {
582 const Scene *scene = CTX_data_scene(C);
583 const float3x3 tmat = scene->cursor.matrix<float3x3>();
584 mat3_normalized_to_eul(r_rot, tmat.ptr());
585 RNA_float_set_array(op->ptr, "rotation", r_rot);
586 break;
587 }
588 }
589 }
590 }
591
592 /* Scale! */
593 {
594 float _scale[3];
595 if (!r_scale) {
596 r_scale = _scale;
597 }
598
599 /* For now this is optional, we can make it always use. */
600 copy_v3_fl(r_scale, 1.0f);
601
602 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "scale");
603 if (prop != nullptr) {
604 if (RNA_property_is_set(op->ptr, prop)) {
605 RNA_property_float_get_array(op->ptr, prop, r_scale);
606 }
607 else {
608 copy_v3_fl(r_scale, 1.0f);
609 RNA_property_float_set_array(op->ptr, prop, r_scale);
610 }
611 }
612 }
613}
614
616 const int type,
617 const char *name,
618 const float loc[3],
619 const float rot[3],
620 const bool enter_editmode,
621 const ushort local_view_bits,
622 ID *obdata)
623{
624 Main *bmain = CTX_data_main(C);
625 Scene *scene = CTX_data_scene(C);
626 ViewLayer *view_layer = CTX_data_view_layer(C);
627
628 {
629 BKE_view_layer_synced_ensure(scene, view_layer);
630 Object *obedit = BKE_view_layer_edit_object_get(view_layer);
631 if (obedit != nullptr) {
632 editmode_exit_ex(bmain, scene, obedit, EM_FREEDATA);
633 }
634 }
635
636 /* deselects all, sets active object */
637 Object *ob;
638 if (obdata != nullptr) {
639 BLI_assert(type == BKE_object_obdata_to_type(obdata));
640 ob = BKE_object_add_for_data(bmain, scene, view_layer, type, name, obdata, true);
641 const short *materials_len_p = BKE_id_material_len_p(obdata);
642 if (materials_len_p && *materials_len_p > 0) {
643 BKE_object_materials_sync_length(bmain, ob, static_cast<ID *>(ob->data));
644 }
645 }
646 else {
647 ob = BKE_object_add(bmain, scene, view_layer, type, name);
648 }
649
650 BKE_view_layer_synced_ensure(scene, view_layer);
651 Base *ob_base_act = BKE_view_layer_active_base_get(view_layer);
652 /* While not getting a valid base is not a good thing, it can happen in convoluted corner cases,
653 * better not crash on it in releases. */
654 BLI_assert(ob_base_act != nullptr);
655 if (ob_base_act != nullptr) {
656 ob_base_act->local_view_bits = local_view_bits;
657 /* editor level activate, notifiers */
658 base_activate(C, ob_base_act);
659 }
660
661 /* more editor stuff */
662 init_transform_on_add(ob, loc, rot);
663
664 /* TODO(sergey): This is weird to manually tag objects for update, better to
665 * use DEG_id_tag_update here perhaps.
666 */
667 DEG_id_type_tag(bmain, ID_OB);
669 if (ob->data != nullptr) {
671 }
672
673 if (enter_editmode) {
674 editmode_enter_ex(bmain, scene, ob, 0);
675 }
676
678
680
682
683 return ob;
684}
685
687 const int type,
688 const char *name,
689 const float loc[3],
690 const float rot[3],
691 const bool enter_editmode,
692 const ushort local_view_bits)
693{
694 return add_type_with_obdata(C, type, name, loc, rot, enter_editmode, local_view_bits, nullptr);
695}
696
697/* for object add operator */
699{
700 ushort local_view_bits;
701 bool enter_editmode;
702 float loc[3], rot[3], radius;
704 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, &enter_editmode, &local_view_bits, nullptr);
705
706 radius = RNA_float_get(op->ptr, "radius");
707 Object *ob = add_type(
708 C, RNA_enum_get(op->ptr, "type"), nullptr, loc, rot, enter_editmode, local_view_bits);
709
710 if (ob->type == OB_LATTICE) {
711 /* lattice is a special case!
712 * we never want to scale the obdata since that is the rest-state */
713 copy_v3_fl(ob->scale, radius);
714 }
715 else {
716 BKE_object_obdata_size_init(ob, radius);
717 }
718
719 return OPERATOR_FINISHED;
720}
721
723{
724 /* identifiers */
725 ot->name = "Add Object";
726 ot->description = "Add an object to the scene";
727 ot->idname = "OBJECT_OT_add";
728
729 /* API callbacks. */
730 ot->exec = object_add_exec;
732
733 /* flags */
735
736 /* properties */
738 PropertyRNA *prop = RNA_def_enum(ot->srna, "type", rna_enum_object_type_items, 0, "Type", "");
740
741 add_generic_props(ot, true);
742}
743
745
746/* -------------------------------------------------------------------- */
749
750/* for object add operator */
751static const char *get_lightprobe_defname(int type)
752{
753 switch (type) {
755 return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Volume");
757 return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Plane");
759 return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Sphere");
760 default:
761 return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "LightProbe");
762 }
763}
764
766{
767 bool enter_editmode;
768 ushort local_view_bits;
769 float loc[3], rot[3];
771 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, &enter_editmode, &local_view_bits, nullptr);
772
773 int type = RNA_enum_get(op->ptr, "type");
774 float radius = RNA_float_get(op->ptr, "radius");
775
776 Object *ob = add_type(
777 C, OB_LIGHTPROBE, get_lightprobe_defname(type), loc, rot, false, local_view_bits);
778 copy_v3_fl(ob->scale, radius);
779
780 LightProbe *probe = (LightProbe *)ob->data;
781
782 BKE_lightprobe_type_set(probe, type);
783
784 return OPERATOR_FINISHED;
785}
786
788{
789 /* identifiers */
790 ot->name = "Add Light Probe";
791 ot->description = "Add a light probe object";
792 ot->idname = "OBJECT_OT_lightprobe_add";
793
794 /* API callbacks. */
795 ot->exec = lightprobe_add_exec;
797
798 /* flags */
800
801 /* properties */
802 ot->prop = RNA_def_enum(ot->srna, "type", lightprobe_type_items, 0, "Type", "");
803
805 add_generic_props(ot, true);
806}
807
809
810/* -------------------------------------------------------------------- */
813
814/* for object add operator */
815
816static const char *get_effector_defname(ePFieldType type)
817{
818 switch (type) {
819 case PFIELD_FORCE:
820 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Force");
821 case PFIELD_VORTEX:
822 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Vortex");
823 case PFIELD_MAGNET:
824 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Magnet");
825 case PFIELD_WIND:
826 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Wind");
827 case PFIELD_GUIDE:
828 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "CurveGuide");
829 case PFIELD_TEXTURE:
830 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "TextureField");
831 case PFIELD_HARMONIC:
832 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Harmonic");
833 case PFIELD_CHARGE:
834 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Charge");
835 case PFIELD_LENNARDJ:
836 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Lennard-Jones");
837 case PFIELD_BOID:
838 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Boid");
840 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Turbulence");
841 case PFIELD_DRAG:
842 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Drag");
843 case PFIELD_FLUIDFLOW:
844 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "FluidField");
845 case PFIELD_NULL:
846 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Field");
847 case NUM_PFIELD_TYPES:
848 break;
849 }
850
851 BLI_assert(false);
852 return CTX_DATA_(BLT_I18NCONTEXT_ID_OBJECT, "Field");
853}
854
856{
857 bool enter_editmode;
858 ushort local_view_bits;
859 float loc[3], rot[3];
861 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, &enter_editmode, &local_view_bits, nullptr);
862
863 const ePFieldType type = static_cast<ePFieldType>(RNA_enum_get(op->ptr, "type"));
864 float dia = RNA_float_get(op->ptr, "radius");
865
866 Object *ob;
867 if (type == PFIELD_GUIDE) {
868 Main *bmain = CTX_data_main(C);
869 Scene *scene = CTX_data_scene(C);
870 ob = add_type(
871 C, OB_CURVES_LEGACY, get_effector_defname(type), loc, rot, false, local_view_bits);
872
873 Curve *cu = static_cast<Curve *>(ob->data);
874 cu->flag |= CU_PATH | CU_3D;
875 editmode_enter_ex(bmain, scene, ob, 0);
876
877 float mat[4][4];
878 new_primitive_matrix(C, ob, loc, rot, nullptr, mat);
879 mul_mat3_m4_fl(mat, dia);
882 if (!enter_editmode) {
883 editmode_exit_ex(bmain, scene, ob, EM_FREEDATA);
884 }
885 }
886 else {
887 ob = add_type(C, OB_EMPTY, get_effector_defname(type), loc, rot, false, local_view_bits);
889 if (ELEM(type, PFIELD_WIND, PFIELD_VORTEX)) {
891 }
892 }
893
894 ob->pd = BKE_partdeflect_new(type);
895
896 return OPERATOR_FINISHED;
897}
898
900{
901 /* identifiers */
902 ot->name = "Add Effector";
903 ot->description = "Add an empty object with a physics effector to the scene";
904 ot->idname = "OBJECT_OT_effector_add";
905
906 /* API callbacks. */
907 ot->exec = effector_add_exec;
909
910 /* flags */
912
913 /* properties */
914 ot->prop = RNA_def_enum(ot->srna, "type", field_type_items, 0, "Type", "");
915
917 add_generic_props(ot, true);
918}
919
921
922/* -------------------------------------------------------------------- */
925
927{
928 View3D *v3d = CTX_wm_view3d(C);
929 Scene *scene = CTX_data_scene(C);
930
931 /* force view align for cameras */
932 RNA_enum_set(op->ptr, "align", ALIGN_VIEW);
933
934 ushort local_view_bits;
935 bool enter_editmode;
936 float loc[3], rot[3];
937 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, &enter_editmode, &local_view_bits, nullptr);
938
939 Object *ob = add_type(C, OB_CAMERA, nullptr, loc, rot, false, local_view_bits);
940
941 if (v3d) {
942 if (v3d->camera == nullptr) {
943 v3d->camera = ob;
944 }
945 if (v3d->scenelock && scene->camera == nullptr) {
946 scene->camera = ob;
947 }
948 }
949
950 Camera *cam = static_cast<Camera *>(ob->data);
951 cam->drawsize = v3d ? ED_view3d_grid_scale(scene, v3d, nullptr) :
952 ED_scene_grid_scale(scene, nullptr);
953
954 return OPERATOR_FINISHED;
955}
956
958{
959 PropertyRNA *prop;
960
961 /* identifiers */
962 ot->name = "Add Camera";
963 ot->description = "Add a camera object to the scene";
964 ot->idname = "OBJECT_OT_camera_add";
965
966 /* API callbacks. */
969
970 /* flags */
972
973 add_generic_props(ot, true);
974
975 /* hide this for cameras, default */
976 prop = RNA_struct_type_find_property(ot->srna, "align");
978}
979
981
982/* -------------------------------------------------------------------- */
985
987{
988 Main *bmain = CTX_data_main(C);
989 Scene *scene = CTX_data_scene(C);
990 ViewLayer *view_layer = CTX_data_view_layer(C);
991
992 ushort local_view_bits;
993 bool enter_editmode;
994 float loc[3], rot[3];
996 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, &enter_editmode, &local_view_bits, nullptr);
997
998 bool newob = false;
999 BKE_view_layer_synced_ensure(scene, view_layer);
1000 Object *obedit = BKE_view_layer_edit_object_get(view_layer);
1001 if (obedit == nullptr || obedit->type != OB_MBALL) {
1002 obedit = add_type(C, OB_MBALL, nullptr, loc, rot, true, local_view_bits);
1003 newob = true;
1004 }
1005 else {
1007 }
1008
1009 float mat[4][4];
1010 new_primitive_matrix(C, obedit, loc, rot, nullptr, mat);
1011 /* Halving here is done to account for constant values from #BKE_mball_element_add.
1012 * While the default radius of the resulting meta element is 2,
1013 * we want to pass in 1 so other values such as resolution are scaled by 1.0. */
1014 float dia = RNA_float_get(op->ptr, "radius") / 2;
1015
1016 ED_mball_add_primitive(C, obedit, newob, mat, dia, RNA_enum_get(op->ptr, "type"));
1017
1018 /* userdef */
1019 if (newob && !enter_editmode) {
1020 editmode_exit_ex(bmain, scene, obedit, EM_FREEDATA);
1021 }
1022 else {
1023 /* Only needed in edit-mode (#add_type normally handles this). */
1025 }
1026
1027 return OPERATOR_FINISHED;
1028}
1029
1031{
1032 /* identifiers */
1033 ot->name = "Add Metaball";
1034 ot->description = "Add an metaball object to the scene";
1035 ot->idname = "OBJECT_OT_metaball_add";
1036
1037 /* API callbacks. */
1038 ot->invoke = WM_menu_invoke;
1041
1042 /* flags */
1043 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1044
1045 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_metaelem_type_items, 0, "Primitive", "");
1046
1048 add_generic_props(ot, true);
1049}
1050
1052
1053/* -------------------------------------------------------------------- */
1056
1058{
1059 Object *obedit = CTX_data_edit_object(C);
1060 bool enter_editmode;
1061 ushort local_view_bits;
1062 float loc[3], rot[3];
1063
1065 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, &enter_editmode, &local_view_bits, nullptr);
1066
1067 if (obedit && obedit->type == OB_FONT) {
1068 return OPERATOR_CANCELLED;
1069 }
1070
1071 obedit = add_type(C, OB_FONT, nullptr, loc, rot, enter_editmode, local_view_bits);
1072 BKE_object_obdata_size_init(obedit, RNA_float_get(op->ptr, "radius"));
1073
1074 return OPERATOR_FINISHED;
1075}
1076
1078{
1079 /* identifiers */
1080 ot->name = "Add Text";
1081 ot->description = "Add a text object to the scene";
1082 ot->idname = "OBJECT_OT_text_add";
1083
1084 /* API callbacks. */
1085 ot->exec = object_add_text_exec;
1086 ot->poll = ED_operator_objectmode;
1087
1088 /* flags */
1089 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1090
1091 /* properties */
1093 add_generic_props(ot, true);
1094}
1095
1097
1098/* -------------------------------------------------------------------- */
1101
1103{
1104 Main *bmain = CTX_data_main(C);
1105 Scene *scene = CTX_data_scene(C);
1106 ViewLayer *view_layer = CTX_data_view_layer(C);
1107 BKE_view_layer_synced_ensure(scene, view_layer);
1108 Object *obedit = BKE_view_layer_edit_object_get(view_layer);
1109
1111 bool newob = false;
1112 bool enter_editmode;
1113 ushort local_view_bits;
1114 float loc[3], rot[3], dia;
1115 bool view_aligned = rv3d && (U.flag & USER_ADD_VIEWALIGNED);
1116
1118 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, &enter_editmode, &local_view_bits, nullptr);
1119
1120 if ((obedit == nullptr) || (obedit->type != OB_ARMATURE)) {
1121 obedit = add_type(C, OB_ARMATURE, nullptr, loc, rot, true, local_view_bits);
1122 editmode_enter_ex(bmain, scene, obedit, 0);
1123 newob = true;
1124 }
1125 else {
1127 }
1128
1129 if (obedit == nullptr) {
1130 BKE_report(op->reports, RPT_ERROR, "Cannot create editmode armature");
1131 return OPERATOR_CANCELLED;
1132 }
1133
1134 /* Give the Armature its default bone collection. */
1135 bArmature *armature = static_cast<bArmature *>(obedit->data);
1136 BoneCollection *default_bonecoll = ANIM_armature_bonecoll_new(armature, "");
1137 ANIM_armature_bonecoll_active_set(armature, default_bonecoll);
1138
1139 dia = RNA_float_get(op->ptr, "radius");
1140 ED_armature_ebone_add_primitive(obedit, dia, view_aligned);
1141
1142 /* userdef */
1143 if (newob && !enter_editmode) {
1144 editmode_exit_ex(bmain, scene, obedit, EM_FREEDATA);
1145 }
1146
1147 return OPERATOR_FINISHED;
1148}
1149
1151{
1152 /* identifiers */
1153 ot->name = "Add Armature";
1154 ot->description = "Add an armature object to the scene";
1155 ot->idname = "OBJECT_OT_armature_add";
1156
1157 /* API callbacks. */
1159 ot->poll = ED_operator_objectmode;
1160
1161 /* flags */
1162 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1163
1164 /* properties */
1166 add_generic_props(ot, true);
1167}
1168
1170
1171/* -------------------------------------------------------------------- */
1174
1176{
1177 Object *ob;
1178 int type = RNA_enum_get(op->ptr, "type");
1179 ushort local_view_bits;
1180 float loc[3], rot[3];
1181
1183 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, nullptr, &local_view_bits, nullptr);
1184
1185 ob = add_type(C, OB_EMPTY, nullptr, loc, rot, false, local_view_bits);
1186
1188 BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
1189
1190 return OPERATOR_FINISHED;
1191}
1192
1194{
1195 /* identifiers */
1196 ot->name = "Add Empty";
1197 ot->description = "Add an empty object to the scene";
1198 ot->idname = "OBJECT_OT_empty_add";
1199
1200 /* API callbacks. */
1201 ot->invoke = WM_menu_invoke;
1202 ot->exec = object_empty_add_exec;
1203 ot->poll = ED_operator_objectmode;
1204
1205 /* flags */
1206 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1207
1208 /* properties */
1209 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_empty_drawtype_items, 0, "Type", "");
1210
1212 add_generic_props(ot, false);
1213}
1214
1216{
1217 Image *ima = nullptr;
1218
1219 ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
1220 if (!ima) {
1221 return OPERATOR_CANCELLED;
1222 }
1223
1224 if (!ED_operator_objectmode(C)) {
1225 BKE_report(op->reports, RPT_ERROR, "Image objects can only be added in Object Mode");
1226 return OPERATOR_CANCELLED;
1227 }
1228
1229 /* Add new empty. */
1230 ushort local_view_bits;
1231 float loc[3], rot[3];
1232
1233 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, nullptr, &local_view_bits, nullptr);
1234
1235 Object *ob = add_type(C, OB_EMPTY, nullptr, loc, rot, false, local_view_bits);
1236 ob->empty_drawsize = 5.0f;
1237
1238 if (RNA_boolean_get(op->ptr, "background")) {
1239 /* When "background" has been set to "true", set image to render in the background. */
1242
1244 if (rv3d->persp != RV3D_PERSP) {
1246 }
1247 }
1248
1250
1251 ob->data = ima;
1252
1253 return OPERATOR_FINISHED;
1254}
1255
1257{
1258 if (!RNA_struct_property_is_set(op->ptr, "align")) {
1259 /* Default to Aligned unless something else was explicitly passed. */
1260 RNA_enum_set(op->ptr, "align", ALIGN_VIEW);
1261 }
1262
1263 /* Check if the user has not specified the image to load.
1264 * If they have not, assume this is a drag an drop operation. */
1265 if (!RNA_struct_property_is_set(op->ptr, "filepath") &&
1267 {
1270 }
1271
1272 if (!RNA_struct_property_is_set(op->ptr, "background")) {
1273 /* Check if we should switch to "background" mode. */
1275 if (rv3d->persp != RV3D_PERSP) {
1276 RNA_boolean_set(op->ptr, "background", true);
1277 }
1278 }
1279
1280 float loc[3];
1281 location_from_view(C, loc);
1282 ED_view3d_cursor3d_position(C, event->mval, false, loc);
1283 RNA_float_set_array(op->ptr, "location", loc);
1284
1285 Object *ob_cursor = ED_view3d_give_object_under_cursor(C, event->mval);
1286
1287 /* Either change empty under cursor or create a new empty. */
1288 if (!ob_cursor || ob_cursor->type != OB_EMPTY) {
1289 return object_image_add_exec(C, op);
1290 }
1291 /* User dropped an image on an existing image. */
1292 Image *ima = nullptr;
1293
1294 ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
1295 if (!ima) {
1296 return OPERATOR_CANCELLED;
1297 }
1298 /* Handled below. */
1299 id_us_min(&ima->id);
1300
1301 Scene *scene = CTX_data_scene(C);
1304
1306
1307 id_us_min(static_cast<ID *>(ob_cursor->data));
1308 ob_cursor->data = ima;
1309 id_us_plus(static_cast<ID *>(ob_cursor->data));
1310 return OPERATOR_FINISHED;
1311}
1312
1314{
1315 return CTX_wm_region_view3d(C);
1316}
1317
1319{
1320 /* identifiers */
1321 ot->name = "Add Empty Image/Drop Image to Empty";
1322 ot->description = "Add an empty image type to scene with data";
1323 ot->idname = "OBJECT_OT_empty_image_add";
1324
1325 /* API callbacks. */
1326 ot->invoke = object_image_add_invoke;
1327 ot->exec = object_image_add_exec;
1328 ot->poll = object_image_add_poll;
1329
1330 /* flags */
1331 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1332
1333 /* properties */
1341
1343 add_generic_props(ot, false);
1344 PropertyRNA *prop;
1345 prop = RNA_def_boolean(ot->srna,
1346 "background",
1347 false,
1348 "Put in Background",
1349 "Make the image render behind all objects");
1351 /* Hide the filepath and relative path prop */
1352 prop = RNA_struct_type_find_property(ot->srna, "filepath");
1354 prop = RNA_struct_type_find_property(ot->srna, "relative_path");
1356}
1357
1359
1360/* -------------------------------------------------------------------- */
1363
1366 "2D",
1367 0,
1368 "2D Layers",
1369 "Display strokes using Grease Pencil layers to define order"},
1370 {GP_DRAWMODE_3D, "3D", 0, "3D Location", "Display strokes using real 3D position in 3D space"},
1371 {0, nullptr, 0, nullptr, nullptr},
1372};
1373
1375{
1376 Main *bmain = CTX_data_main(C);
1377 Scene *scene = CTX_data_scene(C);
1378 Object *original_active_object = CTX_data_active_object(C);
1379 /* TODO: For now, only support adding the 'Stroke' type. */
1380 const int type = RNA_enum_get(op->ptr, "type");
1381
1382 ushort local_view_bits;
1383 float loc[3], rot[3];
1384
1385 /* NOTE: We use 'Y' here (not 'Z'), as. */
1387 add_generic_get_opts(C, op, 'Y', loc, rot, nullptr, nullptr, &local_view_bits, nullptr);
1388
1389 const char *ob_name = nullptr;
1390 switch (type) {
1391 case GP_EMPTY: {
1392 ob_name = CTX_DATA_(BLT_I18NCONTEXT_ID_GPENCIL, "GPencil");
1393 break;
1394 }
1395 case GP_STROKE: {
1396 ob_name = CTX_DATA_(BLT_I18NCONTEXT_ID_GPENCIL, "Stroke");
1397 break;
1398 }
1399 case GP_MONKEY: {
1400 ob_name = CTX_DATA_(BLT_I18NCONTEXT_ID_GPENCIL, "Suzanne");
1401 break;
1402 }
1406 ob_name = CTX_DATA_(BLT_I18NCONTEXT_ID_GPENCIL, "LineArt");
1407 break;
1408 }
1409 default: {
1410 break;
1411 }
1412 }
1413
1414 Object *object = add_type(C, OB_GREASE_PENCIL, ob_name, loc, rot, false, local_view_bits);
1415 GreasePencil &grease_pencil_id = *static_cast<GreasePencil *>(object->data);
1416 const bool use_in_front = RNA_boolean_get(op->ptr, "use_in_front");
1417 const bool use_lights = RNA_boolean_get(op->ptr, "use_lights");
1418
1419 switch (type) {
1420 case GP_EMPTY: {
1421 greasepencil::create_blank(*bmain, *object, scene->r.cfra);
1422 break;
1423 }
1424 case GP_STROKE: {
1425 const float radius = RNA_float_get(op->ptr, "radius");
1426 const float3 scale(radius);
1427
1428 float4x4 mat;
1429 new_primitive_matrix(C, object, loc, rot, scale, mat.ptr());
1430
1431 greasepencil::create_stroke(*bmain, *object, mat, scene->r.cfra);
1432 break;
1433 }
1434 case GP_MONKEY: {
1435 const float radius = RNA_float_get(op->ptr, "radius");
1436 const float3 scale(radius);
1437
1438 float4x4 mat;
1439 new_primitive_matrix(C, object, loc, rot, scale, mat.ptr());
1440
1441 greasepencil::create_suzanne(*bmain, *object, mat, scene->r.cfra);
1442 break;
1443 }
1447 const int type = RNA_enum_get(op->ptr, "type");
1448 const int stroke_depth_order = RNA_enum_get(op->ptr, "stroke_depth_order");
1449 const float stroke_depth_offset = RNA_float_get(op->ptr, "stroke_depth_offset");
1450
1451 greasepencil::create_blank(*bmain, *object, scene->r.cfra);
1452
1453 auto *grease_pencil = reinterpret_cast<GreasePencil *>(object->data);
1455 auto *md = reinterpret_cast<GreasePencilLineartModifierData *>(new_md);
1456
1457 BLI_addtail(&object->modifiers, md);
1458 BKE_modifier_unique_name(&object->modifiers, new_md);
1459 BKE_modifiers_persistent_uid_init(*object, *new_md);
1460
1462 md->source_type = LINEART_SOURCE_COLLECTION;
1463 md->source_collection = CTX_data_collection(C);
1464 }
1465 else if (type == GREASE_PENCIL_LINEART_OBJECT) {
1466 md->source_type = LINEART_SOURCE_OBJECT;
1467 md->source_object = original_active_object;
1468 }
1469 else {
1470 /* Whole scene. */
1471 md->source_type = LINEART_SOURCE_SCENE;
1472 }
1473 /* Only created one layer and one material. */
1474 STRNCPY(md->target_layer, grease_pencil->get_active_layer()->name().c_str());
1475 md->target_material = BKE_object_material_get(object, 0);
1476 if (md->target_material) {
1477 id_us_plus(&md->target_material->id);
1478 }
1479
1480 if (!use_in_front) {
1481 if (stroke_depth_order == GP_DRAWMODE_3D) {
1482 grease_pencil->flag |= GREASE_PENCIL_STROKE_ORDER_3D;
1483 }
1484 md->stroke_depth_offset = stroke_depth_offset;
1485 }
1486
1487 break;
1488 }
1489 }
1490
1491 SET_FLAG_FROM_TEST(object->dtx, use_in_front, OB_DRAW_IN_FRONT);
1493
1494 for (blender::bke::greasepencil::Layer *layer : grease_pencil_id.layers_for_write()) {
1495 SET_FLAG_FROM_TEST(layer->as_node().flag, use_lights, GP_LAYER_TREE_NODE_USE_LIGHTS);
1496 }
1497
1498 DEG_id_tag_update(&grease_pencil_id.id, ID_RECALC_GEOMETRY);
1499 WM_main_add_notifier(NC_GEOM | ND_DATA, &grease_pencil_id.id);
1500
1501 return OPERATOR_FINISHED;
1502}
1503
1505 wmOperator *op,
1506 const wmEvent * /*event*/)
1507{
1508 const int type = RNA_enum_get(op->ptr, "type");
1509
1510 /* Only disable "use_in_front" if it's one of the non-LineArt types */
1511 if (ELEM(type, GP_EMPTY, GP_STROKE, GP_MONKEY)) {
1512 RNA_boolean_set(op->ptr, "use_in_front", false);
1513 }
1514
1515 return object_grease_pencil_add_exec(C, op);
1516}
1517
1519{
1520 /* identifiers */
1521 ot->name = "Add Grease Pencil";
1522 ot->description = "Add a Grease Pencil object to the scene";
1523 ot->idname = "OBJECT_OT_grease_pencil_add";
1524
1525 /* API callbacks. */
1528 ot->poll = ED_operator_objectmode;
1529
1530 /* flags */
1531 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1532
1533 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", "");
1535 RNA_def_boolean(ot->srna,
1536 "use_in_front",
1537 true,
1538 "Show In Front",
1539 "Show Line Art Grease Pencil in front of everything");
1540 RNA_def_float(ot->srna,
1541 "stroke_depth_offset",
1542 0.05f,
1543 0.0f,
1544 FLT_MAX,
1545 "Stroke Offset",
1546 "Stroke offset for the Line Art modifier",
1547 0.0f,
1548 0.5f);
1550 ot->srna, "use_lights", true, "Use Lights", "Use lights for this Grease Pencil object");
1552 ot->srna,
1553 "stroke_depth_order",
1556 "Stroke Depth Order",
1557 "Defines how the strokes are ordered in 3D space (for objects not displayed 'In Front')");
1558
1560 add_generic_props(ot, false);
1561}
1562
1564
1565/* -------------------------------------------------------------------- */
1568
1569static const char *get_light_defname(int type)
1570{
1571 switch (type) {
1572 case LA_LOCAL:
1573 return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Point");
1574 case LA_SUN:
1575 return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Sun");
1576 case LA_SPOT:
1577 return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Spot");
1578 case LA_AREA:
1579 return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Area");
1580 default:
1581 return CTX_DATA_(BLT_I18NCONTEXT_ID_LIGHT, "Light");
1582 }
1583}
1584
1586{
1587 Object *ob;
1588 Light *la;
1589 int type = RNA_enum_get(op->ptr, "type");
1590 ushort local_view_bits;
1591 float loc[3], rot[3];
1592
1594 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, nullptr, &local_view_bits, nullptr);
1595
1596 ob = add_type(C, OB_LAMP, get_light_defname(type), loc, rot, false, local_view_bits);
1597
1598 float size = RNA_float_get(op->ptr, "radius");
1599 /* Better defaults for light size. */
1600 switch (type) {
1601 case LA_LOCAL:
1602 case LA_SPOT:
1603 break;
1604 case LA_AREA:
1605 size *= 4.0f;
1606 break;
1607 default:
1608 size *= 0.5f;
1609 break;
1610 }
1612
1613 la = (Light *)ob->data;
1614 la->type = type;
1615
1616 if (type == LA_SUN) {
1617 la->energy = 1.0f;
1618 }
1619
1620 return OPERATOR_FINISHED;
1621}
1622
1624{
1625 /* identifiers */
1626 ot->name = "Add Light";
1627 ot->description = "Add a light object to the scene";
1628 ot->idname = "OBJECT_OT_light_add";
1629
1630 /* API callbacks. */
1631 ot->invoke = WM_menu_invoke;
1632 ot->exec = object_light_add_exec;
1633 ot->poll = ED_operator_objectmode;
1634
1635 /* flags */
1636 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1637
1638 /* properties */
1639 ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_light_type_items, 0, "Type", "");
1641
1643 add_generic_props(ot, false);
1644}
1645
1647
1648/* -------------------------------------------------------------------- */
1651
1653 /* The collection that is supposed to be added, determined through operator properties. */
1655 /* The local-view bits (if any) the object should have set to become visible in current context.
1656 */
1658 /* The transform that should be applied to the collection, determined through operator properties
1659 * if set (e.g. to place the collection under the cursor), otherwise through context (e.g. 3D
1660 * cursor location). */
1661 float loc[3], rot[3], scale[3];
1662};
1663
1664static std::optional<CollectionAddInfo> collection_add_info_get_from_op(bContext *C,
1665 wmOperator *op)
1666{
1667 CollectionAddInfo add_info{};
1668
1669 Main *bmain = CTX_data_main(C);
1670
1671 PropertyRNA *prop_location = RNA_struct_find_property(op->ptr, "location");
1672
1673 add_info.collection = reinterpret_cast<Collection *>(
1675
1676 bool update_location_if_necessary = false;
1677 if (add_info.collection) {
1678 update_location_if_necessary = true;
1679 }
1680 else {
1681 add_info.collection = static_cast<Collection *>(
1682 BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection")));
1683 }
1684
1685 if (update_location_if_necessary && CTX_wm_region_view3d(C)) {
1686 int mval[2];
1687 if (!RNA_property_is_set(op->ptr, prop_location) && object_add_drop_xy_get(C, op, &mval)) {
1688 location_from_view(C, add_info.loc);
1689 ED_view3d_cursor3d_position(C, mval, false, add_info.loc);
1690 RNA_property_float_set_array(op->ptr, prop_location, add_info.loc);
1691 }
1692 }
1693
1694 if (add_info.collection == nullptr) {
1695 return std::nullopt;
1696 }
1697
1699 op,
1700 'Z',
1701 add_info.loc,
1702 add_info.rot,
1703 add_info.scale,
1704 nullptr,
1705 &add_info.local_view_bits,
1706 nullptr);
1707
1708 ViewLayer *view_layer = CTX_data_view_layer(C);
1709
1710 /* Avoid dependency cycles. */
1711 LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer);
1712 while (BKE_collection_cycle_find(active_lc->collection, add_info.collection)) {
1713 active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
1714 }
1715
1716 return add_info;
1717}
1718
1720{
1721 std::optional<CollectionAddInfo> add_info = collection_add_info_get_from_op(C, op);
1722 if (!add_info) {
1723 return OPERATOR_CANCELLED;
1724 }
1725
1726 Object *ob = add_type(C,
1727 OB_EMPTY,
1728 add_info->collection->id.name + 2,
1729 add_info->loc,
1730 add_info->rot,
1731 false,
1732 add_info->local_view_bits);
1733 /* `add_type()` does not have scale argument so copy that value separately. */
1734 copy_v3_v3(ob->scale, add_info->scale);
1735 ob->instance_collection = add_info->collection;
1736 ob->empty_drawsize = U.collection_instance_empty_size;
1738 id_us_plus(&add_info->collection->id);
1739
1740 return OPERATOR_FINISHED;
1741}
1742
1744 wmOperator *op,
1745 const wmEvent *event)
1746{
1747 if (!object_add_drop_xy_is_set(op)) {
1748 RNA_int_set(op->ptr, "drop_x", event->xy[0]);
1749 RNA_int_set(op->ptr, "drop_y", event->xy[1]);
1750 }
1751
1753 return WM_enum_search_invoke(C, op, event);
1754 }
1755 return op->type->exec(C, op);
1756}
1757
1759{
1760 PropertyRNA *prop;
1761
1762 /* identifiers */
1763 ot->name = "Add Collection Instance";
1764 ot->description = "Add a collection instance";
1765 ot->idname = "OBJECT_OT_collection_instance_add";
1766
1767 /* API callbacks. */
1770 ot->poll = ED_operator_objectmode;
1771
1772 /* flags */
1773 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1774
1775 /* properties */
1777 ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Collection name to add");
1778 prop = RNA_def_enum(ot->srna, "collection", rna_enum_dummy_NULL_items, 0, "Collection", "");
1781 ot->prop = prop;
1782 add_generic_props(ot, false);
1783
1785
1787}
1788
1790
1791/* -------------------------------------------------------------------- */
1809
1811{
1812 Main *bmain = CTX_data_main(C);
1813 LayerCollection *active_collection = CTX_data_layer_collection(C);
1814 std::optional<CollectionAddInfo> add_info = collection_add_info_get_from_op(C, op);
1815 if (!add_info) {
1816 return OPERATOR_CANCELLED;
1817 }
1818
1819 if (RNA_boolean_get(op->ptr, "use_instance")) {
1820 BKE_collection_child_remove(bmain, active_collection->collection, add_info->collection);
1823
1824 Object *ob = add_type(C,
1825 OB_EMPTY,
1826 add_info->collection->id.name + 2,
1827 add_info->loc,
1828 add_info->rot,
1829 false,
1830 add_info->local_view_bits);
1831 ob->instance_collection = add_info->collection;
1832 ob->empty_drawsize = U.collection_instance_empty_size;
1834 id_us_plus(&add_info->collection->id);
1835 }
1836 else if (ID_IS_EDITABLE(&add_info->collection->id)) {
1837 ViewLayer *view_layer = CTX_data_view_layer(C);
1838 float delta_mat[4][4];
1839 unit_m4(delta_mat);
1840
1841 const float scale[3] = {1.0f, 1.0f, 1.0f};
1842 loc_eul_size_to_mat4(delta_mat, add_info->loc, add_info->rot, scale);
1843
1844 float offset[3];
1845 /* Reverse apply the instance offset, so toggling the Instance option doesn't cause the
1846 * collection to jump. */
1847 negate_v3_v3(offset, add_info->collection->instance_offset);
1848 translate_m4(delta_mat, UNPACK3(offset));
1849
1852 view_layer, nullptr, &params);
1853 object_xform_array_m4(objects.data(), objects.size(), delta_mat);
1854 }
1855
1856 return OPERATOR_FINISHED;
1857}
1858
1860{
1861 PropertyRNA *prop;
1862
1863 /* identifiers */
1864 /* Name should only be displayed in the drag tooltip. */
1865 ot->name = "Add Collection";
1866 ot->description = "Add the dragged collection to the scene";
1867 ot->idname = "OBJECT_OT_collection_external_asset_drop";
1868
1869 /* API callbacks. */
1871 ot->exec = collection_drop_exec;
1872 ot->poll = ED_operator_objectmode;
1873
1874 /* flags */
1876
1877 /* properties */
1879
1880 add_generic_props(ot, false);
1881
1882 prop = RNA_def_boolean(ot->srna,
1883 "use_instance",
1884 true,
1885 "Instance",
1886 "Add the dropped collection as collection instance");
1888
1890
1891 prop = RNA_def_enum(ot->srna, "collection", rna_enum_dummy_NULL_items, 0, "Collection", "");
1894 ot->prop = prop;
1895}
1896
1898
1899/* -------------------------------------------------------------------- */
1904
1906{
1907 Main *bmain = CTX_data_main(C);
1908 ID *id = nullptr;
1909 ushort local_view_bits;
1910 float loc[3], rot[3];
1911
1912 PropertyRNA *prop_type = RNA_struct_find_property(op->ptr, "type");
1913 PropertyRNA *prop_location = RNA_struct_find_property(op->ptr, "location");
1914
1915 const short id_type = RNA_property_enum_get(op->ptr, prop_type);
1917 if (id == nullptr) {
1918 return OPERATOR_CANCELLED;
1919 }
1920 const int object_type = BKE_object_obdata_to_type(id);
1921 if (object_type == -1) {
1922 return OPERATOR_CANCELLED;
1923 }
1924
1925 if (CTX_wm_region_view3d(C)) {
1926 int mval[2];
1927 if (!RNA_property_is_set(op->ptr, prop_location) && object_add_drop_xy_get(C, op, &mval)) {
1928 location_from_view(C, loc);
1929 ED_view3d_cursor3d_position(C, mval, false, loc);
1930 RNA_property_float_set_array(op->ptr, prop_location, loc);
1931 }
1932 }
1933
1934 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, nullptr, &local_view_bits, nullptr);
1935
1936 add_type_with_obdata(C, object_type, id->name + 2, loc, rot, false, local_view_bits, id);
1937
1938 return OPERATOR_FINISHED;
1939}
1940
1942{
1943 /* identifiers */
1944 ot->name = "Add Object Data Instance";
1945 ot->description = "Add an object data instance";
1946 ot->idname = "OBJECT_OT_data_instance_add";
1947
1948 /* API callbacks. */
1951 ot->poll = ED_operator_objectmode;
1952
1953 /* flags */
1954 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1955
1956 /* properties */
1958 PropertyRNA *prop = RNA_def_enum(ot->srna, "type", rna_enum_id_type_items, 0, "Type", "");
1960 add_generic_props(ot, false);
1961
1963}
1964
1966
1967/* -------------------------------------------------------------------- */
1970
1972{
1973 Main *bmain = CTX_data_main(C);
1974 Scene *scene = CTX_data_scene(C);
1975
1976 ushort local_view_bits;
1977 float loc[3], rot[3];
1978 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, nullptr, &local_view_bits, nullptr);
1979
1980 Object *ob = add_type(C, OB_SPEAKER, nullptr, loc, rot, false, local_view_bits);
1981 const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ob);
1982
1983 /* To make it easier to start using this immediately in NLA, a default sound clip is created
1984 * ready to be moved around to re-time the sound and/or make new sound clips. */
1985 {
1986 /* create new data for NLA hierarchy */
1987 AnimData *adt = BKE_animdata_ensure_id(&ob->id);
1988 NlaTrack *nlt = BKE_nlatrack_new_tail(&adt->nla_tracks, is_liboverride);
1990 NlaStrip *strip = BKE_nla_add_soundstrip(bmain, scene, static_cast<Speaker *>(ob->data));
1991 strip->start = scene->r.cfra;
1992 strip->end += strip->start;
1993
1994 /* hook them up */
1995 BKE_nlatrack_add_strip(nlt, strip, is_liboverride);
1996
1997 /* Auto-name the strip, and give the track an interesting name. */
1998 STRNCPY_UTF8(nlt->name, DATA_("SoundTrack"));
1999 BKE_nlastrip_validate_name(adt, strip);
2000
2002 }
2003
2004 return OPERATOR_FINISHED;
2005}
2006
2008{
2009 /* identifiers */
2010 ot->name = "Add Speaker";
2011 ot->description = "Add a speaker object to the scene";
2012 ot->idname = "OBJECT_OT_speaker_add";
2013
2014 /* API callbacks. */
2016 ot->poll = ED_operator_objectmode;
2017
2018 /* flags */
2019 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2020
2021 add_generic_props(ot, true);
2022}
2023
2025
2026/* -------------------------------------------------------------------- */
2029
2031{
2032 ushort local_view_bits;
2033 float loc[3], rot[3];
2034 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, nullptr, &local_view_bits, nullptr);
2035
2036 Object *object = add_type(C, OB_CURVES, nullptr, loc, rot, false, local_view_bits);
2037
2038 Curves *curves_id = static_cast<Curves *>(object->data);
2039 curves_id->geometry.wrap() = ed::curves::primitive_random_sphere(500, 8);
2040
2041 return OPERATOR_FINISHED;
2042}
2043
2045{
2046 /* identifiers */
2047 ot->name = "Add Random Curves";
2048 ot->description = "Add a curves object with random curves to the scene";
2049 ot->idname = "OBJECT_OT_curves_random_add";
2050
2051 /* API callbacks. */
2053 ot->poll = ED_operator_objectmode;
2054
2055 /* flags */
2056 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2057
2058 add_generic_props(ot, false);
2059}
2060
2062{
2063 Scene *scene = CTX_data_scene(C);
2064
2065 ushort local_view_bits;
2066 add_generic_get_opts(C, op, 'Z', nullptr, nullptr, nullptr, nullptr, &local_view_bits, nullptr);
2067
2068 Object *surface_ob = CTX_data_active_object(C);
2069 BLI_assert(surface_ob != nullptr);
2070
2071 Object *curves_ob = add_type(C, OB_CURVES, nullptr, nullptr, nullptr, false, local_view_bits);
2072 BKE_object_apply_mat4(curves_ob, surface_ob->object_to_world().ptr(), false, false);
2073
2074 /* Set surface object. */
2075 Curves *curves_id = static_cast<Curves *>(curves_ob->data);
2076 curves_id->surface = surface_ob;
2077
2078 /* Parent to surface object. */
2079 parent_set(op->reports, C, scene, curves_ob, surface_ob, PAR_OBJECT, false, true, nullptr);
2080
2081 /* Decide which UV map to use for attachment. */
2082 Mesh *surface_mesh = static_cast<Mesh *>(surface_ob->data);
2083 const char *uv_name = CustomData_get_active_layer_name(&surface_mesh->corner_data,
2085 if (uv_name != nullptr) {
2086 curves_id->surface_uv_map = BLI_strdup(uv_name);
2087 }
2088
2089 /* Add deformation modifier. */
2091
2092 /* Make sure the surface object has a rest position attribute which is necessary for
2093 * deformations. */
2095
2096 return OPERATOR_FINISHED;
2097}
2098
2100{
2101 if (!ED_operator_objectmode(C)) {
2102 return false;
2103 }
2105 if (ob == nullptr || ob->type != OB_MESH) {
2106 CTX_wm_operator_poll_msg_set(C, "No active mesh object");
2107 return false;
2108 }
2109 return true;
2110}
2111
2113{
2114 ot->name = "Add Empty Curves";
2115 ot->description = "Add an empty curve object to the scene with the selected mesh as surface";
2116 ot->idname = "OBJECT_OT_curves_empty_hair_add";
2117
2120
2121 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2122
2123 add_generic_props(ot, false);
2124}
2125
2127
2128/* -------------------------------------------------------------------- */
2131
2133{
2134 ushort local_view_bits;
2135 float loc[3], rot[3];
2136 add_generic_get_opts(C, op, 'Z', loc, rot, nullptr, nullptr, &local_view_bits, nullptr);
2137
2138 Object *object = add_type(C, OB_POINTCLOUD, nullptr, loc, rot, false, local_view_bits);
2139 PointCloud &pointcloud = *static_cast<PointCloud *>(object->data);
2140 pointcloud.totpoint = 400;
2141 CustomData_realloc(&pointcloud.pdata, 0, pointcloud.totpoint);
2142
2143 bke::MutableAttributeAccessor attributes = pointcloud.attributes_for_write();
2145 "position", bke::AttrDomain::Point);
2147 "radius", bke::AttrDomain::Point);
2148
2149 RandomNumberGenerator rng(0);
2150 for (const int i : position.span.index_range()) {
2151 position.span[i] = float3(rng.get_float(), rng.get_float(), rng.get_float()) * 2.0f - 1.0f;
2152 radii.span[i] = 0.05f * rng.get_float();
2153 }
2154
2155 position.finish();
2156 radii.finish();
2157
2158 return OPERATOR_FINISHED;
2159}
2160
2162{
2163 ot->name = "Add Point Cloud";
2164 ot->description = "Add a point cloud object to the scene";
2165 ot->idname = "OBJECT_OT_pointcloud_random_add";
2166
2168 ot->poll = ED_operator_objectmode;
2169
2170 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2171
2172 add_generic_props(ot, false);
2173}
2174
2176
2177/* -------------------------------------------------------------------- */
2180
2181void base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
2182{
2183 if (ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0 &&
2185 {
2186 /* We cannot delete indirectly used object... */
2187 printf(
2188 "WARNING, undeletable object '%s', should have been caught before reaching this "
2189 "function!",
2190 ob->id.name + 2);
2191 return;
2192 }
2194 /* Do not delete objects used by overrides of collections. */
2195 return;
2196 }
2197
2199
2200 BKE_scene_collections_object_remove(bmain, scene, ob, true);
2201}
2202
2209
2211{
2212 Main *bmain = CTX_data_main(C);
2213 Scene *scene = CTX_data_scene(C);
2215 const bool use_global = RNA_boolean_get(op->ptr, "use_global");
2216 const bool confirm = op->flag & OP_IS_INVOKE;
2217 uint changed_count = 0;
2218 uint tagged_count = 0;
2219
2220 if (CTX_data_edit_object(C)) {
2221 return OPERATOR_CANCELLED;
2222 }
2223
2224 BKE_main_id_tag_all(bmain, ID_TAG_DOIT, false);
2225
2226 CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
2227 if (ob->id.tag & ID_TAG_INDIRECT) {
2228 /* Can this case ever happen? */
2229 BKE_reportf(op->reports,
2231 "Cannot delete indirectly linked object '%s'",
2232 ob->id.name + 2);
2233 continue;
2234 }
2235
2236 if (!BKE_lib_override_library_id_is_user_deletable(bmain, &ob->id)) {
2237 BKE_reportf(op->reports,
2239 "Cannot delete object '%s' as it is used by override collections",
2240 ob->id.name + 2);
2241 continue;
2242 }
2243
2244 if (ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0 &&
2246 {
2247 BKE_reportf(op->reports,
2249 "Cannot delete object '%s' from scene '%s', indirectly used objects need at "
2250 "least one user",
2251 ob->id.name + 2,
2252 scene->id.name + 2);
2253 continue;
2254 }
2255
2256 /* Use multi tagged delete if `use_global=True`, or the object is used only in one scene. */
2257 if (use_global || ID_REAL_USERS(ob) <= 1) {
2258 ob->id.tag |= ID_TAG_DOIT;
2259 tagged_count += 1;
2260 }
2261 else {
2262 /* Object is used in multiple scenes. Delete the object from the current scene only. */
2264 changed_count += 1;
2265 }
2266 }
2268
2269 if ((changed_count + tagged_count) == 0) {
2270 return OPERATOR_CANCELLED;
2271 }
2272
2273 if (tagged_count > 0) {
2275 }
2276
2277 if (confirm) {
2278 BKE_reportf(op->reports, RPT_INFO, "Deleted %u object(s)", (changed_count + tagged_count));
2279 }
2280
2281 /* delete has to handle all open scenes */
2283 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2284 scene = WM_window_get_active_scene(win);
2285
2286 if (scene->id.tag & ID_TAG_DOIT) {
2287 scene->id.tag &= ~ID_TAG_DOIT;
2288
2290
2294 }
2295 }
2296
2297 return OPERATOR_FINISHED;
2298}
2299
2301 wmOperator *op,
2302 const wmEvent * /*event*/)
2303{
2304 if (RNA_boolean_get(op->ptr, "confirm")) {
2306 op,
2307 IFACE_("Delete selected objects?"),
2308 nullptr,
2309 IFACE_("Delete"),
2311 false);
2312 }
2313 return object_delete_exec(C, op);
2314}
2315
2317{
2318 /* identifiers */
2319 ot->name = "Delete";
2320 ot->description = "Delete selected objects";
2321 ot->idname = "OBJECT_OT_delete";
2322
2323 /* API callbacks. */
2324 ot->invoke = object_delete_invoke;
2325 ot->exec = object_delete_exec;
2326 ot->poll = ED_operator_objectmode;
2327
2328 /* flags */
2329 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2330
2331 PropertyRNA *prop;
2332 prop = RNA_def_boolean(
2333 ot->srna, "use_global", false, "Delete Globally", "Remove object from all scenes");
2336}
2337
2339
2340/* -------------------------------------------------------------------- */
2343
2344/* after copying objects, copied data should get new pointers */
2346{
2347 Main *bmain = CTX_data_main(C);
2348
2349 CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
2350 BKE_libblock_relink_to_newid(bmain, &ob->id, 0);
2351 }
2353
2354#ifndef NDEBUG
2355 /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */
2356 ID *id_iter;
2357 FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
2358 if (GS(id_iter->name) == ID_OB) {
2359 /* Not all duplicated objects would be used by other newly duplicated data, so their flag
2360 * will not always be cleared. */
2361 continue;
2362 }
2363 BLI_assert((id_iter->tag & ID_TAG_NEW) == 0);
2364 }
2366#endif
2367
2369}
2370
2372
2373/* -------------------------------------------------------------------- */
2376
2377/* XXX TODO: That whole hierarchy handling based on persistent_id tricks is
2378 * very confusing and convoluted, and it will fail in many cases besides basic ones.
2379 * Think this should be replaced by a proper tree-like representation of the instantiations,
2380 * should help a lot in both readability, and precise consistent rebuilding of hierarchy.
2381 */
2382
2396static uint dupliobject_hash(const void *ptr)
2397{
2398 const DupliObject *dob = static_cast<const DupliObject *>(ptr);
2400
2401 if (dob->type == OB_DUPLICOLLECTION) {
2402 for (int i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) {
2403 hash ^= (dob->persistent_id[i] ^ i);
2404 }
2405 }
2406 else {
2407 hash ^= (dob->persistent_id[0] ^ 0);
2408 }
2409 return hash;
2410}
2411
2419{
2420 const DupliObject *dob = static_cast<const DupliObject *>(ptr);
2422 for (int i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) {
2423 hash ^= (dob->persistent_id[i] ^ i);
2424 }
2425 return hash;
2426}
2427
2431static bool dupliobject_cmp(const void *a_, const void *b_)
2432{
2433 const DupliObject *a = static_cast<const DupliObject *>(a_);
2434 const DupliObject *b = static_cast<const DupliObject *>(b_);
2435
2436 if (a->ob != b->ob) {
2437 return true;
2438 }
2439
2440 if (a->type != b->type) {
2441 return true;
2442 }
2443
2444 if (a->type == OB_DUPLICOLLECTION) {
2445 for (int i = 1; (i < MAX_DUPLI_RECUR); i++) {
2446 if (a->persistent_id[i] != b->persistent_id[i]) {
2447 return true;
2448 }
2449 if (a->persistent_id[i] == INT_MAX) {
2450 break;
2451 }
2452 }
2453 }
2454 else {
2455 if (a->persistent_id[0] != b->persistent_id[0]) {
2456 return true;
2457 }
2458 }
2459
2460 /* matching */
2461 return false;
2462}
2463
2464/* Compare function that matches dupliobject_instancer_hash. */
2465static bool dupliobject_instancer_cmp(const void *a_, const void *b_)
2466{
2467 const DupliObject *a = static_cast<const DupliObject *>(a_);
2468 const DupliObject *b = static_cast<const DupliObject *>(b_);
2469
2470 for (int i = 0; (i < MAX_DUPLI_RECUR); i++) {
2471 if (a->persistent_id[i] != b->persistent_id[i]) {
2472 return true;
2473 }
2474 if (a->persistent_id[i] == INT_MAX) {
2475 break;
2476 }
2477 }
2478
2479 /* matching */
2480 return false;
2481}
2482
2484 Depsgraph *depsgraph,
2485 Scene *scene,
2486 Base *base,
2487 const bool use_base_parent,
2488 const bool use_hierarchy)
2489{
2490 Main *bmain = CTX_data_main(C);
2491 ViewLayer *view_layer = CTX_data_view_layer(C);
2492 GHash *parent_gh = nullptr, *instancer_gh = nullptr;
2493
2494 Object *object_eval = DEG_get_evaluated(depsgraph, base->object);
2495
2496 if (!(base->object->transflag & OB_DUPLI) &&
2498 {
2499 return;
2500 }
2501
2502 ListBase *lb_duplis = object_duplilist(depsgraph, scene, object_eval);
2503
2504 if (BLI_listbase_is_empty(lb_duplis)) {
2505 free_object_duplilist(lb_duplis);
2506 return;
2507 }
2508
2510 if (use_hierarchy) {
2511 parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__);
2512
2513 if (use_base_parent) {
2514 instancer_gh = BLI_ghash_new(
2516 }
2517 }
2518
2519 LISTBASE_FOREACH (DupliObject *, dob, lb_duplis) {
2520 Object *ob_src = DEG_get_original(dob->ob);
2521 Object *ob_dst = static_cast<Object *>(ID_NEW_SET(ob_src, BKE_id_copy(bmain, &ob_src->id)));
2522 id_us_min(&ob_dst->id);
2523
2524 /* font duplis can have a totcol without material, we get them from parent
2525 * should be implemented better...
2526 */
2527 if (ob_dst->mat == nullptr) {
2528 ob_dst->totcol = 0;
2529 }
2530
2531 BKE_collection_object_add_from(bmain, scene, base->object, ob_dst);
2532 BKE_view_layer_synced_ensure(scene, view_layer);
2533 Base *base_dst = BKE_view_layer_base_find(view_layer, ob_dst);
2534 BLI_assert(base_dst != nullptr);
2535
2536 base_select(base_dst, BA_SELECT);
2538
2540
2541 /* make sure apply works */
2542 BKE_animdata_free(&ob_dst->id, true);
2543 ob_dst->adt = nullptr;
2544
2545 ob_dst->parent = nullptr;
2547 ob_dst->runtime->curve_cache = nullptr;
2548 const bool is_dupli_instancer = (ob_dst->transflag & OB_DUPLI) != 0;
2549 ob_dst->transflag &= ~OB_DUPLI;
2550 /* Remove instantiated collection, it's annoying to keep it here
2551 * (and get potentially a lot of usages of it then...). */
2552 id_us_min((ID *)ob_dst->instance_collection);
2553 ob_dst->instance_collection = nullptr;
2554
2555 copy_m4_m4(ob_dst->runtime->object_to_world.ptr(), dob->mat);
2556 BKE_object_apply_mat4(ob_dst, ob_dst->object_to_world().ptr(), false, false);
2557
2558 dupli_map.add(dob, ob_dst);
2559
2560 if (parent_gh) {
2561 void **val;
2562 /* Due to nature of hash/comparison of this ghash, a lot of duplis may be considered as
2563 * 'the same', this avoids trying to insert same key several time and
2564 * raise asserts in debug builds... */
2565 if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) {
2566 *val = ob_dst;
2567 }
2568
2569 if (is_dupli_instancer && instancer_gh) {
2570 /* Same as above, we may have several 'hits'. */
2571 if (!BLI_ghash_ensure_p(instancer_gh, dob, &val)) {
2572 *val = ob_dst;
2573 }
2574 }
2575 }
2576 }
2577
2578 LISTBASE_FOREACH (DupliObject *, dob, lb_duplis) {
2579 Object *ob_src = dob->ob;
2580 Object *ob_dst = dupli_map.lookup(dob);
2581
2582 /* Remap new object to itself, and clear again newid pointer of orig object. */
2583 BKE_libblock_relink_to_newid(bmain, &ob_dst->id, 0);
2584
2586
2587 if (use_hierarchy) {
2588 /* original parents */
2589 Object *ob_src_par = ob_src->parent;
2590 Object *ob_dst_par = nullptr;
2591
2592 /* find parent that was also made real */
2593 if (ob_src_par) {
2594 /* OK to keep most of the members uninitialized,
2595 * they won't be read, this is simply for a hash lookup. */
2596 DupliObject dob_key;
2597 dob_key.ob = ob_src_par;
2598 dob_key.type = dob->type;
2599 if (dob->type == OB_DUPLICOLLECTION) {
2600 memcpy(&dob_key.persistent_id[1],
2601 &dob->persistent_id[1],
2602 sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1));
2603 }
2604 else {
2605 dob_key.persistent_id[0] = dob->persistent_id[0];
2606 }
2607 ob_dst_par = static_cast<Object *>(BLI_ghash_lookup(parent_gh, &dob_key));
2608 }
2609
2610 if (ob_dst_par) {
2611 /* allow for all possible parent types */
2612 ob_dst->partype = ob_src->partype;
2613 STRNCPY(ob_dst->parsubstr, ob_src->parsubstr);
2614 ob_dst->par1 = ob_src->par1;
2615 ob_dst->par2 = ob_src->par2;
2616 ob_dst->par3 = ob_src->par3;
2617
2618 copy_m4_m4(ob_dst->parentinv, ob_src->parentinv);
2619
2620 ob_dst->parent = ob_dst_par;
2621 }
2622 }
2623 if (use_base_parent && ob_dst->parent == nullptr) {
2624 Object *ob_dst_par = nullptr;
2625
2626 if (instancer_gh != nullptr) {
2627 /* OK to keep most of the members uninitialized,
2628 * they won't be read, this is simply for a hash lookup. */
2629 DupliObject dob_key;
2630 /* We are looking one step upper in hierarchy, so we need to 'shift' the `persistent_id`,
2631 * ignoring the first item.
2632 * We only check on persistent_id here, since we have no idea what object it might be. */
2633 memcpy(&dob_key.persistent_id[0],
2634 &dob->persistent_id[1],
2635 sizeof(dob_key.persistent_id[0]) * (MAX_DUPLI_RECUR - 1));
2636 ob_dst_par = static_cast<Object *>(BLI_ghash_lookup(instancer_gh, &dob_key));
2637 }
2638
2639 if (ob_dst_par == nullptr) {
2640 /* Default to parenting to root object...
2641 * Always the case when use_hierarchy is false. */
2642 ob_dst_par = base->object;
2643 }
2644
2645 ob_dst->parent = ob_dst_par;
2646 ob_dst->partype = PAROBJECT;
2647 }
2648
2649 if (ob_dst->parent) {
2650 /* NOTE: this may be the parent of other objects, but it should
2651 * still work out ok */
2652 BKE_object_apply_mat4(ob_dst, dob->mat, false, true);
2653
2654 /* to set ob_dst->orig and in case there's any other discrepancies */
2656 }
2657 }
2658
2660 base->object->instance_collection = nullptr;
2661 }
2662
2663 base_select(base, BA_DESELECT);
2665
2666 if (parent_gh) {
2667 BLI_ghash_free(parent_gh, nullptr, nullptr);
2668 }
2669 if (instancer_gh) {
2670 BLI_ghash_free(instancer_gh, nullptr, nullptr);
2671 }
2672
2673 free_object_duplilist(lb_duplis);
2674
2676
2677 base->object->transflag &= ~OB_DUPLI;
2679}
2680
2682{
2683 Main *bmain = CTX_data_main(C);
2685 Scene *scene = CTX_data_scene(C);
2686
2687 const bool use_base_parent = RNA_boolean_get(op->ptr, "use_base_parent");
2688 const bool use_hierarchy = RNA_boolean_get(op->ptr, "use_hierarchy");
2689
2691
2692 CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) {
2693 make_object_duplilist_real(C, depsgraph, scene, base, use_base_parent, use_hierarchy);
2694
2695 /* dependencies were changed */
2696 WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, base->object);
2697 }
2699
2704
2705 return OPERATOR_FINISHED;
2706}
2707
2709{
2710 /* identifiers */
2711 ot->name = "Make Instances Real";
2712 ot->description = "Make instanced objects attached to this object real";
2713 ot->idname = "OBJECT_OT_duplicates_make_real";
2714
2715 /* API callbacks. */
2717
2718 ot->poll = ED_operator_objectmode;
2719
2720 /* flags */
2721 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2722
2723 ot->prop = RNA_def_boolean(ot->srna,
2724 "use_base_parent",
2725 false,
2726 "Parent",
2727 "Parent newly created objects to the original instancer");
2730 ot->srna, "use_hierarchy", false, "Keep Hierarchy", "Maintain parent child relationships");
2731}
2732
2734
2735/* -------------------------------------------------------------------- */
2738
2741 "CURVE",
2742 ICON_OUTLINER_OB_CURVE,
2743 "Curve",
2744 "Curve from Mesh or Text objects"},
2745 {OB_MESH,
2746 "MESH",
2747 ICON_OUTLINER_OB_MESH,
2748 "Mesh",
2749 "Mesh from Curve, Surface, Metaball, Text, or Point Cloud objects"},
2751 "POINTCLOUD",
2752 ICON_OUTLINER_OB_POINTCLOUD,
2753 "Point Cloud",
2754 "Point Cloud from Mesh objects"},
2755 {OB_CURVES, "CURVES", ICON_OUTLINER_OB_CURVES, "Curves", "Curves from evaluated curve data"},
2757 "GREASEPENCIL",
2758 ICON_OUTLINER_OB_GREASEPENCIL,
2759 "Grease Pencil",
2760 "Grease Pencil from Curve or Mesh objects"},
2761 {0, nullptr, 0, nullptr, nullptr},
2762};
2763
2765 PointerRNA * /*ptr*/,
2766 PropertyRNA * /*prop*/,
2767 bool *r_free)
2768{
2769 if (!C) { /* needed for docs */
2770 return convert_target_items;
2771 }
2772
2773 EnumPropertyItem *item = nullptr;
2774 int totitem = 0;
2775
2781
2782 RNA_enum_item_end(&item, &totitem);
2783
2784 *r_free = true;
2785
2786 return item;
2787}
2788
2789static void object_data_convert_curve_to_mesh(Main *bmain, Depsgraph *depsgraph, Object *ob)
2790{
2791 Object *object_eval = DEG_get_evaluated(depsgraph, ob);
2792 Curve *curve = static_cast<Curve *>(ob->data);
2793
2794 Mesh *mesh = BKE_mesh_new_from_object_to_bmain(bmain, depsgraph, object_eval, true);
2795 if (mesh == nullptr) {
2796 /* Unable to convert the curve to a mesh. */
2797 return;
2798 }
2799
2801 /* Replace curve used by the object itself. */
2802 ob->data = mesh;
2803 ob->type = OB_MESH;
2804 id_us_min(&curve->id);
2805 id_us_plus(&mesh->id);
2806 /* Change objects which are using same curve.
2807 * A bit annoying, but:
2808 * - It's possible to have multiple curve objects selected which are sharing the same curve
2809 * data-block. We don't want mesh to be created for every of those objects.
2810 * - This is how conversion worked for a long time. */
2811 LISTBASE_FOREACH (Object *, other_object, &bmain->objects) {
2812 if (other_object->data == curve) {
2813 other_object->type = OB_MESH;
2814
2815 id_us_min((ID *)other_object->data);
2816 other_object->data = ob->data;
2817 id_us_plus((ID *)other_object->data);
2818 }
2819 }
2820}
2821
2823{
2824 Scene *scene = CTX_data_scene(C);
2825 if (!ID_IS_EDITABLE(scene)) {
2826 return false;
2827 }
2828 ViewLayer *view_layer = CTX_data_view_layer(C);
2829 BKE_view_layer_synced_ensure(scene, view_layer);
2830 /* Don't use `active_object` in the context, it's important this value
2831 * is from the view-layer as it's used to check if Blender is in edit-mode. */
2832 Object *obact = BKE_view_layer_active_object_get(view_layer);
2833 if (obact && BKE_object_is_in_editmode(obact)) {
2834 return false;
2835 }
2836
2837 /* Note that `obact` may not be editable,
2838 * only check the active object to ensure Blender is not in edit-mode. */
2839 return true;
2840}
2841
2842/* Helper for object_convert_exec */
2844 Main *bmain, Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, Base *base, Object *ob)
2845{
2846 if (ob == nullptr) {
2847 ob = base->object;
2848 }
2849
2850 Object *obn = (Object *)BKE_id_copy(bmain, &ob->id);
2851 id_us_min(&obn->id);
2853 BKE_collection_object_add_from(bmain, scene, ob, obn);
2854
2855 BKE_view_layer_synced_ensure(scene, view_layer);
2856 Base *basen = BKE_view_layer_base_find(view_layer, obn);
2857 base_select(basen, BA_SELECT);
2858 base_select(base, BA_DESELECT);
2859
2860 /* XXX: An ugly hack needed because if we re-run depsgraph with some new meta-ball objects
2861 * having same 'family name' as orig ones, they will affect end result of meta-ball computation.
2862 * For until we get rid of that name-based thingy in meta-balls, that should do the trick
2863 * (this is weak, but other solution (to change name of `obn`) is even worse IMHO).
2864 * See #65996. */
2865 const bool is_meta_ball = (obn->type == OB_MBALL);
2866 void *obdata = obn->data;
2867 if (is_meta_ball) {
2868 obn->type = OB_EMPTY;
2869 obn->data = nullptr;
2870 }
2871
2872 /* XXX Doing that here is stupid, it means we update and re-evaluate the whole depsgraph every
2873 * time we need to duplicate an object to convert it. Even worse, this is not 100% correct, since
2874 * we do not yet have duplicated obdata.
2875 * However, that is a safe solution for now. Proper, longer-term solution is to refactor
2876 * object_convert_exec to:
2877 * - duplicate all data it needs to in a first loop.
2878 * - do a single update.
2879 * - convert data in a second loop. */
2881 CustomData_MeshMasks customdata_mask_prev = scene->customdata_mask;
2884 scene->customdata_mask = customdata_mask_prev;
2885
2886 if (is_meta_ball) {
2887 obn->type = OB_MBALL;
2888 obn->data = obdata;
2889 }
2890
2891 return basen;
2892}
2893
2909
2911{
2912 if (info.keep_original) {
2913 *r_new_base = duplibase_for_convert(
2914 info.bmain, info.depsgraph, info.scene, info.view_layer, &base, nullptr);
2915 Object *newob = (*r_new_base)->object;
2916
2917 /* Decrement original object data usage count. */
2918 ID *original_object_data = static_cast<ID *>(newob->data);
2919 id_us_min(original_object_data);
2920
2921 /* Make a copy of the object data. */
2922 newob->data = BKE_id_copy(info.bmain, original_object_data);
2923
2924 return newob;
2925 }
2926 *r_new_base = nullptr;
2927 return base.object;
2928}
2929
2932 Base **r_new_base)
2933{
2934 Object *ob = base.object;
2935 ob->flag |= OB_DONE;
2936 Object *newob = get_object_for_conversion(base, info, r_new_base);
2937
2938 BKE_mesh_to_curve(info.bmain, info.depsgraph, info.scene, newob);
2939
2940 if (newob->type == OB_CURVES_LEGACY) {
2941 BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
2942 if (newob->rigidbody_object != nullptr) {
2943 ED_rigidbody_object_remove(info.bmain, info.scene, newob);
2944 }
2945 }
2946
2947 return newob;
2948}
2949
2952 Base **r_new_base)
2953{
2954 Object *ob = base.object, *newob = nullptr;
2955 ob->flag |= OB_DONE;
2956
2957 Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
2959 if (ob_eval->runtime->geometry_set_eval != nullptr) {
2960 geometry = *ob_eval->runtime->geometry_set_eval;
2961 }
2962
2963 if (geometry.has_curves()) {
2964 newob = get_object_for_conversion(base, info, r_new_base);
2965
2966 const Curves *curves_eval = geometry.get_curves();
2967 Curves *new_curves = BKE_id_new<Curves>(info.bmain, newob->id.name + 2);
2968
2969 newob->data = new_curves;
2970 newob->type = OB_CURVES;
2971
2972 new_curves->geometry.wrap() = curves_eval->geometry.wrap();
2973 BKE_object_material_from_eval_data(info.bmain, newob, &curves_eval->id);
2974
2976 BKE_object_free_modifiers(newob, 0);
2977 }
2978 else {
2979 BKE_reportf(info.reports,
2981 "Object '%s' has no evaluated Curve or Grease Pencil data",
2982 ob->id.name + 2);
2983 }
2984
2985 return newob;
2986}
2987
2990 Base **r_new_base)
2991{
2992 Object *ob = base.object, *newob = nullptr;
2993 ob->flag |= OB_DONE;
2994
2995 Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
2997 if (ob_eval->runtime->geometry_set_eval != nullptr) {
2998 geometry = *ob_eval->runtime->geometry_set_eval;
2999 }
3000
3001 if (geometry.has_grease_pencil()) {
3002 newob = get_object_for_conversion(base, info, r_new_base);
3003
3004 Curves *new_curves = BKE_id_new<Curves>(info.bmain, newob->id.name + 2);
3005 newob->data = new_curves;
3006 newob->type = OB_CURVES;
3007
3008 if (const Curves *curves_eval = geometry.get_curves()) {
3009 new_curves->geometry.wrap() = curves_eval->geometry.wrap();
3010 BKE_object_material_from_eval_data(info.bmain, newob, &curves_eval->id);
3011 }
3012 else if (const GreasePencil *grease_pencil = geometry.get_grease_pencil()) {
3014 ed::greasepencil::retrieve_visible_drawings(*info.scene, *grease_pencil, false);
3015 if (drawings.size() > 0) {
3016 Array<bke::GeometrySet> geometries(drawings.size());
3017 for (const int i : drawings.index_range()) {
3018 Curves *curves_id = BKE_id_new_nomain<Curves>(nullptr);
3019 curves_id->geometry.wrap() = drawings[i].drawing.strokes();
3020 geometries[i] = bke::GeometrySet::from_curves(curves_id);
3021 }
3022 bke::GeometrySet joined_curves = geometry::join_geometries(geometries, {});
3023
3024 new_curves->geometry.wrap() = joined_curves.get_curves()->geometry.wrap();
3025 new_curves->geometry.wrap().tag_topology_changed();
3026 BKE_object_material_from_eval_data(info.bmain, newob, &joined_curves.get_curves()->id);
3027 }
3028 }
3029
3031 BKE_object_free_modifiers(newob, 0);
3032 }
3033 else {
3034 BKE_reportf(info.reports,
3036 "Object '%s' has no evaluated Curve or Grease Pencil data",
3037 ob->id.name + 2);
3038 }
3039
3040 return newob;
3041}
3042
3044{
3045 Object *newob = convert_curves_component_to_curves(base, info, r_new_base);
3046 if (newob) {
3047 return newob;
3048 }
3049 return convert_grease_pencil_component_to_curves(base, info, r_new_base);
3050}
3051
3054 Base **r_new_base)
3055{
3056 Object *ob = base.object;
3057 ob->flag |= OB_DONE;
3058 Object *newob = get_object_for_conversion(base, info, r_new_base);
3059
3060 BKE_mesh_to_pointcloud(info.bmain, info.depsgraph, info.scene, newob);
3061
3062 if (newob->type == OB_POINTCLOUD) {
3063 BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
3064 ED_rigidbody_object_remove(info.bmain, info.scene, newob);
3065 }
3066
3067 return newob;
3068}
3069
3070static Object *convert_mesh_to_mesh(Base &base, ObjectConversionInfo &info, Base **r_new_base)
3071{
3072 Object *ob = base.object;
3073 ob->flag |= OB_DONE;
3074 Object *newob = get_object_for_conversion(base, info, r_new_base);
3075
3076 /* make new mesh data from the original copy */
3077 /* NOTE: get the mesh from the original, not from the copy in some
3078 * cases this doesn't give correct results (when MDEF is used for eg)
3079 */
3080 const Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
3081 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
3082 Mesh *new_mesh = mesh_eval ? BKE_mesh_copy_for_eval(*mesh_eval) :
3083 BKE_mesh_new_nomain(0, 0, 0, 0);
3084 BKE_object_material_from_eval_data(info.bmain, newob, &new_mesh->id);
3085 /* Anonymous attributes shouldn't be available on the applied geometry. */
3086 new_mesh->attributes_for_write().remove_anonymous();
3087 if (info.do_merge_customdata) {
3089 }
3090
3091 Mesh *ob_data_mesh = (Mesh *)newob->data;
3092
3093 if (ob_data_mesh->key) {
3094 /* NOTE(@ideasman42): Clearing the shape-key is needed when the
3095 * number of vertices remains unchanged. Otherwise using this operator
3096 * to "Apply Visual Geometry" will evaluate using the existing shape-key
3097 * which doesn't have the "evaluated" coordinates from `new_mesh`.
3098 * See #128839 for details.
3099 *
3100 * While shape-keys could be supported, this is more of a feature to consider.
3101 * As there is already a `MESH_OT_blend_from_shape` operator,
3102 * it's not clear this is especially useful or needed. */
3103 if (!CustomData_has_layer(&new_mesh->vert_data, CD_SHAPEKEY)) {
3104 id_us_min(&ob_data_mesh->key->id);
3105 ob_data_mesh->key = nullptr;
3106 }
3107 }
3108 BKE_mesh_nomain_to_mesh(new_mesh, ob_data_mesh, newob);
3109
3110 BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
3111
3112 if (!info.keep_original) {
3114 }
3115
3116 return newob;
3117}
3118
3120 Object &ob_grease_pencil,
3121 const StringRefNull name,
3122 const std::optional<float4> &stroke_color,
3123 const std::optional<float4> &fill_color)
3124{
3125 int index;
3127 &bmain, &ob_grease_pencil, DATA_(name.c_str()), &index);
3128
3129 if (stroke_color.has_value()) {
3130 copy_v4_v4(ma->gp_style->stroke_rgba, stroke_color.value());
3132 }
3133
3134 if (fill_color.has_value()) {
3135 copy_v4_v4(ma->gp_style->fill_rgba, fill_color.value());
3137 }
3138
3139 SET_FLAG_FROM_TEST(ma->gp_style->flag, stroke_color.has_value(), GP_MATERIAL_STROKE_SHOW);
3140 SET_FLAG_FROM_TEST(ma->gp_style->flag, fill_color.has_value(), GP_MATERIAL_FILL_SHOW);
3141
3142 return index;
3143}
3144
3146 public:
3149 bool operator==(const FillColorRecord &other) const
3150 {
3151 return other.color == color && other.name == name;
3152 }
3154 {
3155 return hash_string(name);
3156 }
3157};
3158
3160 Object &ob_mesh, const Mesh &mesh, Array<int> &material_remap)
3161{
3162 const short num_materials = mesh.totcol;
3163 const FillColorRecord empty_fill = {float4(1.0f), DATA_("Empty Fill")};
3164
3165 /* This function will only be called when we want to create fills out of mesh faces, so always
3166 * ensure that fills would have at least one material to be assigned to. */
3167 if (num_materials == 0) {
3168 VectorSet<FillColorRecord> fill_colors;
3169 fill_colors.add(empty_fill);
3170 material_remap.reinitialize(1);
3171 material_remap[0] = 0;
3172 return fill_colors;
3173 }
3174
3175 VectorSet<FillColorRecord> fill_colors;
3176
3177 material_remap.reinitialize(num_materials);
3178
3179 for (const int material_i : IndexRange(num_materials)) {
3180 const Material *mesh_material = BKE_object_material_get(&ob_mesh, material_i + 1);
3181 if (!mesh_material) {
3182 material_remap[material_i] = fill_colors.index_of_or_add(empty_fill);
3183 continue;
3184 }
3185 const float4 fill_color = float4(
3186 mesh_material->r, mesh_material->g, mesh_material->b, mesh_material->a);
3187 const StringRefNull material_name = BKE_id_name(mesh_material->id);
3188 const FillColorRecord record = {fill_color, material_name};
3189 material_remap[material_i] = fill_colors.index_of_or_add(record);
3190 }
3191
3192 return fill_colors;
3193}
3194static void mesh_data_to_grease_pencil(const Mesh &mesh_eval,
3195 GreasePencil &grease_pencil,
3196 const int current_frame,
3197 const bool generate_faces,
3198 const float stroke_radius,
3199 const float offset,
3200 const Array<int> &material_remap)
3201{
3202 grease_pencil.flag |= GREASE_PENCIL_STROKE_ORDER_3D;
3203
3204 if (mesh_eval.edges_num <= 0) {
3205 return;
3206 }
3207
3208 bke::greasepencil::Layer &layer_line = grease_pencil.add_layer(DATA_("Lines"));
3209 bke::greasepencil::Drawing *drawing_line = grease_pencil.insert_frame(layer_line, current_frame);
3210
3211 const Span<float3> mesh_positions = mesh_eval.vert_positions();
3212 const OffsetIndices<int> faces = mesh_eval.faces();
3213 Span<int> faces_span = faces.data();
3214 const Span<int> corner_verts = mesh_eval.corner_verts();
3215
3216 if (generate_faces && !faces.is_empty()) {
3217 bke::greasepencil::Layer &layer_fill = grease_pencil.add_layer(DATA_("Fills"));
3218 bke::greasepencil::Drawing *drawing_fill = grease_pencil.insert_frame(layer_fill,
3219 current_frame);
3220 const int fills_num = faces.size();
3221 const int fills_points_num = corner_verts.size();
3222
3223 drawing_fill->strokes_for_write().resize(fills_points_num, fills_num);
3224 bke::CurvesGeometry &curves_fill = drawing_fill->strokes_for_write();
3225 MutableSpan<float3> positions_fill = curves_fill.positions_for_write();
3226 MutableSpan<int> offsets_fill = curves_fill.offsets_for_write();
3227 MutableSpan<bool> cyclic_fill = curves_fill.cyclic_for_write();
3228 bke::SpanAttributeWriter<int> stroke_materials_fill =
3230 "material_index", bke::AttrDomain::Curve);
3231 bke::AttributeAccessor mesh_attributes = mesh_eval.attributes();
3232 VArray<int> mesh_materials = *mesh_attributes.lookup_or_default(
3233 "material_index", bke::AttrDomain::Face, 0);
3234
3235 curves_fill.fill_curve_types(CURVE_TYPE_POLY);
3236 array_utils::gather(mesh_positions, corner_verts, positions_fill);
3237 array_utils::copy(faces_span, offsets_fill);
3238 cyclic_fill.fill(true);
3239
3240 MutableSpan<int> material_span = stroke_materials_fill.span;
3241 for (const int face_i : material_span.index_range()) {
3242 /* Increase material index by 1 to accommodate the stroke material. */
3243 material_span[face_i] = material_remap[mesh_materials[face_i]] + 1;
3244 }
3245 stroke_materials_fill.finish();
3246 }
3247
3248 Mesh *mesh_copied = BKE_mesh_copy_for_eval(mesh_eval);
3249 const Span<float3> normals = mesh_copied->vert_normals();
3250
3251 std::string unique_attribute_id = BKE_attribute_calc_unique_name(
3252 AttributeOwner::from_id(&mesh_copied->id), "vertex_normal_for_conversion");
3253
3254 mesh_copied->attributes_for_write().add(
3255 unique_attribute_id,
3259
3260 const int edges_num = mesh_copied->edges_num;
3262 *mesh_copied, IndexRange(edges_num), {});
3263
3264 MutableSpan<float3> curve_positions = curves.positions_for_write();
3265 const VArraySpan<float3> point_normals = *curves.attributes().lookup<float3>(
3266 unique_attribute_id);
3267
3268 threading::parallel_for(curve_positions.index_range(), 8192, [&](const IndexRange range) {
3269 for (const int point_i : range) {
3270 curve_positions[point_i] += offset * point_normals[point_i];
3271 }
3272 });
3273
3274 BKE_defgroup_copy_list(&grease_pencil.vertex_group_names, &mesh_copied->vertex_group_names);
3275
3276 curves.radius_for_write().fill(stroke_radius);
3277
3278 drawing_line->strokes_for_write() = std::move(curves);
3279 drawing_line->tag_topology_changed();
3280
3281 BKE_id_free(nullptr, mesh_copied);
3282}
3283
3286 Base **r_new_base)
3287{
3288 Object *ob = base.object;
3289 ob->flag |= OB_DONE;
3290 Object *newob = get_object_for_conversion(base, info, r_new_base);
3291
3292 const bool generate_faces = RNA_boolean_get(info.op_props, "faces");
3293 const int thickness = RNA_int_get(info.op_props, "thickness");
3294 const float offset = RNA_float_get(info.op_props, "offset");
3295
3296 /* To be compatible with the thickness value of legacy Grease Pencil. */
3297 const float stroke_radius = float(thickness) / 2 *
3299
3300 Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
3301 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
3302
3303 VectorSet<FillColorRecord> fill_colors;
3304 Array<int> material_remap;
3305 if (generate_faces) {
3306 fill_colors = mesh_to_grease_pencil_get_material_list(*ob_eval, *mesh_eval, material_remap);
3307 }
3308
3310 BKE_object_free_modifiers(newob, 0);
3311
3312 GreasePencil *grease_pencil = BKE_grease_pencil_add(info.bmain, BKE_id_name(mesh_eval->id));
3313 newob->data = grease_pencil;
3314 newob->type = OB_GREASE_PENCIL;
3315
3316 /* Reset object material array and count since currently the generic / grease pencil material
3317 * functions still depend on this value being coherent (The same value as
3318 * `GreasePencil::material_array_num`).
3319 */
3320 BKE_object_material_resize(info.bmain, newob, 0, true);
3321
3323 *info.bmain, *newob, DATA_("Stroke"), float4(0.0f, 0.0f, 0.0f, 1.0f), {});
3324
3325 if (generate_faces) {
3326 for (const int fill_i : fill_colors.index_range()) {
3327 const FillColorRecord &record = fill_colors[fill_i];
3328 mesh_to_grease_pencil_add_material(*info.bmain, *newob, record.name, {}, record.color);
3329 }
3330 }
3331
3332 mesh_data_to_grease_pencil(*mesh_eval,
3333 *grease_pencil,
3334 info.scene->r.cfra,
3335 generate_faces,
3336 stroke_radius,
3337 offset,
3338 material_remap);
3339
3340 return newob;
3341}
3342
3344 const ObjectType target,
3346 Base **r_new_base)
3347{
3348 switch (target) {
3349 case OB_CURVES_LEGACY:
3350 return convert_mesh_to_curves_legacy(base, info, r_new_base);
3351 case OB_CURVES:
3352 return convert_mesh_to_curves(base, info, r_new_base);
3353 case OB_POINTCLOUD:
3354 return convert_mesh_to_pointcloud(base, info, r_new_base);
3355 case OB_MESH:
3356 return convert_mesh_to_mesh(base, info, r_new_base);
3357 case OB_GREASE_PENCIL:
3358 return convert_mesh_to_grease_pencil(base, info, r_new_base);
3359 default:
3360 /* Current logic does convert mesh to mesh for any other target types. This would change
3361 * after other types of conversion are designed and implemented. */
3362 return convert_mesh_to_mesh(base, info, r_new_base);
3363 }
3364}
3365
3367{
3368 Object *ob = base.object, *newob = nullptr;
3369 ob->flag |= OB_DONE;
3370
3371 Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
3373 if (ob_eval->runtime->geometry_set_eval != nullptr) {
3374 geometry = *ob_eval->runtime->geometry_set_eval;
3375 }
3376
3377 const Mesh *mesh_eval = geometry.get_mesh();
3378 const Curves *curves_eval = geometry.get_curves();
3379 Mesh *new_mesh = nullptr;
3380
3381 if (mesh_eval || curves_eval) {
3382 newob = get_object_for_conversion(base, info, r_new_base);
3383 new_mesh = BKE_id_new<Mesh>(info.bmain, newob->id.name + 2);
3384 newob->data = new_mesh;
3385 newob->type = OB_MESH;
3386 }
3387 else {
3388 BKE_reportf(info.reports,
3390 "Object '%s' has no evaluated mesh or curves data",
3391 ob->id.name + 2);
3392 return nullptr;
3393 }
3394
3395 if (mesh_eval) {
3396 BKE_mesh_nomain_to_mesh(BKE_mesh_copy_for_eval(*mesh_eval), new_mesh, newob);
3397 BKE_object_material_from_eval_data(info.bmain, newob, &mesh_eval->id);
3398 new_mesh->attributes_for_write().remove_anonymous();
3399 }
3400 else if (curves_eval) {
3401 Mesh *mesh = bke::curve_to_wire_mesh(curves_eval->geometry.wrap(),
3403 if (!mesh) {
3404 mesh = BKE_mesh_new_nomain(0, 0, 0, 0);
3405 }
3406 BKE_mesh_nomain_to_mesh(mesh, new_mesh, newob);
3407 BKE_object_material_from_eval_data(info.bmain, newob, &curves_eval->id);
3408 }
3409
3411 BKE_object_free_modifiers(newob, 0);
3412
3413 return newob;
3414}
3415
3418 Base **r_new_base)
3419{
3420 Object *ob = base.object, *newob = nullptr;
3421 ob->flag |= OB_DONE;
3422
3423 Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
3425 if (ob_eval->runtime->geometry_set_eval != nullptr) {
3426 geometry = *ob_eval->runtime->geometry_set_eval;
3427 }
3428
3429 const GreasePencil *grease_pencil_eval = geometry.get_grease_pencil();
3430 const Curves *curves_eval = geometry.get_curves();
3431 GreasePencil *new_grease_pencil = nullptr;
3432
3433 if (grease_pencil_eval || curves_eval) {
3434 newob = get_object_for_conversion(base, info, r_new_base);
3435 new_grease_pencil = BKE_id_new<GreasePencil>(info.bmain, newob->id.name + 2);
3436 newob->data = new_grease_pencil;
3437 newob->type = OB_GREASE_PENCIL;
3438 }
3439 else {
3440 BKE_reportf(info.reports,
3442 "Object '%s' has no evaluated Grease Pencil or Curves data",
3443 ob->id.name + 2);
3444 return nullptr;
3445 }
3446
3447 if (grease_pencil_eval) {
3449 new_grease_pencil);
3450 BKE_object_material_from_eval_data(info.bmain, newob, &grease_pencil_eval->id);
3451 new_grease_pencil->attributes_for_write().remove_anonymous();
3452 }
3453 else if (curves_eval) {
3454 GreasePencil *grease_pencil = BKE_grease_pencil_new_nomain();
3455 /* Insert a default layer and place the drawing on frame 1. */
3456 const std::string layer_name = "Layer";
3457 const int frame_number = 1;
3458 bke::greasepencil::Layer &layer = grease_pencil->add_layer(layer_name);
3459 bke::greasepencil::Drawing *drawing = grease_pencil->insert_frame(layer, frame_number);
3460 BLI_assert(drawing != nullptr);
3461 drawing->strokes_for_write() = curves_eval->geometry.wrap();
3462 /* Default radius (1.0 unit) is too thick for converted strokes. */
3463 drawing->radii_for_write().fill(0.01f);
3464
3465 BKE_grease_pencil_nomain_to_grease_pencil(grease_pencil, new_grease_pencil);
3466 BKE_object_material_from_eval_data(info.bmain, newob, &curves_eval->id);
3467 }
3468
3470 BKE_object_free_modifiers(newob, 0);
3471
3472 return newob;
3473}
3474
3476 const ObjectType target,
3478 Base **r_new_base)
3479{
3480 switch (target) {
3481 case OB_MESH:
3482 return convert_curves_to_mesh(base, info, r_new_base);
3483 case OB_GREASE_PENCIL:
3484 return convert_curves_to_grease_pencil(base, info, r_new_base);
3485 default:
3486 return convert_curves_component_to_curves(base, info, r_new_base);
3487 }
3488}
3489
3492 Base **r_new_base)
3493{
3494 Object *ob = base.object, *newob = nullptr;
3495 ob->flag |= OB_DONE;
3496
3497 /* Mostly same as converting to OB_CURVES, the mesh will be converted from Curves afterwards. */
3498
3499 Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
3501 if (ob_eval->runtime->geometry_set_eval != nullptr) {
3502 geometry = *ob_eval->runtime->geometry_set_eval;
3503 }
3504
3505 if (geometry.has_curves()) {
3506 newob = get_object_for_conversion(base, info, r_new_base);
3507
3508 const Curves *curves_eval = geometry.get_curves();
3509 Curves *new_curves = BKE_id_new<Curves>(info.bmain, newob->id.name + 2);
3510
3511 newob->data = new_curves;
3512 newob->type = OB_CURVES;
3513
3514 new_curves->geometry.wrap() = curves_eval->geometry.wrap();
3515 BKE_object_material_from_eval_data(info.bmain, newob, &curves_eval->id);
3516
3518 BKE_object_free_modifiers(newob, 0);
3519 }
3520 else if (geometry.has_grease_pencil()) {
3521 newob = get_object_for_conversion(base, info, r_new_base);
3522
3523 /* Do not link `new_curves` to `bmain` since it's temporary. */
3524 Curves *new_curves = BKE_id_new_nomain<Curves>(newob->id.name + 2);
3525
3526 newob->data = new_curves;
3527 newob->type = OB_CURVES;
3528
3529 if (const Curves *curves_eval = geometry.get_curves()) {
3530 new_curves->geometry.wrap() = curves_eval->geometry.wrap();
3531 BKE_object_material_from_eval_data(info.bmain, newob, &curves_eval->id);
3532 }
3533 else if (const GreasePencil *grease_pencil = geometry.get_grease_pencil()) {
3535 ed::greasepencil::retrieve_visible_drawings(*info.scene, *grease_pencil, false);
3536 Array<bke::GeometrySet> geometries(drawings.size());
3537 for (const int i : drawings.index_range()) {
3538 Curves *curves_id = BKE_id_new_nomain<Curves>(nullptr);
3539 curves_id->geometry.wrap() = drawings[i].drawing.strokes();
3540 const int layer_index = drawings[i].layer_index;
3541 const bke::greasepencil::Layer *layer = grease_pencil->layers()[layer_index];
3542 blender::float4x4 to_object = layer->to_object_space(*ob);
3543 bke::CurvesGeometry &new_curves = curves_id->geometry.wrap();
3544 MutableSpan<blender::float3> positions = new_curves.positions_for_write();
3545 for (const int point_i : new_curves.points_range()) {
3546 positions[point_i] = blender::math::transform_point(to_object, positions[point_i]);
3547 }
3548 geometries[i] = bke::GeometrySet::from_curves(curves_id);
3549 }
3550 if (geometries.size() > 0) {
3551 bke::GeometrySet joined_curves = geometry::join_geometries(geometries, {});
3552
3553 new_curves->geometry.wrap() = joined_curves.get_curves()->geometry.wrap();
3554 new_curves->geometry.wrap().tag_topology_changed();
3555 BKE_object_material_from_eval_data(info.bmain, newob, &joined_curves.get_curves()->id);
3556 }
3557 }
3558
3559 Mesh *new_mesh = BKE_id_new<Mesh>(info.bmain, newob->id.name + 2);
3560 newob->data = new_mesh;
3561 newob->type = OB_MESH;
3562
3563 Mesh *mesh = bke::curve_to_wire_mesh(new_curves->geometry.wrap(), {});
3564 if (!mesh) {
3565 mesh = BKE_mesh_new_nomain(0, 0, 0, 0);
3566 }
3567 BKE_mesh_nomain_to_mesh(mesh, new_mesh, newob);
3568 BKE_object_material_from_eval_data(info.bmain, newob, &new_curves->id);
3569
3570 /* Free `new_curves` because it is just an intermediate. */
3571 BKE_id_free(nullptr, new_curves);
3572
3574 BKE_object_free_modifiers(newob, 0);
3575 }
3576 else {
3578 info.reports, RPT_WARNING, "Object '%s' has no evaluated curves data", ob->id.name + 2);
3579 }
3580
3581 return newob;
3582}
3583
3585 const ObjectType target,
3587 Base **r_new_base)
3588{
3589 switch (target) {
3590 case OB_CURVES:
3591 return convert_grease_pencil_component_to_curves(base, info, r_new_base);
3592 case OB_MESH:
3593 return convert_grease_pencil_to_mesh(base, info, r_new_base);
3594 default:
3595 return nullptr;
3596 }
3597 return nullptr;
3598}
3599
3601 Object *newob,
3603{
3604 Curve *cu = static_cast<Curve *>(newob->data);
3605
3606 Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
3607 BKE_vfont_to_curve_ex(ob_eval,
3608 static_cast<Curve *>(ob_eval->data),
3609 FO_EDIT,
3610 &cu->nurb,
3611 nullptr,
3612 nullptr,
3613 nullptr,
3614 nullptr,
3615 nullptr);
3616
3617 newob->type = OB_CURVES_LEGACY;
3619
3620#define CURVE_VFONT_CLEAR(vfont_member) \
3621 if (cu->vfont_member) { \
3622 id_us_min(&cu->vfont_member->id); \
3623 cu->vfont_member = nullptr; \
3624 } \
3625 ((void)0)
3626
3627 CURVE_VFONT_CLEAR(vfont);
3628 CURVE_VFONT_CLEAR(vfontb);
3629 CURVE_VFONT_CLEAR(vfonti);
3630 CURVE_VFONT_CLEAR(vfontbi);
3631
3632#undef CURVE_VFONT_CLEAR
3633
3634 if (!info.keep_original) {
3635 /* other users */
3636 Object *ob1 = nullptr;
3637 if (ID_REAL_USERS(&cu->id) > 1) {
3638 for (ob1 = static_cast<Object *>(info.bmain->objects.first); ob1;
3639 ob1 = static_cast<Object *>(ob1->id.next))
3640 {
3641 if (ob1->data == ob->data && ob1 != ob) {
3642 ob1->type = OB_CURVES_LEGACY;
3643 DEG_id_tag_update(&ob1->id,
3645 }
3646 }
3647 }
3648 }
3649
3650 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
3651 nu->charidx = 0;
3652 }
3653
3654 cu->flag &= ~CU_3D;
3656
3657 return newob;
3658}
3659
3662 Base **r_new_base)
3663{
3664 Object *ob = base.object;
3665 ob->flag |= OB_DONE;
3666 Object *newob = get_object_for_conversion(base, info, r_new_base);
3667
3668 return convert_font_to_curve_legacy_generic(ob, newob, info);
3669}
3670
3672{
3673 Object *ob = base.object;
3674 ob->flag |= OB_DONE;
3675 Object *newob = get_object_for_conversion(base, info, r_new_base);
3676 Object *curve_ob = convert_font_to_curve_legacy_generic(ob, newob, info);
3677 BLI_assert(curve_ob->type == OB_CURVES_LEGACY);
3678
3679 Curve *legacy_curve_id = static_cast<Curve *>(curve_ob->data);
3680 Curves *curves_nomain = bke::curve_legacy_to_curves(*legacy_curve_id);
3681
3682 Curves *curves_id = BKE_curves_add(info.bmain, BKE_id_name(legacy_curve_id->id));
3683 curves_id->geometry.wrap() = curves_nomain->geometry.wrap();
3684
3685 blender::bke::curves_copy_parameters(*curves_nomain, *curves_id);
3686
3687 curve_ob->data = curves_id;
3688 curve_ob->type = OB_CURVES;
3689
3690 BKE_id_free(nullptr, curves_nomain);
3691
3692 return curve_ob;
3693}
3694
3695/* Currently neither Grease Pencil nor legacy curves supports per-stroke/curve fill attribute, thus
3696 * the #fill argument applies on all strokes that are converted. */
3698 ID &from_id,
3699 Object &gp_object,
3700 const bool use_fill)
3701{
3702 short *len_p = BKE_id_material_len_p(&from_id);
3703 if (!len_p || *len_p == 0) {
3704 return;
3705 }
3706 Material ***materials = BKE_id_material_array_p(&from_id);
3707 if (!materials || !(*materials)) {
3708 return;
3709 }
3710 for (short i = 0; i < *len_p; i++) {
3711 const Material *orig_material = (*materials)[i];
3712 const char *name = orig_material ? BKE_id_name(orig_material->id) : IFACE_("Empty Material");
3713
3715 &bmain, &gp_object, name, nullptr);
3716
3717 /* If the original object has this material slot but didn't assign any material, then we don't
3718 * have anything to copy color information from. In those cases we still added an empty
3719 * material to keep the material index matching. */
3720 if (!orig_material) {
3721 continue;
3722 }
3723
3724 copy_v4_v4(gp_material->gp_style->fill_rgba, &orig_material->r);
3725
3726 SET_FLAG_FROM_TEST(gp_material->gp_style->flag, !use_fill, GP_MATERIAL_STROKE_SHOW);
3727 SET_FLAG_FROM_TEST(gp_material->gp_style->flag, use_fill, GP_MATERIAL_FILL_SHOW);
3728 }
3729}
3730
3733 Base **r_new_base)
3734{
3735 Object *ob = base.object;
3736 ob->flag |= OB_DONE;
3737 Object *newob = get_object_for_conversion(base, info, r_new_base);
3738 Object *curve_ob = convert_font_to_curve_legacy_generic(ob, newob, info);
3739 BLI_assert(curve_ob->type == OB_CURVES_LEGACY);
3740
3741 Curve *legacy_curve_id = static_cast<Curve *>(curve_ob->data);
3742 Curves *curves_nomain = bke::curve_legacy_to_curves(*legacy_curve_id);
3743
3744 GreasePencil *grease_pencil = BKE_grease_pencil_add(info.bmain,
3745 BKE_id_name(legacy_curve_id->id));
3746 bke::greasepencil::Layer &layer = grease_pencil->add_layer(DATA_("Converted Layer"));
3747
3748 const int current_frame = info.scene->r.cfra;
3749
3750 bke::greasepencil::Drawing *drawing = grease_pencil->insert_frame(layer, current_frame);
3751
3752 blender::bke::CurvesGeometry &curves = curves_nomain->geometry.wrap();
3753
3754 drawing->strokes_for_write() = std::move(curves);
3755 /* Default radius (1.0 unit) is too thick for converted strokes. */
3756 drawing->radii_for_write().fill(0.01f);
3757 drawing->tag_positions_changed();
3758
3759 curve_ob->data = grease_pencil;
3760 curve_ob->type = OB_GREASE_PENCIL;
3761 curve_ob->totcol = grease_pencil->material_array_num;
3762
3763 const bool use_fill = (legacy_curve_id->flag & (CU_FRONT | CU_BACK)) != 0;
3764 add_grease_pencil_materials_for_conversion(*info.bmain, legacy_curve_id->id, *newob, use_fill);
3765
3766 /* We don't need the intermediate font/curve data ID any more. */
3767 BKE_id_delete(info.bmain, legacy_curve_id);
3768
3769 BKE_id_free(nullptr, curves_nomain);
3770
3771 return curve_ob;
3772}
3773
3774static Object *convert_font_to_mesh(Base &base, ObjectConversionInfo &info, Base **r_new_base)
3775{
3776 Object *newob = convert_font_to_curves_legacy(base, info, r_new_base);
3777
3778 /* No assumption should be made that the resulting objects is a mesh, as conversion can
3779 * fail. */
3781
3782 /* Meshes doesn't use the "curve cache". */
3784
3785 return newob;
3786}
3787
3789 const short target,
3791 Base **r_new_base)
3792{
3793 switch (target) {
3794 case OB_MESH:
3795 return convert_font_to_mesh(base, info, r_new_base);
3796 case OB_CURVES_LEGACY:
3797 return convert_font_to_curves_legacy(base, info, r_new_base);
3798 case OB_CURVES:
3799 return convert_font_to_curves(base, info, r_new_base);
3800 case OB_GREASE_PENCIL:
3801 return convert_font_to_grease_pencil(base, info, r_new_base);
3802 default:
3803 return nullptr;
3804 }
3805 return nullptr;
3806}
3807
3810 Base **r_new_base)
3811{
3812 Object *ob = base.object;
3813 ob->flag |= OB_DONE;
3814 Object *newob = get_object_for_conversion(base, info, r_new_base);
3815
3816 /* No assumption should be made that the resulting objects is a mesh, as conversion can
3817 * fail. */
3819
3820 /* Meshes doesn't use the "curve cache". */
3822
3823 return newob;
3824}
3825
3828 Base **r_new_base)
3829{
3830 Object *newob = convert_curves_component_to_curves(base, info, r_new_base);
3831 if (newob) {
3832 return newob;
3833 }
3834 return convert_grease_pencil_component_to_curves(base, info, r_new_base);
3835}
3836
3839 Base **r_new_base)
3840{
3841 Object *ob = base.object;
3842 ob->flag |= OB_DONE;
3843 Object *newob = get_object_for_conversion(base, info, r_new_base);
3844 BLI_assert(newob->type == OB_CURVES_LEGACY);
3845
3846 Curve *legacy_curve_id = static_cast<Curve *>(newob->data);
3847 Curves *curves_nomain = bke::curve_legacy_to_curves(*legacy_curve_id);
3848
3849 GreasePencil *grease_pencil = BKE_grease_pencil_add(info.bmain,
3850 BKE_id_name(legacy_curve_id->id));
3851 bke::greasepencil::Layer &layer = grease_pencil->add_layer(DATA_("Converted Layer"));
3852
3853 const int current_frame = info.scene->r.cfra;
3854
3855 bke::greasepencil::Drawing *drawing = grease_pencil->insert_frame(layer, current_frame);
3856
3857 blender::bke::CurvesGeometry &curves = curves_nomain->geometry.wrap();
3858
3859 drawing->strokes_for_write() = std::move(curves);
3860 /* Default radius (1.0 unit) is too thick for converted strokes. */
3861 drawing->radii_for_write().fill(0.01f);
3862 drawing->tag_positions_changed();
3863
3864 newob->data = grease_pencil;
3865 newob->type = OB_GREASE_PENCIL;
3866
3867 /* Some functions like #BKE_id_material_len_p still uses Object::totcol so this value must be in
3868 * sync. */
3869 newob->totcol = grease_pencil->material_array_num;
3870
3871 const bool use_fill = (legacy_curve_id->flag & (CU_FRONT | CU_BACK)) != 0;
3872 add_grease_pencil_materials_for_conversion(*info.bmain, legacy_curve_id->id, *newob, use_fill);
3873
3874 /* For some reason this must be called, otherwise evaluated id_cow will still be the original
3875 * curves id (and that seems to only happen if "Keep Original" is enabled, and only with this
3876 * specific conversion combination), not sure why. Ref: #138793 */
3877 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
3878
3879 BKE_id_free(nullptr, curves_nomain);
3880
3881 return newob;
3882}
3883
3885 const ObjectType target,
3887 Base **r_new_base)
3888{
3889 switch (target) {
3890 case OB_MESH:
3891 return convert_curves_legacy_to_mesh(base, info, r_new_base);
3892 case OB_CURVES:
3893 return convert_curves_legacy_to_curves(base, info, r_new_base);
3894 case OB_GREASE_PENCIL:
3895 return convert_curves_legacy_to_grease_pencil(base, info, r_new_base);
3896 default:
3897 return nullptr;
3898 }
3899}
3900
3903 bool &r_mball_converted,
3904 Base **r_new_base,
3905 Base **r_act_base)
3906{
3907 Object *ob = base.object;
3908 Object *newob = nullptr;
3909 Object *baseob = nullptr;
3910
3911 base.flag &= ~BASE_SELECTED;
3913
3914 baseob = BKE_mball_basis_find(info.scene, ob);
3915
3916 if (ob != baseob) {
3917 /* If mother-ball is converting it would be marked as done later. */
3918 ob->flag |= OB_DONE;
3919 }
3920
3921 if (!(baseob->flag & OB_DONE)) {
3922 *r_new_base = duplibase_for_convert(
3923 info.bmain, info.depsgraph, info.scene, info.view_layer, &base, baseob);
3924 newob = (*r_new_base)->object;
3925
3926 MetaBall *mb = static_cast<MetaBall *>(newob->data);
3927 id_us_min(&mb->id);
3928
3929 /* Find the evaluated mesh of the basis metaball object. */
3930 Object *object_eval = DEG_get_evaluated(info.depsgraph, baseob);
3931 Mesh *mesh = BKE_mesh_new_from_object_to_bmain(info.bmain, info.depsgraph, object_eval, true);
3932
3933 id_us_plus(&mesh->id);
3934 newob->data = mesh;
3935 newob->type = OB_MESH;
3936
3937 if (info.obact && (info.obact->type == OB_MBALL)) {
3938 *r_act_base = *r_new_base;
3939 }
3940
3941 baseob->flag |= OB_DONE;
3942 r_mball_converted = true;
3943 }
3944
3945 return newob;
3946}
3947
3949 const ObjectType target,
3951 bool &r_mball_converted,
3952 Base **r_new_base,
3953 Base **r_act_base)
3954{
3955 switch (target) {
3956 case OB_MESH:
3957 return convert_mball_to_mesh(base, info, r_mball_converted, r_new_base, r_act_base);
3958 default:
3959 return nullptr;
3960 }
3961}
3962
3965 Base **r_new_base)
3966{
3967 Object *ob = base.object;
3968 ob->flag |= OB_DONE;
3969 Object *newob = get_object_for_conversion(base, info, r_new_base);
3970
3971 BKE_pointcloud_to_mesh(info.bmain, info.depsgraph, info.scene, newob);
3972
3973 if (newob->type == OB_MESH) {
3974 BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
3975 ED_rigidbody_object_remove(info.bmain, info.scene, newob);
3976 }
3977
3978 return newob;
3979}
3980
3982 const ObjectType target,
3984 Base **r_new_base)
3985{
3986 switch (target) {
3987 case OB_MESH:
3988 return convert_pointcloud_to_mesh(base, info, r_new_base);
3989 default:
3990 return nullptr;
3991 }
3992}
3993
3995{
3996 Main *bmain = CTX_data_main(C);
3998 Scene *scene = CTX_data_scene(C);
3999 ViewLayer *view_layer = CTX_data_view_layer(C);
4000
4001 const short target = RNA_enum_get(op->ptr, "target");
4002 bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
4003 const bool do_merge_customdata = RNA_boolean_get(op->ptr, "merge_customdata");
4004
4005 Vector<PointerRNA> selected_editable_bases;
4006 CTX_data_selected_editable_bases(C, &selected_editable_bases);
4007
4008 /* Too expensive to detect on poll(). */
4009 if (selected_editable_bases.is_empty()) {
4010 BKE_report(op->reports, RPT_INFO, "No editable objects to convert");
4011 return OPERATOR_CANCELLED;
4012 }
4013
4014 /* don't forget multiple users! */
4015
4016 {
4017 FOREACH_SCENE_OBJECT_BEGIN (scene, ob) {
4018 ob->flag &= ~OB_DONE;
4019
4020 /* flag data that's not been edited (only needed for !keep_original) */
4021 if (ob->data) {
4022 ((ID *)ob->data)->tag |= ID_TAG_DOIT;
4023 }
4024
4025 /* possible metaball basis is not in this scene */
4026 if (ob->type == OB_MBALL && target == OB_MESH) {
4027 if (BKE_mball_is_basis(ob) == false) {
4028 Object *ob_basis;
4029 ob_basis = BKE_mball_basis_find(scene, ob);
4030 if (ob_basis) {
4031 ob_basis->flag &= ~OB_DONE;
4032 }
4033 }
4034 }
4035 }
4037 }
4038
4040 info.bmain = bmain;
4041 info.depsgraph = depsgraph;
4042 info.scene = scene;
4043 info.view_layer = view_layer;
4044 info.obact = BKE_view_layer_active_object_get(view_layer);
4045 info.keep_original = keep_original;
4046 info.do_merge_customdata = do_merge_customdata;
4047 info.op_props = op->ptr;
4048 info.reports = op->reports;
4049
4050 Base *act_base = nullptr;
4051
4052 /* Ensure we get all meshes calculated with a sufficient data-mask,
4053 * needed since re-evaluating single modifiers causes bugs if they depend
4054 * on other objects data masks too, see: #50950. */
4055 {
4056 for (const PointerRNA &ptr : selected_editable_bases) {
4057 Base *base = static_cast<Base *>(ptr.data);
4058 Object *ob = base->object;
4059
4060 /* The way object type conversion works currently (enforcing conversion of *all* objects
4061 * using converted object-data, even some un-selected/hidden/another scene ones,
4062 * sounds totally bad to me.
4063 * However, changing this is more design than bug-fix, not to mention convoluted code below,
4064 * so that will be for later.
4065 * But at the very least, do not do that with linked IDs! */
4066 if ((!BKE_id_is_editable(bmain, &ob->id) ||
4067 (ob->data && !BKE_id_is_editable(bmain, static_cast<ID *>(ob->data)))) &&
4068 !keep_original)
4069 {
4070 keep_original = true;
4071 BKE_report(op->reports,
4072 RPT_INFO,
4073 "Converting some non-editable object/object data, enforcing 'Keep Original' "
4074 "option to True");
4075 }
4076
4078 }
4079
4080 CustomData_MeshMasks customdata_mask_prev = scene->customdata_mask;
4083 scene->customdata_mask = customdata_mask_prev;
4084 }
4085
4086 bool mball_converted = false;
4087 int incompatible_count = 0;
4088
4089 for (const PointerRNA &ptr : selected_editable_bases) {
4090 Object *newob = nullptr;
4091 Base *base = static_cast<Base *>(ptr.data), *new_base = nullptr;
4092 Object *ob = base->object;
4093
4094 if (ob->flag & OB_DONE || !IS_TAGGED(ob->data)) {
4095 if (ob->type != target) {
4096 base->flag &= ~SELECT;
4097 ob->flag &= ~SELECT;
4098 }
4099
4100 /* obdata already modified */
4101 if (!IS_TAGGED(ob->data)) {
4102 /* When 2 objects with linked data are selected, converting both
4103 * would keep modifiers on all but the converted object #26003. */
4104 if (ob->type == OB_MESH) {
4105 BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */
4106 }
4107 }
4108 }
4109 else {
4110 const ObjectType target_type = ObjectType(target);
4111 switch (ob->type) {
4112 case OB_MESH:
4113 newob = convert_mesh(*base, target_type, info, &new_base);
4114 break;
4115 case OB_CURVES:
4116 newob = convert_curves(*base, target_type, info, &new_base);
4117 break;
4118 case OB_CURVES_LEGACY:
4120 case OB_SURF:
4121 newob = convert_curves_legacy(*base, target_type, info, &new_base);
4122 break;
4123 case OB_FONT:
4124 newob = convert_font(*base, target_type, info, &new_base);
4125 break;
4126 case OB_GREASE_PENCIL:
4127 newob = convert_grease_pencil(*base, target_type, info, &new_base);
4128 break;
4129 case OB_MBALL:
4130 newob = convert_mball(*base, target_type, info, mball_converted, &new_base, &act_base);
4131 break;
4132 case OB_POINTCLOUD:
4133 newob = convert_pointcloud(*base, target_type, info, &new_base);
4134 break;
4135 default:
4136 incompatible_count++;
4137 continue;
4138 }
4139 }
4140
4141 /* Ensure new object has consistent material data with its new obdata. */
4142 if (newob) {
4143 BKE_object_materials_sync_length(bmain, newob, static_cast<ID *>(newob->data));
4144 }
4145
4146 /* tag obdata if it was been changed */
4147
4148 /* If the original object is active then make this object active */
4149 if (new_base) {
4150 if (info.obact && (info.obact == ob)) {
4151 /* Store new active base to update view layer. */
4152 act_base = new_base;
4153 }
4154 new_base = nullptr;
4155 }
4156
4157 if (!keep_original && (ob->flag & OB_DONE)) {
4158 /* NOTE: Tag transform for update because object parenting to curve with path is handled
4159 * differently from all other cases. Converting curve to mesh and mesh to curve will likely
4160 * affect the way children are evaluated.
4161 * It is not enough to tag only geometry and rely on the curve parenting relations because
4162 * this relation is lost when curve is converted to mesh. */
4164 ((ID *)ob->data)->tag &= ~ID_TAG_DOIT; /* flag not to convert this datablock again */
4165 }
4166 }
4167
4168 if (!keep_original) {
4169 if (mball_converted) {
4170 /* We need to remove non-basis MBalls first, otherwise we won't be able to detect them if
4171 * their basis happens to be removed first. */
4172 FOREACH_SCENE_OBJECT_BEGIN (scene, ob_mball) {
4173 if (ob_mball->type == OB_MBALL) {
4174 Object *ob_basis = nullptr;
4175 if (!BKE_mball_is_basis(ob_mball) &&
4176 ((ob_basis = BKE_mball_basis_find(scene, ob_mball)) && (ob_basis->flag & OB_DONE)))
4177 {
4178 base_free_and_unlink(bmain, scene, ob_mball);
4179 }
4180 }
4181 }
4183 FOREACH_SCENE_OBJECT_BEGIN (scene, ob_mball) {
4184 if (ob_mball->type == OB_MBALL) {
4185 if (ob_mball->flag & OB_DONE) {
4186 if (BKE_mball_is_basis(ob_mball)) {
4187 base_free_and_unlink(bmain, scene, ob_mball);
4188 }
4189 }
4190 }
4191 }
4193 }
4194 }
4195
4196 // XXX: editmode_enter(C, 0);
4197 // XXX: exit_editmode(C, EM_FREEDATA|); /* free data, but no undo. */
4198
4199 if (act_base) {
4200 /* active base was changed */
4201 base_activate(C, act_base);
4202 view_layer->basact = act_base;
4203 }
4204 else {
4205 BKE_view_layer_synced_ensure(scene, view_layer);
4206 if (Object *object = BKE_view_layer_active_object_get(view_layer)) {
4207 if (object->flag & OB_DONE) {
4210 }
4211 }
4212 }
4213
4214 if (incompatible_count != 0) {
4215 const char *target_type_name = "";
4216 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "target");
4217 BLI_assert(prop != nullptr);
4218 RNA_property_enum_name(C, op->ptr, prop, target, &target_type_name);
4219 if (incompatible_count == selected_editable_bases.size()) {
4220 BKE_reportf(op->reports,
4221 RPT_INFO,
4222 "None of the objects are compatible with a conversion to \"%s\"",
4223 RPT_(target_type_name));
4224 }
4225 else {
4227 op->reports,
4228 RPT_INFO,
4229 "The selection included %d object type(s) which do not support conversion to \"%s\"",
4230 incompatible_count,
4231 RPT_(target_type_name));
4232 }
4233 }
4234
4240
4241 return OPERATOR_FINISHED;
4242}
4243
4244static void object_convert_ui(bContext * /*C*/, wmOperator *op)
4245{
4246 uiLayout *layout = op->layout;
4247
4248 uiLayoutSetPropSep(layout, true);
4249
4250 layout->prop(op->ptr, "target", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4251 layout->prop(op->ptr, "keep_original", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4252
4253 const int target = RNA_enum_get(op->ptr, "target");
4254 if (target == OB_MESH) {
4255 layout->prop(op->ptr, "merge_customdata", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4256 }
4257 else if (target == OB_GREASE_PENCIL) {
4258 layout->prop(op->ptr, "thickness", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4259 layout->prop(op->ptr, "offset", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4260 layout->prop(op->ptr, "faces", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4261 }
4262}
4263
4265{
4266 PropertyRNA *prop;
4267
4268 /* identifiers */
4269 ot->name = "Convert To";
4270 ot->description = "Convert selected objects to another type";
4271 ot->idname = "OBJECT_OT_convert";
4272
4273 /* API callbacks. */
4274 ot->invoke = WM_menu_invoke;
4275 ot->exec = object_convert_exec;
4276 ot->poll = object_convert_poll;
4277 ot->ui = object_convert_ui;
4278
4279 /* flags */
4280 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4281
4282 /* properties */
4283 ot->prop = prop = RNA_def_enum(
4284 ot->srna, "target", convert_target_items, OB_MESH, "Target", "Type of object to convert to");
4286
4287 prop = RNA_def_boolean(ot->srna,
4288 "keep_original",
4289 false,
4290 "Keep Original",
4291 "Keep original objects instead of replacing them");
4293
4295 ot->srna,
4296 "merge_customdata",
4297 true,
4298 "Merge UVs",
4299 "Merge UV coordinates that share a vertex to account for imprecision in some modifiers");
4300
4301 RNA_def_int(ot->srna, "thickness", 5, 1, 100, "Thickness", "", 1, 100);
4302 RNA_def_boolean(ot->srna, "faces", true, "Export Faces", "Export faces as filled strokes");
4304 "offset",
4305 0.01f,
4306 0.0,
4308 "Stroke Offset",
4309 "Offset strokes from fill",
4310 0.0,
4311 100.00);
4312}
4313
4315
4316/* -------------------------------------------------------------------- */
4319
4321 Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_src, Object *object_new)
4322{
4323 if ((base_src != nullptr) && (base_src->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT)) {
4324 BKE_collection_object_add_from(bmain, scene, base_src->object, object_new);
4325 }
4326 else {
4327 LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
4328 BKE_collection_object_add(bmain, layer_collection->collection, object_new);
4329 }
4330}
4331
4332static void object_add_sync_local_view(Base *base_src, Base *base_new)
4333{
4334 base_new->local_view_bits = base_src->local_view_bits;
4335}
4336
4337static void object_add_sync_rigid_body(Main *bmain, Object *object_src, Object *object_new)
4338{
4339 /* 1) duplis should end up in same collection as the original
4340 * 2) Rigid Body sim participants MUST always be part of a collection...
4341 */
4342 /* XXX: is 2) really a good measure here? */
4343 if (object_src->rigidbody_object || object_src->rigidbody_constraint) {
4344 LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
4345 if (BKE_collection_has_object(collection, object_src)) {
4346 BKE_collection_object_add(bmain, collection, object_new);
4347 }
4348 }
4349 }
4350}
4351
4358 Object *ob,
4359 const eDupli_ID_Flags dupflag,
4360 const eLibIDDuplicateFlags duplicate_options,
4361 Object **r_ob_new)
4362{
4363 if (ob->mode & OB_MODE_POSE) {
4364 return;
4365 }
4366
4367 Object *obn = BKE_object_duplicate(bmain, ob, dupflag, duplicate_options);
4368 if (r_ob_new) {
4369 *r_ob_new = obn;
4370 }
4372}
4373
4375 Scene *scene,
4376 ViewLayer *view_layer,
4377 Object *ob,
4378 const eDupli_ID_Flags dupflag,
4379 const eLibIDDuplicateFlags duplicate_options,
4380 Object **r_ob_new)
4381{
4382 Object *object_new = nullptr;
4383 object_add_duplicate_internal(bmain, ob, dupflag, duplicate_options, &object_new);
4384 if (r_ob_new) {
4385 *r_ob_new = object_new;
4386 }
4387 if (object_new == nullptr) {
4388 return nullptr;
4389 }
4390
4391 BKE_view_layer_synced_ensure(scene, view_layer);
4392 Base *base_src = BKE_view_layer_base_find(view_layer, ob);
4393 object_add_sync_base_collection(bmain, scene, view_layer, base_src, object_new);
4394 BKE_view_layer_synced_ensure(scene, view_layer);
4395 Base *base_new = BKE_view_layer_base_find(view_layer, object_new);
4396 if (base_src && base_new) {
4397 object_add_sync_local_view(base_src, base_new);
4398 }
4399 object_add_sync_rigid_body(bmain, ob, object_new);
4400 return base_new;
4401}
4402
4404 Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, const eDupli_ID_Flags dupflag)
4405{
4406 Base *basen;
4407 Object *ob;
4408
4409 basen = object_add_duplicate_internal(bmain,
4410 scene,
4411 view_layer,
4412 base->object,
4413 dupflag,
4416 nullptr);
4417 if (basen == nullptr) {
4418 return nullptr;
4419 }
4420
4421 ob = basen->object;
4422
4423 /* Link own references to the newly duplicated data #26816.
4424 * Note that this function can be called from edit-mode code, in which case we may have to
4425 * enforce remapping obdata (by default this is forbidden in edit mode). */
4426 const int remap_flag = BKE_object_is_in_editmode(ob) ? ID_REMAP_FORCE_OBDATA_IN_EDITMODE : 0;
4427 BKE_libblock_relink_to_newid(bmain, &ob->id, remap_flag);
4428
4429 /* Correct but the caller must do this. */
4430 // DAG_relations_tag_update(bmain);
4431
4432 if (ob->data != nullptr) {
4434 }
4435
4437
4438 return basen;
4439}
4440
4441/* contextual operator dupli */
4443{
4444 Main *bmain = CTX_data_main(C);
4445 Scene *scene = CTX_data_scene(C);
4446 ViewLayer *view_layer = CTX_data_view_layer(C);
4447 const bool linked = RNA_boolean_get(op->ptr, "linked");
4448 const eDupli_ID_Flags dupflag = (linked) ? (eDupli_ID_Flags)0 : (eDupli_ID_Flags)U.dupflag;
4449
4450 /* We need to handle that here ourselves, because we may duplicate several objects, in which case
4451 * we also want to remap pointers between those... */
4453
4454 /* Duplicate the selected objects, remember data needed to process
4455 * after the sync. */
4456 struct DuplicateObjectLink {
4457 Base *base_src = nullptr;
4458 Object *object_new = nullptr;
4459
4460 DuplicateObjectLink(Base *base_src) : base_src(base_src) {}
4461 };
4462
4463 Vector<DuplicateObjectLink> object_base_links;
4464 CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
4465 object_base_links.append(DuplicateObjectLink(base));
4466 }
4468
4469 bool new_objects_created = false;
4470 for (DuplicateObjectLink &link : object_base_links) {
4472 link.base_src->object,
4473 dupflag,
4475 &link.object_new);
4476 if (link.object_new) {
4477 new_objects_created = true;
4478 }
4479 }
4480
4481 if (!new_objects_created) {
4482 return OPERATOR_CANCELLED;
4483 }
4484
4485 /* Sync that could tag the view_layer out of sync. */
4486 for (DuplicateObjectLink &link : object_base_links) {
4487 /* note that this is safe to do with this context iterator,
4488 * the list is made in advance */
4489 base_select(link.base_src, BA_DESELECT);
4490 if (link.object_new) {
4491 object_add_sync_base_collection(bmain, scene, view_layer, link.base_src, link.object_new);
4492 object_add_sync_rigid_body(bmain, link.base_src->object, link.object_new);
4493 }
4494 }
4495
4496 /* Sync the view layer. Everything else should not tag the view_layer out of sync. */
4497 BKE_view_layer_synced_ensure(scene, view_layer);
4498 const Base *active_base = BKE_view_layer_active_base_get(view_layer);
4499 for (DuplicateObjectLink &link : object_base_links) {
4500 if (!link.object_new) {
4501 continue;
4502 }
4503
4504 Base *base_new = BKE_view_layer_base_find(view_layer, link.object_new);
4505 BLI_assert(base_new);
4506 base_select(base_new, BA_SELECT);
4507 if (active_base == link.base_src) {
4508 base_activate(C, base_new);
4509 }
4510
4511 if (link.object_new->data) {
4512 DEG_id_tag_update(static_cast<ID *>(link.object_new->data), 0);
4513 }
4514
4515 object_add_sync_local_view(link.base_src, base_new);
4516 }
4517
4518 /* Note that this will also clear newid pointers and tags. */
4520
4522
4525
4528
4529 return OPERATOR_FINISHED;
4530}
4531
4533{
4534 PropertyRNA *prop;
4535
4536 /* identifiers */
4537 ot->name = "Duplicate Objects";
4538 ot->description = "Duplicate selected objects";
4539 ot->idname = "OBJECT_OT_duplicate";
4540
4541 /* API callbacks. */
4542 ot->exec = duplicate_exec;
4543 ot->poll = ED_operator_objectmode;
4544
4545 /* flags */
4546 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4547
4548 /* to give to transform */
4549 prop = RNA_def_boolean(ot->srna,
4550 "linked",
4551 false,
4552 "Linked",
4553 "Duplicate object but not object data, linking to the original data");
4555
4556 prop = RNA_def_enum(ot->srna,
4557 "mode",
4560 "Mode",
4561 "");
4563}
4564
4566
4567/* -------------------------------------------------------------------- */
4572
4574{
4575 Main *bmain = CTX_data_main(C);
4576 Scene *scene = CTX_data_scene(C);
4577 ViewLayer *view_layer = CTX_data_view_layer(C);
4578 const bool linked = RNA_boolean_get(op->ptr, "linked");
4579 const eDupli_ID_Flags dupflag = (linked) ? (eDupli_ID_Flags)0 : (eDupli_ID_Flags)U.dupflag;
4580
4581 /* Find object, create fake base. */
4582
4583 Object *ob = reinterpret_cast<Object *>(
4585
4586 if (ob == nullptr) {
4587 BKE_report(op->reports, RPT_ERROR, "Object not found");
4588 return OPERATOR_CANCELLED;
4589 }
4590
4591 /* prepare dupli */
4593 bmain,
4594 scene,
4595 view_layer,
4596 ob,
4597 dupflag,
4598 /* Sub-process flag because the new-ID remapping (#BKE_libblock_relink_to_newid()) in this
4599 * function will only work if the object is already linked in the view layer, which is not
4600 * the case here. So we have to do the new-ID relinking ourselves
4601 * (#copy_object_set_idnew()).
4602 */
4604 nullptr);
4605
4606 if (basen == nullptr) {
4607 BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated");
4608 return OPERATOR_CANCELLED;
4609 }
4610
4612 /* Do immediately, as #copy_object_set_idnew() below operates on visible objects. */
4613 BKE_base_eval_flags(basen);
4614
4615 /* #object_add_duplicate_internal() doesn't deselect other objects,
4616 * unlike #object_add_common() or #BKE_view_layer_base_deselect_all(). */
4617 base_deselect_all(scene, view_layer, nullptr, SEL_DESELECT);
4618 base_select(basen, BA_SELECT);
4619 base_activate(C, basen);
4620
4622
4623 /* TODO(sergey): Only update relations for the current scene. */
4625
4631
4632 PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix");
4633 if (RNA_property_is_set(op->ptr, prop_matrix)) {
4634 Object *ob_add = basen->object;
4636 op->ptr, prop_matrix, ob_add->runtime->object_to_world.base_ptr());
4637 BKE_object_apply_mat4(ob_add, ob_add->object_to_world().ptr(), true, true);
4638
4640 }
4641 else if (CTX_wm_region_view3d(C)) {
4642 int mval[2];
4643 if (object_add_drop_xy_get(C, op, &mval)) {
4644 location_from_view(C, basen->object->loc);
4645 ED_view3d_cursor3d_position(C, mval, false, basen->object->loc);
4646 }
4647 }
4648
4649 return OPERATOR_FINISHED;
4650}
4651
4653{
4654 /* identifiers */
4655 ot->name = "Add Object";
4656 ot->description = "Add named object";
4657 ot->idname = "OBJECT_OT_add_named";
4658
4659 /* API callbacks. */
4661 ot->exec = object_add_named_exec;
4663
4664 /* flags */
4665 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4666
4667 PropertyRNA *prop;
4668 RNA_def_boolean(ot->srna,
4669 "linked",
4670 false,
4671 "Linked",
4672 "Duplicate object but not object data, linking to the original data");
4673
4675
4676 prop = RNA_def_float_matrix(
4677 ot->srna, "matrix", 4, 4, nullptr, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
4679
4681}
4682
4684
4685/* -------------------------------------------------------------------- */
4688
4693{
4694 Main *bmain = CTX_data_main(C);
4695 const Scene *scene = CTX_data_scene(C);
4696 ViewLayer *view_layer = CTX_data_view_layer(C);
4697
4698 Object *ob = reinterpret_cast<Object *>(
4700
4701 if (!ob) {
4702 BKE_view_layer_synced_ensure(scene, view_layer);
4703 ob = BKE_view_layer_active_object_get(view_layer);
4704 }
4705
4706 if (ob == nullptr) {
4707 BKE_report(op->reports, RPT_ERROR, "Object not found");
4708 return OPERATOR_CANCELLED;
4709 }
4710
4711 /* Don't transform a linked object. There's just nothing to do here in this case, so return
4712 * #OPERATOR_FINISHED. */
4713 if (!BKE_id_is_editable(bmain, &ob->id)) {
4714 return OPERATOR_FINISHED;
4715 }
4716
4717 /* Ensure the locations are updated so snap reads the evaluated active location. */
4719
4720 PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix");
4721 if (RNA_property_is_set(op->ptr, prop_matrix)) {
4724 view_layer, nullptr, &params);
4725
4726 float matrix[4][4];
4727 RNA_property_float_get_array(op->ptr, prop_matrix, &matrix[0][0]);
4728
4729 float mat_src_unit[4][4];
4730 float mat_dst_unit[4][4];
4731 float final_delta[4][4];
4732
4733 normalize_m4_m4(mat_src_unit, ob->object_to_world().ptr());
4734 normalize_m4_m4(mat_dst_unit, matrix);
4735 invert_m4(mat_src_unit);
4736 mul_m4_m4m4(final_delta, mat_dst_unit, mat_src_unit);
4737
4738 object_xform_array_m4(objects.data(), objects.size(), final_delta);
4739 }
4740 else if (CTX_wm_region_view3d(C)) {
4741 int mval[2];
4742 if (object_add_drop_xy_get(C, op, &mval)) {
4743 float cursor[3];
4744 location_from_view(C, cursor);
4745 ED_view3d_cursor3d_position(C, mval, false, cursor);
4746
4747 /* Use the active objects location since this is the ID which the user selected to drop.
4748 *
4749 * This transforms all selected objects, so that dropping a single object which links in
4750 * other objects will have their relative transformation preserved.
4751 * For example a child/parent relationship or other objects used with a boolean modifier.
4752 *
4753 * The caller is responsible for ensuring the selection state gives useful results.
4754 * Link/append does this using #FILE_AUTOSELECT. */
4756 }
4757 }
4758
4759 return OPERATOR_FINISHED;
4760}
4761
4763{
4764 /* identifiers */
4765 ot->name = "Place Object Under Mouse";
4766 ot->description = "Snap selected item(s) to the mouse location";
4767 ot->idname = "OBJECT_OT_transform_to_mouse";
4768
4769 /* API callbacks. */
4773
4774 /* flags */
4775 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4776
4777 PropertyRNA *prop;
4778 prop = RNA_def_string(
4779 ot->srna,
4780 "name",
4781 nullptr,
4782 MAX_ID_NAME - 2,
4783 "Name",
4784 "Object name to place (uses the active object when this and 'session_uid' are unset)");
4786 prop = RNA_def_int(ot->srna,
4787 "session_uid",
4788 0,
4789 INT32_MIN,
4790 INT32_MAX,
4791 "Session UUID",
4792 "Session UUID of the object to place (uses the active object when this and "
4793 "'name' are unset)",
4794 INT32_MIN,
4795 INT32_MAX);
4797
4798 prop = RNA_def_float_matrix(
4799 ot->srna, "matrix", 4, 4, nullptr, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
4801
4803}
4804
4806
4807/* -------------------------------------------------------------------- */
4810
4812{
4814
4815 if (ob == nullptr || ob->data == nullptr || !ID_IS_EDITABLE(ob) || ID_IS_OVERRIDE_LIBRARY(ob) ||
4817 {
4818 return false;
4819 }
4820
4821 if (ELEM(ob->type,
4822 OB_MESH,
4824 OB_SURF,
4826 OB_CURVES,
4829 {
4830 return true;
4831 }
4832 return false;
4833}
4834
4836{
4837 Main *bmain = CTX_data_main(C);
4839
4840 if (ob->mode & OB_MODE_EDIT) {
4841 BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode");
4842 return OPERATOR_CANCELLED;
4843 }
4845 BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data");
4846 return OPERATOR_CANCELLED;
4847 }
4849 BKE_reportf(op->reports,
4851 "Cannot edit object '%s' as it is used by override collections",
4852 ob->id.name + 2);
4853 return OPERATOR_CANCELLED;
4854 }
4855
4857 if (ob->type == OB_MESH) {
4859 }
4860 else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF)) {
4862 }
4863 else if (ob->type == OB_ARMATURE) {
4865 }
4866 else if (ob->type == OB_POINTCLOUD) {
4868 }
4869 else if (ob->type == OB_CURVES) {
4871 }
4872 else if (ob->type == OB_GREASE_PENCIL) {
4874 }
4875
4876 if (ret & OPERATOR_FINISHED) {
4877 /* Even though internally failure to invert is accounted for with a fallback,
4878 * show a warning since the result may not be what the user expects. See #80077.
4879 *
4880 * Failure to invert the matrix is typically caused by zero scaled axes
4881 * (which can be caused by constraints, even if the input scale isn't zero).
4882 *
4883 * Internally the join functions use #invert_m4_m4_safe_ortho which creates
4884 * an inevitable matrix from one that has one or more degenerate axes.
4885 *
4886 * In most cases we don't worry about special handling for non-inevitable matrices however for
4887 * joining objects there may be flat 2D objects where it's not obvious the scale is zero.
4888 * In this case, using #invert_m4_m4_safe_ortho works as well as we can expect,
4889 * joining the contents, flattening on the axis that's zero scaled.
4890 * If the zero scale is removed, the data on this axis remains un-scaled
4891 * (something that wouldn't work for #invert_m4_m4_safe). */
4892 float imat_test[4][4];
4893 if (!invert_m4_m4(imat_test, ob->object_to_world().ptr())) {
4894 BKE_report(op->reports,
4896 "Active object final transform has one or more zero scaled axes");
4897 }
4898 }
4899
4900 return ret;
4901}
4902
4904{
4905 /* identifiers */
4906 ot->name = "Join";
4907 ot->description = "Join selected objects into active object";
4908 ot->idname = "OBJECT_OT_join";
4909
4910 /* API callbacks. */
4911 ot->exec = object_join_exec;
4912 ot->poll = object_join_poll;
4913
4914 /* flags */
4915 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4916}
4917
4919
4920/* -------------------------------------------------------------------- */
4923
4925{
4927 if (!ob) {
4928 return false;
4929 }
4930 if (ob->type != OB_MESH) {
4931 return false;
4932 }
4933
4934 if (ob->mode & OB_MODE_EDIT) {
4935 CTX_wm_operator_poll_msg_set(C, "This operation is not supported in edit mode");
4936 return false;
4937 }
4939 CTX_wm_operator_poll_msg_set(C, "Cannot edit external library data");
4940 return false;
4941 }
4942 Main &bmain = *CTX_data_main(C);
4944 CTX_wm_operator_poll_msg_set(C, "Cannot edit object used by override collections");
4945 return false;
4946 }
4947 return true;
4948}
4949
4954
4956{
4957 ot->name = "Join as Shapes";
4958 ot->description =
4959 "Add the vertex positions of selected objects as shape keys or update existing shape keys "
4960 "with matching names";
4961 ot->idname = "OBJECT_OT_join_shapes";
4962
4963 ot->exec = join_shapes_exec;
4965
4966 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4967}
4968
4973
4975{
4976 ot->name = "Update from Objects";
4977 ot->description =
4978 "Update existing shape keys with the vertex positions of selected objects with matching "
4979 "names";
4980 ot->idname = "OBJECT_OT_update_shapes";
4981
4984
4985 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4986}
4987
4989
4990} // namespace blender::ed::object
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
void ANIM_armature_bonecoll_active_set(bArmature *armature, BoneCollection *bcoll)
BoneCollection * ANIM_armature_bonecoll_new(bArmature *armature, const char *name, int parent_index=-1)
Blender kernel action and pose functionality.
AnimData * BKE_animdata_ensure_id(ID *id)
Definition anim_data.cc:96
void BKE_animdata_free(ID *id, bool do_id_user)
Definition anim_data.cc:187
std::string BKE_attribute_calc_unique_name(const AttributeOwner &owner, blender::StringRef name)
Definition attribute.cc:383
Camera data-block and utility functions.
#define FOREACH_SCENE_OBJECT_END
bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, bool free_us)
bool BKE_collection_child_remove(Main *bmain, Collection *parent, Collection *child)
bool BKE_collection_has_object(Collection *collection, const Object *ob)
void BKE_collection_object_add_from(Main *bmain, Scene *scene, Object *ob_src, Object *ob_dst)
bool BKE_collection_cycle_find(Collection *new_ancestor, Collection *collection)
#define FOREACH_SCENE_OBJECT_BEGIN(scene, _instance)
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
void BKE_constraints_free(struct ListBase *list)
LayerCollection * CTX_data_layer_collection(const bContext *C)
#define CTX_DATA_BEGIN(C, Type, instance, member)
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
Main * CTX_data_main(const bContext *C)
bool CTX_data_selected_editable_bases(const bContext *C, blender::Vector< PointerRNA > *list)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
Collection * CTX_data_collection(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
#define CTX_DATA_END
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
void BKE_curve_dimension_update(Curve *cu)
Definition curve.cc:441
Low-level operations for curves that cannot be defined in the C++ header yet.
struct Curves * BKE_curves_add(struct Main *bmain, const char *name)
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
void CustomData_realloc(CustomData *data, int old_size, int new_size, eCDAllocType alloctype=CD_CONSTRUCT)
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst, const CustomData_MeshMasks *mask_src)
Definition customdata.cc:94
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
const char * CustomData_get_active_layer_name(const CustomData *data, eCustomDataType type)
const CustomData_MeshMasks CD_MASK_MESH
support for deformation groups and hooks.
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:71
display list (or rather multi purpose list) stuff.
constexpr int MAX_DUPLI_RECUR
void free_object_duplilist(ListBase *lb)
ListBase * object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob, blender::Set< const Object * > *include_objects=nullptr)
struct PartDeflect * BKE_partdeflect_new(int type)
Definition effect.cc:71
Low-level operations for grease pencil.
Material * BKE_grease_pencil_object_material_new(Main *bmain, Object *ob, const char *name, int *r_index)
GreasePencil * BKE_grease_pencil_add(Main *bmain, const char *name)
void BKE_grease_pencil_nomain_to_grease_pencil(GreasePencil *grease_pencil_src, GreasePencil *grease_pencil_dst)
GreasePencil * BKE_grease_pencil_new_nomain()
GreasePencil * BKE_grease_pencil_copy_for_eval(const GreasePencil *grease_pencil_src)
Material * BKE_grease_pencil_object_material_ensure_by_name(Main *bmain, Object *ob, const char *name, int *r_index)
LayerCollection * BKE_layer_collection_get_active(ViewLayer *view_layer)
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Base * BKE_view_layer_active_base_get(ViewLayer *view_layer)
blender::Vector< Object * > BKE_view_layer_array_selected_objects_params(ViewLayer *view_layer, const View3D *v3d, const ObjectsInViewLayerParams *params)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
LayerCollection * BKE_layer_collection_activate_parent(ViewLayer *view_layer, LayerCollection *lc)
void BKE_base_eval_flags(Base *base)
Object * BKE_view_layer_edit_object_get(const ViewLayer *view_layer)
void BKE_id_delete(Main *bmain, void *idv) ATTR_NONNULL()
void size_t BKE_id_multi_tagged_delete(Main *bmain) ATTR_NONNULL()
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2503
void BKE_id_free(Main *bmain, void *idv)
void id_us_plus(ID *id)
Definition lib_id.cc:353
void BKE_main_id_newptr_and_tag_clear(Main *bmain)
Definition lib_id.cc:1981
ID * BKE_id_copy(Main *bmain, const ID *id)
Definition lib_id.cc:772
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1495
#define IS_TAGGED(_id)
const char * BKE_id_name(const ID &id)
void id_us_min(ID *id)
Definition lib_id.cc:361
void BKE_main_id_tag_listbase(ListBase *lb, int tag, bool value)
Definition lib_id.cc:1191
eLibIDDuplicateFlags
@ LIB_ID_DUPLICATE_IS_ROOT_ID
@ LIB_ID_DUPLICATE_IS_SUBPROCESS
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1500
void BKE_main_id_tag_all(Main *mainvar, int tag, bool value)
Definition lib_id.cc:1214
bool BKE_lib_override_library_id_is_user_deletable(Main *bmain, ID *id)
bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv)
Definition lib_query.cc:628
void BKE_libblock_relink_to_newid(Main *bmain, ID *id, int remap_flag) ATTR_NONNULL()
Definition lib_remap.cc:919
@ ID_REMAP_FORCE_OBDATA_IN_EDITMODE
General operations, lookup, etc. for blender lights.
General operations for probes.
void BKE_lightprobe_type_set(struct LightProbe *probe, short lightprobe_type)
Definition lightprobe.cc:82
#define FOREACH_MAIN_ID_END
Definition BKE_main.hh:563
#define FOREACH_MAIN_ID_BEGIN(_bmain, _id)
Definition BKE_main.hh:557
General operations, lookup, etc. for materials.
short * BKE_id_material_len_p(ID *id)
Material *** BKE_id_material_array_p(ID *id)
void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, const ID *data_eval)
void BKE_object_materials_sync_length(Main *bmain, Object *ob, ID *id)
void BKE_object_material_resize(Main *bmain, Object *ob, short totcol, bool do_id_user)
Material * BKE_object_material_get(Object *ob, short act)
bool BKE_mball_is_basis(const Object *ob)
Definition mball.cc:260
Object * BKE_mball_basis_find(Scene *scene, Object *ob)
Definition mball.cc:424
void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
void BKE_pointcloud_to_mesh(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
void BKE_mesh_merge_customdata_for_apply_modifier(Mesh *mesh)
Mesh * BKE_mesh_copy_for_eval(const Mesh &source)
Mesh * BKE_mesh_new_from_object_to_bmain(Main *bmain, Depsgraph *depsgraph, Object *object, bool preserve_all_data_layers)
void BKE_modifiers_persistent_uid_init(const Object &object, ModifierData &md)
void BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md)
ModifierData * BKE_modifier_new(int type)
bool BKE_nlatrack_add_strip(NlaTrack *nlt, NlaStrip *strip, bool is_liboverride)
void BKE_nlatrack_set_active(ListBase *tracks, NlaTrack *nlt)
NlaTrack * BKE_nlatrack_new_tail(ListBase *nla_tracks, const bool is_liboverride)
NlaStrip * BKE_nla_add_soundstrip(Main *bmain, Scene *scene, Speaker *speaker)
void BKE_nlastrip_validate_name(AnimData *adt, NlaStrip *strip)
General operations, lookup, etc. for blender objects.
void BKE_object_empty_draw_type_set(Object *ob, int value)
bool BKE_object_is_in_editmode(const Object *ob)
Object * BKE_object_add_for_data(Main *bmain, const Scene *scene, ViewLayer *view_layer, int type, const char *name, ID *data, bool do_id_user) ATTR_RETURNS_NONNULL
void BKE_object_apply_mat4(Object *ob, const float mat[4][4], bool use_compat, bool use_parent)
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
Object * BKE_object_add(Main *bmain, Scene *scene, ViewLayer *view_layer, int type, const char *name) ATTR_NONNULL(1
bool BKE_object_obdata_is_libdata(const Object *ob)
void BKE_object_free_modifiers(Object *ob, int flag)
void BKE_object_obdata_size_init(Object *ob, float size)
Object * BKE_object_duplicate(Main *bmain, Object *ob, eDupli_ID_Flags dupflag, uint duplicate_options)
void BKE_object_to_mat4(const Object *ob, float r_mat[4][4])
int BKE_object_obdata_to_type(const ID *id) ATTR_NONNULL(1)
void BKE_object_free_derived_caches(Object *ob)
General operations for point clouds.
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
void BKE_scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2618
void BKE_scene_object_base_flag_sync_from_base(Base *base)
Definition scene.cc:2870
General operations for speakers.
bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, eEditFontMode mode, ListBase *r_nubase, const char32_t **r_text, int *r_text_len, bool *r_text_free, CharTrans **r_chartransdata, float *r_font_size_eval)
@ FO_EDIT
Definition BKE_vfont.hh:77
Volume data-block.
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ATTR_FALLTHROUGH
unsigned int BLI_ghashutil_ptrhash(const void *key)
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:686
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:752
#define BLI_ghashutil_inthash(key)
Definition BLI_ghash.h:576
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
MINLINE void srgb_to_linearrgb_v4(float linear[4], const float srgb[4])
#define DEG2RADF(_deg)
#define M_PI_2
void mul_m3_v3(const float M[3][3], float r[3])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_mat3_m4_fl(float R[4][4], float f)
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void normalize_m4_m4(float rmat[4][4], const float mat[4][4]) ATTR_NONNULL()
bool invert_m3_m3(float inverse[3][3], const float mat[3][3])
void copy_m4_m3(float m1[4][4], const float m2[3][3])
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void rescale_m4(float mat[4][4], const float scale[3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void loc_eul_size_to_mat4(float R[4][4], const float loc[3], const float eul[3], const float size[3])
bool invert_m4(float mat[4][4])
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
bool invert_m3(float mat[3][3])
void unit_m4(float m[4][4])
void eul_to_mat3(float mat[3][3], const float eul[3])
void axis_angle_to_quat(float r[4], const float axis[3], float angle)
void quat_to_eul(float eul[3], const float quat[4])
void mat3_normalized_to_eul(float eul[3], const float mat[3][3])
void mul_qt_qtqt(float q[4], const float a[4], const float b[4])
void copy_qt_qt(float q[4], const float a[4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void zero_v3(float r[3])
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
#define STRNCPY_UTF8(dst, src)
unsigned int uint
unsigned short ushort
#define SET_FLAG_FROM_TEST(value, test, flag)
#define UNPACK3(a)
#define ELEM(...)
#define RPT_(msgid)
#define BLT_I18NCONTEXT_ID_ID
#define BLT_I18NCONTEXT_ID_GPENCIL
#define BLT_I18NCONTEXT_ID_LIGHT
#define BLT_I18NCONTEXT_ID_OBJECT
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define CTX_DATA_(context, msgid)
#define IFACE_(msgid)
#define DATA_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_id_type_tag(Main *bmain, short id_type)
void DEG_relations_tag_update(Main *bmain)
void DEG_graph_tag_relations_update(Depsgraph *graph)
T * DEG_get_original(T *id)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:962
@ ID_RECALC_SELECT
Definition DNA_ID.h:1009
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1026
@ ID_RECALC_EDITORS
Definition DNA_ID.h:1019
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:985
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1012
@ ID_TAG_NEW
Definition DNA_ID.h:827
@ ID_TAG_INDIRECT
Definition DNA_ID.h:756
@ ID_TAG_DOIT
Definition DNA_ID.h:944
ID_Type
@ ID_IM
@ ID_GR
@ ID_OB
Object groups, one object can be in many groups at once.
@ CU_NURBS
@ CU_PRIM_PATH
@ CU_3D
@ CU_FRONT
@ CU_PATH
@ CU_BACK
@ CURVE_TYPE_POLY
@ CD_PROP_FLOAT3
@ CD_PROP_FLOAT2
@ GP_LAYER_TREE_NODE_USE_LIGHTS
@ GREASE_PENCIL_STROKE_ORDER_3D
@ BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT
@ LA_AREA
@ LA_LOCAL
@ LA_SPOT
@ LA_SUN
@ LIGHTPROBE_TYPE_PLANE
@ LIGHTPROBE_TYPE_VOLUME
@ LIGHTPROBE_TYPE_SPHERE
@ GP_MATERIAL_STROKE_SHOW
@ GP_MATERIAL_FILL_SHOW
@ LINEART_SOURCE_SCENE
@ LINEART_SOURCE_OBJECT
@ LINEART_SOURCE_COLLECTION
@ eModifierType_GreasePencilLineart
@ OB_MODE_EDIT
@ OB_MODE_POSE
@ NUM_PFIELD_TYPES
@ PFIELD_FLUIDFLOW
@ PFIELD_HARMONIC
@ PFIELD_TURBULENCE
@ PFIELD_LENNARDJ
Object is a sort of wrapper for general info.
@ OB_DUPLI
@ OB_DUPLICOLLECTION
@ OB_SINGLE_ARROW
@ OB_EMPTY_IMAGE
@ OB_HIDE_VIEWPORT
@ GREASE_PENCIL_LINEART_SCENE
@ GP_STROKE
@ GREASE_PENCIL_LINEART_COLLECTION
@ GREASE_PENCIL_LINEART_OBJECT
@ GP_MONKEY
@ GP_EMPTY
@ OB_MODIFIER_FLAG_ADD_REST_POSITION
@ OB_SPEAKER
@ OB_LATTICE
@ OB_MBALL
@ OB_EMPTY
@ OB_SURF
@ OB_CAMERA
@ OB_FONT
@ OB_GREASE_PENCIL
@ OB_ARMATURE
@ OB_LAMP
@ OB_MESH
@ OB_POINTCLOUD
@ OB_CURVES_LEGACY
@ OB_CURVES
@ OB_LIGHTPROBE
@ OB_USE_GPENCIL_LIGHTS
@ OB_DRAW_IN_FRONT
@ OB_EMPTY_IMAGE_HIDE_BACK
@ OB_EMPTY_IMAGE_HIDE_PERSPECTIVE
@ PAROBJECT
@ OB_DONE
@ OB_EMPTY_IMAGE_DEPTH_BACK
#define BASE_SELECTED(v3d, base)
@ FILE_SORT_DEFAULT
@ FILE_SPECIAL
@ FILE_TYPE_MOVIE
@ FILE_TYPE_FOLDER
@ FILE_TYPE_IMAGE
@ FILE_DEFAULTDISPLAY
eDupli_ID_Flags
@ USER_ADD_VIEWALIGNED
@ USER_ADD_CURSORALIGNED
@ USER_ADD_EDITMODE
@ RV3D_PERSP
@ V3D_AROUND_ACTIVE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
MetaElem * ED_mball_add_primitive(bContext *C, Object *obedit, bool obedit_is_new, float mat[4][4], float dia, int type)
wmOperatorStatus ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
Definition meshtools.cc:339
wmOperatorStatus ED_mesh_shapes_join_objects_exec(bContext *C, bool ensure_keys_exist, ReportList *reports)
Definition meshtools.cc:720
#define OBJECT_ADD_SIZE_MAXF
Definition ED_object.hh:304
void ED_outliner_select_sync_from_object_tag(bContext *C)
void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
bool ED_operator_objectmode(bContext *C)
bool ED_operator_scene_editable(bContext *C)
bool ED_operator_objectmode_poll_msg(bContext *C)
@ SEL_DESELECT
bool ED_view3d_snap_selected_to_location(bContext *C, wmOperator *op, const float target_loc_global[3], int pivot_point)
float ED_view3d_grid_scale(const Scene *scene, const View3D *v3d, const char **r_grid_unit)
Object * ED_view3d_give_object_under_cursor(bContext *C, const int mval[2])
void ED_view3d_cursor3d_position(bContext *C, const int mval[2], bool use_depth, float r_cursor_co[3])
float ED_scene_grid_scale(const Scene *scene, const char **r_grid_unit)
const EnumPropertyItem * RNA_collection_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:406
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_SKIP_PRESET
Definition RNA_types.hh:446
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
@ ALERT_ICON_NONE
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
@ WM_FILESEL_RELPATH
Definition WM_api.hh:1072
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1075
@ FILE_OPENFILE
Definition WM_api.hh:1084
#define NC_GEOM
Definition WM_types.hh:390
#define ND_DRAW
Definition WM_types.hh:458
#define ND_OB_ACTIVE
Definition WM_types.hh:437
#define ND_DATA
Definition WM_types.hh:506
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_ANIMATION
Definition WM_types.hh:385
#define ND_OB_SELECT
Definition WM_types.hh:439
#define NC_SCENE
Definition WM_types.hh:375
#define NA_ADDED
Definition WM_types.hh:583
#define ND_LAYER_CONTENT
Definition WM_types.hh:450
#define ND_MODIFIER
Definition WM_types.hh:459
#define ND_PARENT
Definition WM_types.hh:464
#define ND_NLA
Definition WM_types.hh:494
#define NC_OBJECT
Definition WM_types.hh:376
EditBone * ED_armature_ebone_add_primitive(Object *obedit_arm, const float length, const bool view_aligned)
wmOperatorStatus ED_armature_join_objects_exec(bContext *C, wmOperator *op)
#define U
BPy_StructRNA * depsgraph
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static AttributeOwner from_id(ID *id)
Definition attribute.cc:43
AttributeSet attributes
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
int64_t size() const
Definition BLI_array.hh:245
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:398
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr const char * c_str() const
static VArray ForSpan(Span< T > values)
bool add(const Key &key)
int64_t index_of_or_add(const Key &key)
IndexRange index_range() const
int64_t size() const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
MutableSpan< float3 > positions_for_write()
MutableAttributeAccessor attributes_for_write()
IndexRange points_range() const
void resize(int points_num, int curves_num)
void fill_curve_types(CurveType type)
MutableSpan< int > offsets_for_write()
MutableSpan< bool > cyclic_for_write()
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
GSpanAttributeWriter lookup_or_add_for_write_only_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type)
MutableSpan< float > radii_for_write()
bke::CurvesGeometry & strokes_for_write()
float4x4 to_object_space(const Object &object) const
bool operator==(const FillColorRecord &other) const
#define SELECT
static wmOperatorStatus duplicate_exec(bContext *C, wmOperator *op)
wmOperatorStatus ED_curve_join_objects_exec(bContext *C, wmOperator *op)
Nurb * ED_curve_add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type, int newob)
#define rot(x, k)
static float normals[][3]
#define INT32_MAX
#define INT32_MIN
VecBase< float, 4 > float4
#define printf(...)
#define ID_EXTRA_USERS(id)
#define MAX_ID_NAME
#define ID_IS_EDITABLE(_id)
#define ID_REAL_USERS(id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
#define ID_NEW_SET(_id, _idn)
#define GS(a)
wmOperatorStatus ED_grease_pencil_join_objects_exec(bContext *C, wmOperator *op)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
DEG_id_tag_update_ex(cb_data->bmain, cb_data->owner_id, ID_RECALC_TAG_FOR_UNDO|ID_RECALC_SYNC_TO_EVAL)
static char faces[256]
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
constexpr float LEGACY_RADIUS_CONVERSION_FACTOR
void curves_copy_parameters(const Curves &src, Curves &dst)
Curves * curve_legacy_to_curves(const Curve &curve_legacy)
Mesh * curve_to_wire_mesh(const CurvesGeometry &curve, const bke::AttributeFilter &attribute_filter={})
bool object_has_geometry_set_instances(const Object &object)
bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int points_per_curve)
void ensure_surface_deformation_node_exists(bContext &C, Object &curves_ob)
Definition curves_add.cc:64
wmOperatorStatus join_objects_exec(bContext *C, wmOperator *op)
void create_suzanne(Main &bmain, Object &object, const float4x4 &matrix, const int frame_number)
Vector< DrawingInfo > retrieve_visible_drawings(const Scene &scene, const GreasePencil &grease_pencil, const bool do_onion_skinning)
void create_blank(Main &bmain, Object &object, const int frame_number)
void create_stroke(Main &bmain, Object &object, const float4x4 &matrix, const int frame_number)
static uint dupliobject_instancer_hash(const void *ptr)
void OBJECT_OT_metaball_add(wmOperatorType *ot)
static wmOperatorStatus collection_drop_exec(bContext *C, wmOperator *op)
static wmOperatorStatus duplicate_exec(bContext *C, wmOperator *op)
static void mesh_data_to_grease_pencil(const Mesh &mesh_eval, GreasePencil &grease_pencil, const int current_frame, const bool generate_faces, const float stroke_radius, const float offset, const Array< int > &material_remap)
static wmOperatorStatus object_convert_exec(bContext *C, wmOperator *op)
void add_unit_props_radius(wmOperatorType *ot)
static Object * convert_grease_pencil(Base &base, const ObjectType target, ObjectConversionInfo &info, Base **r_new_base)
static void object_data_convert_curve_to_mesh(Main *bmain, Depsgraph *depsgraph, Object *ob)
static int mesh_to_grease_pencil_add_material(Main &bmain, Object &ob_grease_pencil, const StringRefNull name, const std::optional< float4 > &stroke_color, const std::optional< float4 > &fill_color)
Object * add_type(bContext *C, int type, const char *name, const float loc[3], const float rot[3], bool enter_editmode, unsigned short local_view_bits) ATTR_NONNULL(1) ATTR_RETURNS_NONNULL
void OBJECT_OT_curves_empty_hair_add(wmOperatorType *ot)
static Object * convert_mesh_to_mesh(Base &base, ObjectConversionInfo &info, Base **r_new_base)
static Base * duplibase_for_convert(Main *bmain, Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, Base *base, Object *ob)
static void object_add_duplicate_internal(Main *bmain, Object *ob, const eDupli_ID_Flags dupflag, const eLibIDDuplicateFlags duplicate_options, Object **r_ob_new)
void OBJECT_OT_text_add(wmOperatorType *ot)
static Object * convert_curves_legacy_to_mesh(Base &base, ObjectConversionInfo &info, Base **r_new_base)
static Object * convert_curves_legacy(Base &base, const ObjectType target, ObjectConversionInfo &info, Base **r_new_base)
static Object * convert_mesh_to_curves(Base &base, ObjectConversionInfo &info, Base **r_new_base)
Object * add_type_with_obdata(bContext *C, int type, const char *name, const float loc[3], const float rot[3], bool enter_editmode, ushort local_view_bits, ID *obdata)
static const char * get_light_defname(int type)
static wmOperatorStatus effector_add_exec(bContext *C, wmOperator *op)
static wmOperatorStatus object_add_text_exec(bContext *C, wmOperator *op)
static Object * convert_font(Base &base, const short target, ObjectConversionInfo &info, Base **r_new_base)
static Object * convert_mesh(Base &base, const ObjectType target, ObjectConversionInfo &info, Base **r_new_base)
void OBJECT_OT_update_shapes(wmOperatorType *ot)
static void object_add_drop_xy_props(wmOperatorType *ot)
void object_xform_array_m4(Object **objects, uint objects_len, const float matrix[4][4])
static wmOperatorStatus object_pointcloud_add_exec(bContext *C, wmOperator *op)
static Object * convert_curves_legacy_to_grease_pencil(Base &base, ObjectConversionInfo &info, Base **r_new_base)
void OBJECT_OT_delete(wmOperatorType *ot)
static bool object_convert_poll(bContext *C)
void OBJECT_OT_transform_to_mouse(wmOperatorType *ot)
static Object * convert_font_to_curves(Base &base, ObjectConversionInfo &info, Base **r_new_base)
static bool object_join_poll(bContext *C)
void OBJECT_OT_collection_instance_add(wmOperatorType *ot)
void add_unit_props_size(wmOperatorType *ot)
static const char * get_effector_defname(ePFieldType type)
static const EnumPropertyItem align_options[]
static EnumPropertyItem rna_enum_gpencil_add_stroke_depth_order_items[]
float new_primitive_matrix(bContext *C, Object *obedit, const float loc[3], const float rot[3], const float scale[3], float primmat[4][4])
static Object * convert_curves_to_grease_pencil(Base &base, ObjectConversionInfo &info, Base **r_new_base)
static VectorSet< FillColorRecord > mesh_to_grease_pencil_get_material_list(Object &ob_mesh, const Mesh &mesh, Array< int > &material_remap)
void rotation_from_view(bContext *C, float rot[3], char align_axis)
static wmOperatorStatus object_armature_add_exec(bContext *C, wmOperator *op)
void base_activate(bContext *C, Base *base)
static const EnumPropertyItem field_type_items[]
void OBJECT_OT_collection_external_asset_drop(wmOperatorType *ot)
void OBJECT_OT_data_instance_add(wmOperatorType *ot)
void OBJECT_OT_armature_add(wmOperatorType *ot)
static Object * convert_mball(Base &base, const ObjectType target, ObjectConversionInfo &info, bool &r_mball_converted, Base **r_new_base, Base **r_act_base)
void OBJECT_OT_speaker_add(wmOperatorType *ot)
static void object_add_sync_base_collection(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_src, Object *object_new)
static void object_add_sync_local_view(Base *base_src, Base *base_new)
static bool dupliobject_instancer_cmp(const void *a_, const void *b_)
void base_select(Base *base, eObjectSelect_Mode mode)
static Object * convert_font_to_curves_legacy(Base &base, ObjectConversionInfo &info, Base **r_new_base)
static bool dupliobject_cmp(const void *a_, const void *b_)
void base_free_and_unlink_no_indirect_check(Main *bmain, Scene *scene, Object *ob)
static void object_add_sync_rigid_body(Main *bmain, Object *object_src, Object *object_new)
static Object * convert_mesh_to_grease_pencil(Base &base, ObjectConversionInfo &info, Base **r_new_base)
static Object * convert_grease_pencil_to_mesh(Base &base, ObjectConversionInfo &info, Base **r_new_base)
void add_unit_props_radius_ex(wmOperatorType *ot, float default_value)
void rotation_from_quat(float rot[3], const float quat[4], char align_axis)
static bool active_shape_key_editable_poll(bContext *C)
static bool object_curves_empty_hair_add_poll(bContext *C)
static void object_convert_ui(bContext *, wmOperator *op)
static void add_grease_pencil_materials_for_conversion(Main &bmain, ID &from_id, Object &gp_object, const bool use_fill)
static void view_align_update(Main *, Scene *, PointerRNA *ptr)
static wmOperatorStatus object_delete_exec(bContext *C, wmOperator *op)
static Object * convert_grease_pencil_component_to_curves(Base &base, ObjectConversionInfo &info, Base **r_new_base)
void OBJECT_OT_pointcloud_random_add(wmOperatorType *ot)
static const EnumPropertyItem * convert_target_itemf(bContext *C, PointerRNA *, PropertyRNA *, bool *r_free)
void OBJECT_OT_lightprobe_add(wmOperatorType *ot)
static const char * get_lightprobe_defname(int type)
void OBJECT_OT_join_shapes(wmOperatorType *ot)
void OBJECT_OT_grease_pencil_add(wmOperatorType *ot)
static wmOperatorStatus object_curves_empty_hair_add_exec(bContext *C, wmOperator *op)
void OBJECT_OT_convert(wmOperatorType *ot)
bool parent_set(ReportList *reports, const bContext *C, Scene *scene, Object *const ob, Object *const par, int partype, bool xmirror, bool keep_transform, const int vert_par[3])
bool editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag)
static wmOperatorStatus object_empty_add_exec(bContext *C, wmOperator *op)
static wmOperatorStatus object_curves_random_add_exec(bContext *C, wmOperator *op)
static wmOperatorStatus object_transform_to_mouse_exec(bContext *C, wmOperator *op)
static void copy_object_set_idnew(bContext *C)
static wmOperatorStatus object_light_add_exec(bContext *C, wmOperator *op)
static Object * convert_mesh_to_curves_legacy(Base &base, ObjectConversionInfo &info, Base **r_new_base)
static wmOperatorStatus object_join_exec(bContext *C, wmOperator *op)
void OBJECT_OT_effector_add(wmOperatorType *ot)
void OBJECT_OT_add_named(wmOperatorType *ot)
static wmOperatorStatus object_instance_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static Object * convert_mesh_to_pointcloud(Base &base, ObjectConversionInfo &info, Base **r_new_base)
Base * add_duplicate(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, eDupli_ID_Flags dupflag)
void OBJECT_OT_light_add(wmOperatorType *ot)
static wmOperatorStatus object_add_exec(bContext *C, wmOperator *op)
static wmOperatorStatus join_shapes_exec(bContext *C, wmOperator *op)
static EnumPropertyItem lightprobe_type_items[]
static Object * convert_pointcloud_to_mesh(Base &base, ObjectConversionInfo &info, Base **r_new_base)
static wmOperatorStatus collection_instance_add_exec(bContext *C, wmOperator *op)
static wmOperatorStatus object_metaball_add_exec(bContext *C, wmOperator *op)
static wmOperatorStatus object_grease_pencil_add_invoke(bContext *C, wmOperator *op, const wmEvent *)
void OBJECT_OT_empty_image_add(wmOperatorType *ot)
static wmOperatorStatus object_speaker_add_exec(bContext *C, wmOperator *op)
static bool object_image_add_poll(bContext *C)
static wmOperatorStatus object_camera_add_exec(bContext *C, wmOperator *op)
static Object * convert_pointcloud(Base &base, const ObjectType target, ObjectConversionInfo &info, Base **r_new_base)
static wmOperatorStatus object_duplicates_make_real_exec(bContext *C, wmOperator *op)
static Object * convert_curves_legacy_to_curves(Base &base, ObjectConversionInfo &info, Base **r_new_base)
static bool object_add_drop_xy_get(bContext *C, wmOperator *op, int(*r_mval)[2])
void OBJECT_OT_empty_add(wmOperatorType *ot)
static wmOperatorStatus object_add_named_exec(bContext *C, wmOperator *op)
void base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
static const EnumPropertyItem convert_target_items[]
static Object * convert_font_to_grease_pencil(Base &base, ObjectConversionInfo &info, Base **r_new_base)
static Object * get_object_for_conversion(Base &base, ObjectConversionInfo &info, Base **r_new_base)
void OBJECT_OT_duplicates_make_real(wmOperatorType *ot)
bool base_deselect_all(const Scene *scene, ViewLayer *view_layer, View3D *v3d, int action)
void init_transform_on_add(Object *object, const float loc[3], const float rot[3])
static wmOperatorStatus object_delete_invoke(bContext *C, wmOperator *op, const wmEvent *)
void OBJECT_OT_add(wmOperatorType *ot)
void add_generic_props(wmOperatorType *ot, bool do_editmode)
static uint dupliobject_hash(const void *ptr)
static Object * convert_mball_to_mesh(Base &base, ObjectConversionInfo &info, bool &r_mball_converted, Base **r_new_base, Base **r_act_base)
void OBJECT_OT_curves_random_add(wmOperatorType *ot)
void location_from_view(bContext *C, float loc[3])
static wmOperatorStatus object_image_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus object_data_instance_add_exec(bContext *C, wmOperator *op)
static Object * convert_curves_to_mesh(Base &base, ObjectConversionInfo &info, Base **r_new_base)
static void make_object_duplilist_real(bContext *C, Depsgraph *depsgraph, Scene *scene, Base *base, const bool use_base_parent, const bool use_hierarchy)
static bool object_add_drop_xy_is_set(const wmOperator *op)
void add_mesh_props(wmOperatorType *ot)
static Object * convert_curves_component_to_curves(Base &base, ObjectConversionInfo &info, Base **r_new_base)
static Object * convert_curves(Base &base, const ObjectType target, ObjectConversionInfo &info, Base **r_new_base)
static wmOperatorStatus object_image_add_exec(bContext *C, wmOperator *op)
static Object * convert_font_to_mesh(Base &base, ObjectConversionInfo &info, Base **r_new_base)
void OBJECT_OT_duplicate(wmOperatorType *ot)
void OBJECT_OT_join(wmOperatorType *ot)
void add_generic_get_opts(bContext *C, wmOperator *op, char view_align_axis, float r_loc[3], float r_rot[3], float r_scale[3], bool *r_enter_editmode, unsigned short *r_local_view_bits, bool *r_is_view_aligned)
bool editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int flag)
void OBJECT_OT_camera_add(wmOperatorType *ot)
static wmOperatorStatus object_grease_pencil_add_exec(bContext *C, wmOperator *op)
static wmOperatorStatus lightprobe_add_exec(bContext *C, wmOperator *op)
static std::optional< CollectionAddInfo > collection_add_info_get_from_op(bContext *C, wmOperator *op)
static Object * convert_font_to_curve_legacy_generic(Object *ob, Object *newob, ObjectConversionInfo &info)
static wmOperatorStatus update_all_shape_keys_exec(bContext *C, wmOperator *op)
static wmOperatorStatus object_add_drop_xy_generic_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus join_objects_exec(bContext *C, wmOperator *op)
bke::CurvesGeometry mesh_edges_to_curves_convert(const Mesh &mesh, const IndexMask &selection, const bke::AttributeFilter &attribute_filter)
bke::GeometrySet join_geometries(Span< bke::GeometrySet > geometries, const bke::AttributeFilter &attribute_filter, const std::optional< Span< bke::GeometryComponent::Type > > &component_types_to_join=std::nullopt)
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))
Definition BLI_task.hh:93
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
uint64_t hash_string(StringRef str)
Definition BLI_hash.hh:166
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
#define hash
Definition noise_c.cc:154
#define CURVE_VFONT_CLEAR(vfont_member)
const EnumPropertyItem rna_enum_light_type_items[]
return ret
const EnumPropertyItem rna_enum_id_type_items[]
Definition rna_ID.cc:29
PropertyRNA * RNA_struct_type_find_property(StructRNA *srna, const char *identifier)
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
int RNA_int_get(PointerRNA *ptr, const char *name)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
bool RNA_property_enum_name(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **r_name)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_struct_idprops_unset(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_float_rotation(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float_distance(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float_matrix(StructOrFunctionRNA *cont_, const char *identifier, const int rows, const int columns, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
void RNA_def_property_update_runtime(PropertyRNA *prop, RNAPropertyUpdateFunc func)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_float_vector_xyz(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
void RNA_enum_items_add_value(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item, int value)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_object_empty_drawtype_items[]
const EnumPropertyItem rna_enum_metaelem_type_items[]
const EnumPropertyItem rna_enum_object_gpencil_type_items[]
const EnumPropertyItem rna_enum_object_type_items[]
const EnumPropertyItem rna_enum_dummy_NULL_items[]
Definition rna_rna.cc:26
#define FLT_MAX
Definition stdcycles.h:14
ListBase nla_tracks
short flag
struct Object * object
unsigned short local_view_bits
float drawsize
EditNurb * editnurb
ListBase nurb
short ob_type
CurvesGeometry geometry
struct Object * surface
char * surface_uv_map
int persistent_id[MAX_DUPLI_RECUR]
ListBase nurbs
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
void * next
Definition DNA_ID.h:407
char name[66]
Definition DNA_ID.h:415
struct Collection * collection
float energy
short type
void * first
ListBase scenes
Definition BKE_main.hh:245
ListBase collections
Definition BKE_main.hh:267
ListBase objects
Definition BKE_main.hh:247
struct MaterialGPencilStyle * gp_style
int edges_num
CustomData corner_data
CustomData vert_data
struct Key * key
char name[64]
const NodeType * type
Definition graph/node.h:178
short transflag
ListBase constraints
struct Collection * instance_collection
short base_flag
ObjectRuntimeHandle * runtime
struct RigidBodyOb * rigidbody_object
struct Material ** mat
float loc[3]
struct PartDeflect * pd
float scale[3]
float parentinv[4][4]
char empty_drawtype
short visibility_flag
uint8_t modifier_flag
float empty_drawsize
struct AnimData * adt
char empty_image_depth
struct Object * parent
struct RigidBodyCon * rigidbody_constraint
char parsubstr[64]
char empty_image_visibility_flag
struct CustomData_MeshMasks customdata_mask
struct RenderData r
View3DCursor cursor
struct Object * camera
struct Object * camera
struct View3D * localvd
short scenelock
unsigned short local_view_uid
struct Base * basact
const c_style_mat & ptr() const
static GeometrySet from_curves(Curves *curves, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const Curves * get_curves() const
int ymin
int xmin
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
int xy[2]
Definition WM_types.hh:758
int mval[2]
Definition WM_types.hh:760
wmOperatorStatus(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1046
struct ReportList * reports
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
i
Definition text_draw.cc:230
const EnumPropertyItem rna_enum_transform_mode_type_items[]
void WM_event_add_fileselect(bContext *C, wmOperator *op)
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4226
wmOperatorType * ot
Definition wm_files.cc:4225
void WM_operator_properties_confirm_or_exec(wmOperatorType *ot)
bool WM_operator_properties_id_lookup_is_set(PointerRNA *ptr)
ID * WM_operator_properties_id_lookup_from_name_or_session_uid(Main *bmain, PointerRNA *ptr, const ID_Type type)
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)
void WM_operator_properties_id_lookup(wmOperatorType *ot, const bool add_name_prop)
wmOperatorStatus WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
void WM_operator_view3d_unit_defaults(bContext *C, wmOperator *op)
wmOperatorStatus WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)
wmOperatorStatus WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *)
ID * WM_operator_drop_load_path(bContext *C, wmOperator *op, const short idcode)
Scene * WM_window_get_active_scene(const wmWindow *win)