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 grease_pencil.vertex_group_active_index = mesh_copied->vertex_group_active_index;
3276
3277 curves.radius_for_write().fill(stroke_radius);
3278
3279 drawing_line->strokes_for_write() = std::move(curves);
3280 drawing_line->tag_topology_changed();
3281
3282 BKE_id_free(nullptr, mesh_copied);
3283}
3284
3287 Base **r_new_base)
3288{
3289 Object *ob = base.object;
3290 ob->flag |= OB_DONE;
3291 Object *newob = get_object_for_conversion(base, info, r_new_base);
3292
3293 const bool generate_faces = RNA_boolean_get(info.op_props, "faces");
3294 const int thickness = RNA_int_get(info.op_props, "thickness");
3295 const float offset = RNA_float_get(info.op_props, "offset");
3296
3297 /* To be compatible with the thickness value of legacy Grease Pencil. */
3298 const float stroke_radius = float(thickness) / 2 *
3300
3301 Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
3302 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
3303
3304 VectorSet<FillColorRecord> fill_colors;
3305 Array<int> material_remap;
3306 if (generate_faces) {
3307 fill_colors = mesh_to_grease_pencil_get_material_list(*ob_eval, *mesh_eval, material_remap);
3308 }
3309
3311 BKE_object_free_modifiers(newob, 0);
3312
3313 GreasePencil *grease_pencil = BKE_grease_pencil_add(info.bmain, BKE_id_name(mesh_eval->id));
3314 newob->data = grease_pencil;
3315 newob->type = OB_GREASE_PENCIL;
3316
3317 /* Reset object material array and count since currently the generic / grease pencil material
3318 * functions still depend on this value being coherent (The same value as
3319 * `GreasePencil::material_array_num`).
3320 */
3321 BKE_object_material_resize(info.bmain, newob, 0, true);
3322
3324 *info.bmain, *newob, DATA_("Stroke"), float4(0.0f, 0.0f, 0.0f, 1.0f), {});
3325
3326 if (generate_faces) {
3327 for (const int fill_i : fill_colors.index_range()) {
3328 const FillColorRecord &record = fill_colors[fill_i];
3329 mesh_to_grease_pencil_add_material(*info.bmain, *newob, record.name, {}, record.color);
3330 }
3331 }
3332
3333 mesh_data_to_grease_pencil(*mesh_eval,
3334 *grease_pencil,
3335 info.scene->r.cfra,
3336 generate_faces,
3337 stroke_radius,
3338 offset,
3339 material_remap);
3340
3341 return newob;
3342}
3343
3345 const ObjectType target,
3347 Base **r_new_base)
3348{
3349 switch (target) {
3350 case OB_CURVES_LEGACY:
3351 return convert_mesh_to_curves_legacy(base, info, r_new_base);
3352 case OB_CURVES:
3353 return convert_mesh_to_curves(base, info, r_new_base);
3354 case OB_POINTCLOUD:
3355 return convert_mesh_to_pointcloud(base, info, r_new_base);
3356 case OB_MESH:
3357 return convert_mesh_to_mesh(base, info, r_new_base);
3358 case OB_GREASE_PENCIL:
3359 return convert_mesh_to_grease_pencil(base, info, r_new_base);
3360 default:
3361 /* Current logic does convert mesh to mesh for any other target types. This would change
3362 * after other types of conversion are designed and implemented. */
3363 return convert_mesh_to_mesh(base, info, r_new_base);
3364 }
3365}
3366
3368{
3369 Object *ob = base.object, *newob = nullptr;
3370 ob->flag |= OB_DONE;
3371
3372 Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
3374 if (ob_eval->runtime->geometry_set_eval != nullptr) {
3375 geometry = *ob_eval->runtime->geometry_set_eval;
3376 }
3377
3378 const Mesh *mesh_eval = geometry.get_mesh();
3379 const Curves *curves_eval = geometry.get_curves();
3380 Mesh *new_mesh = nullptr;
3381
3382 if (mesh_eval || curves_eval) {
3383 newob = get_object_for_conversion(base, info, r_new_base);
3384 new_mesh = BKE_id_new<Mesh>(info.bmain, newob->id.name + 2);
3385 newob->data = new_mesh;
3386 newob->type = OB_MESH;
3387 }
3388 else {
3389 BKE_reportf(info.reports,
3391 "Object '%s' has no evaluated mesh or curves data",
3392 ob->id.name + 2);
3393 return nullptr;
3394 }
3395
3396 if (mesh_eval) {
3397 BKE_mesh_nomain_to_mesh(BKE_mesh_copy_for_eval(*mesh_eval), new_mesh, newob);
3398 BKE_object_material_from_eval_data(info.bmain, newob, &mesh_eval->id);
3399 new_mesh->attributes_for_write().remove_anonymous();
3400 }
3401 else if (curves_eval) {
3402 Mesh *mesh = bke::curve_to_wire_mesh(curves_eval->geometry.wrap(),
3404 if (!mesh) {
3405 mesh = BKE_mesh_new_nomain(0, 0, 0, 0);
3406 }
3407 BKE_mesh_nomain_to_mesh(mesh, new_mesh, newob);
3408 BKE_object_material_from_eval_data(info.bmain, newob, &curves_eval->id);
3409 }
3410
3412 BKE_object_free_modifiers(newob, 0);
3413
3414 return newob;
3415}
3416
3419 Base **r_new_base)
3420{
3421 Object *ob = base.object, *newob = nullptr;
3422 ob->flag |= OB_DONE;
3423
3424 Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
3426 if (ob_eval->runtime->geometry_set_eval != nullptr) {
3427 geometry = *ob_eval->runtime->geometry_set_eval;
3428 }
3429
3430 const GreasePencil *grease_pencil_eval = geometry.get_grease_pencil();
3431 const Curves *curves_eval = geometry.get_curves();
3432 GreasePencil *new_grease_pencil = nullptr;
3433
3434 if (grease_pencil_eval || curves_eval) {
3435 newob = get_object_for_conversion(base, info, r_new_base);
3436 new_grease_pencil = BKE_id_new<GreasePencil>(info.bmain, newob->id.name + 2);
3437 newob->data = new_grease_pencil;
3438 newob->type = OB_GREASE_PENCIL;
3439 }
3440 else {
3441 BKE_reportf(info.reports,
3443 "Object '%s' has no evaluated Grease Pencil or Curves data",
3444 ob->id.name + 2);
3445 return nullptr;
3446 }
3447
3448 if (grease_pencil_eval) {
3450 new_grease_pencil);
3451 BKE_object_material_from_eval_data(info.bmain, newob, &grease_pencil_eval->id);
3452 new_grease_pencil->attributes_for_write().remove_anonymous();
3453 }
3454 else if (curves_eval) {
3455 GreasePencil *grease_pencil = BKE_grease_pencil_new_nomain();
3456 /* Insert a default layer and place the drawing on frame 1. */
3457 const std::string layer_name = "Layer";
3458 const int frame_number = 1;
3459 bke::greasepencil::Layer &layer = grease_pencil->add_layer(layer_name);
3460 bke::greasepencil::Drawing *drawing = grease_pencil->insert_frame(layer, frame_number);
3461 BLI_assert(drawing != nullptr);
3462 drawing->strokes_for_write() = curves_eval->geometry.wrap();
3463 /* Default radius (1.0 unit) is too thick for converted strokes. */
3464 drawing->radii_for_write().fill(0.01f);
3465
3466 BKE_grease_pencil_nomain_to_grease_pencil(grease_pencil, new_grease_pencil);
3467 BKE_object_material_from_eval_data(info.bmain, newob, &curves_eval->id);
3468 }
3469
3471 BKE_object_free_modifiers(newob, 0);
3472
3473 return newob;
3474}
3475
3477 const ObjectType target,
3479 Base **r_new_base)
3480{
3481 switch (target) {
3482 case OB_MESH:
3483 return convert_curves_to_mesh(base, info, r_new_base);
3484 case OB_GREASE_PENCIL:
3485 return convert_curves_to_grease_pencil(base, info, r_new_base);
3486 default:
3487 return convert_curves_component_to_curves(base, info, r_new_base);
3488 }
3489}
3490
3493 Base **r_new_base)
3494{
3495 Object *ob = base.object, *newob = nullptr;
3496 ob->flag |= OB_DONE;
3497
3498 /* Mostly same as converting to OB_CURVES, the mesh will be converted from Curves afterwards. */
3499
3500 Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
3502 if (ob_eval->runtime->geometry_set_eval != nullptr) {
3503 geometry = *ob_eval->runtime->geometry_set_eval;
3504 }
3505
3506 if (geometry.has_curves()) {
3507 newob = get_object_for_conversion(base, info, r_new_base);
3508
3509 const Curves *curves_eval = geometry.get_curves();
3510 Curves *new_curves = BKE_id_new<Curves>(info.bmain, newob->id.name + 2);
3511
3512 newob->data = new_curves;
3513 newob->type = OB_CURVES;
3514
3515 new_curves->geometry.wrap() = curves_eval->geometry.wrap();
3516 BKE_object_material_from_eval_data(info.bmain, newob, &curves_eval->id);
3517
3519 BKE_object_free_modifiers(newob, 0);
3520 }
3521 else if (geometry.has_grease_pencil()) {
3522 newob = get_object_for_conversion(base, info, r_new_base);
3523
3524 /* Do not link `new_curves` to `bmain` since it's temporary. */
3525 Curves *new_curves = BKE_id_new_nomain<Curves>(newob->id.name + 2);
3526
3527 newob->data = new_curves;
3528 newob->type = OB_CURVES;
3529
3530 if (const Curves *curves_eval = geometry.get_curves()) {
3531 new_curves->geometry.wrap() = curves_eval->geometry.wrap();
3532 BKE_object_material_from_eval_data(info.bmain, newob, &curves_eval->id);
3533 }
3534 else if (const GreasePencil *grease_pencil = geometry.get_grease_pencil()) {
3536 ed::greasepencil::retrieve_visible_drawings(*info.scene, *grease_pencil, false);
3537 Array<bke::GeometrySet> geometries(drawings.size());
3538 for (const int i : drawings.index_range()) {
3539 Curves *curves_id = BKE_id_new_nomain<Curves>(nullptr);
3540 curves_id->geometry.wrap() = drawings[i].drawing.strokes();
3541 const int layer_index = drawings[i].layer_index;
3542 const bke::greasepencil::Layer *layer = grease_pencil->layers()[layer_index];
3543 blender::float4x4 to_object = layer->to_object_space(*ob);
3544 bke::CurvesGeometry &new_curves = curves_id->geometry.wrap();
3545 MutableSpan<blender::float3> positions = new_curves.positions_for_write();
3546 for (const int point_i : new_curves.points_range()) {
3547 positions[point_i] = blender::math::transform_point(to_object, positions[point_i]);
3548 }
3549 geometries[i] = bke::GeometrySet::from_curves(curves_id);
3550 }
3551 if (geometries.size() > 0) {
3552 bke::GeometrySet joined_curves = geometry::join_geometries(geometries, {});
3553
3554 new_curves->geometry.wrap() = joined_curves.get_curves()->geometry.wrap();
3555 new_curves->geometry.wrap().tag_topology_changed();
3556 BKE_object_material_from_eval_data(info.bmain, newob, &joined_curves.get_curves()->id);
3557 }
3558 }
3559
3560 Mesh *new_mesh = BKE_id_new<Mesh>(info.bmain, newob->id.name + 2);
3561 newob->data = new_mesh;
3562 newob->type = OB_MESH;
3563
3564 Mesh *mesh = bke::curve_to_wire_mesh(new_curves->geometry.wrap(), {});
3565 if (!mesh) {
3566 mesh = BKE_mesh_new_nomain(0, 0, 0, 0);
3567 }
3568 BKE_mesh_nomain_to_mesh(mesh, new_mesh, newob);
3569 BKE_object_material_from_eval_data(info.bmain, newob, &new_curves->id);
3570
3571 /* Free `new_curves` because it is just an intermediate. */
3572 BKE_id_free(nullptr, new_curves);
3573
3575 BKE_object_free_modifiers(newob, 0);
3576 }
3577 else {
3579 info.reports, RPT_WARNING, "Object '%s' has no evaluated curves data", ob->id.name + 2);
3580 }
3581
3582 return newob;
3583}
3584
3586 const ObjectType target,
3588 Base **r_new_base)
3589{
3590 switch (target) {
3591 case OB_CURVES:
3592 return convert_grease_pencil_component_to_curves(base, info, r_new_base);
3593 case OB_MESH:
3594 return convert_grease_pencil_to_mesh(base, info, r_new_base);
3595 default:
3596 return nullptr;
3597 }
3598 return nullptr;
3599}
3600
3602 Object *newob,
3604{
3605 Curve *cu = static_cast<Curve *>(newob->data);
3606
3607 Object *ob_eval = DEG_get_evaluated(info.depsgraph, ob);
3608 BKE_vfont_to_curve_ex(ob_eval,
3609 static_cast<Curve *>(ob_eval->data),
3610 FO_EDIT,
3611 &cu->nurb,
3612 nullptr,
3613 nullptr,
3614 nullptr,
3615 nullptr,
3616 nullptr);
3617
3618 newob->type = OB_CURVES_LEGACY;
3620
3621#define CURVE_VFONT_CLEAR(vfont_member) \
3622 if (cu->vfont_member) { \
3623 id_us_min(&cu->vfont_member->id); \
3624 cu->vfont_member = nullptr; \
3625 } \
3626 ((void)0)
3627
3628 CURVE_VFONT_CLEAR(vfont);
3629 CURVE_VFONT_CLEAR(vfontb);
3630 CURVE_VFONT_CLEAR(vfonti);
3631 CURVE_VFONT_CLEAR(vfontbi);
3632
3633#undef CURVE_VFONT_CLEAR
3634
3635 if (!info.keep_original) {
3636 /* other users */
3637 Object *ob1 = nullptr;
3638 if (ID_REAL_USERS(&cu->id) > 1) {
3639 for (ob1 = static_cast<Object *>(info.bmain->objects.first); ob1;
3640 ob1 = static_cast<Object *>(ob1->id.next))
3641 {
3642 if (ob1->data == ob->data && ob1 != ob) {
3643 ob1->type = OB_CURVES_LEGACY;
3644 DEG_id_tag_update(&ob1->id,
3646 }
3647 }
3648 }
3649 }
3650
3651 LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
3652 nu->charidx = 0;
3653 }
3654
3655 cu->flag &= ~CU_3D;
3657
3658 return newob;
3659}
3660
3663 Base **r_new_base)
3664{
3665 Object *ob = base.object;
3666 ob->flag |= OB_DONE;
3667 Object *newob = get_object_for_conversion(base, info, r_new_base);
3668
3669 return convert_font_to_curve_legacy_generic(ob, newob, info);
3670}
3671
3673{
3674 Object *ob = base.object;
3675 ob->flag |= OB_DONE;
3676 Object *newob = get_object_for_conversion(base, info, r_new_base);
3677 Object *curve_ob = convert_font_to_curve_legacy_generic(ob, newob, info);
3678 BLI_assert(curve_ob->type == OB_CURVES_LEGACY);
3679
3680 Curve *legacy_curve_id = static_cast<Curve *>(curve_ob->data);
3681 Curves *curves_nomain = bke::curve_legacy_to_curves(*legacy_curve_id);
3682
3683 Curves *curves_id = BKE_curves_add(info.bmain, BKE_id_name(legacy_curve_id->id));
3684 curves_id->geometry.wrap() = curves_nomain->geometry.wrap();
3685
3686 blender::bke::curves_copy_parameters(*curves_nomain, *curves_id);
3687
3688 curve_ob->data = curves_id;
3689 curve_ob->type = OB_CURVES;
3690
3691 BKE_id_free(nullptr, curves_nomain);
3692
3693 return curve_ob;
3694}
3695
3696/* Currently neither Grease Pencil nor legacy curves supports per-stroke/curve fill attribute, thus
3697 * the #fill argument applies on all strokes that are converted. */
3699 ID &from_id,
3700 Object &gp_object,
3701 const bool use_fill)
3702{
3703 short *len_p = BKE_id_material_len_p(&from_id);
3704 if (!len_p || *len_p == 0) {
3705 return;
3706 }
3707 Material ***materials = BKE_id_material_array_p(&from_id);
3708 if (!materials || !(*materials)) {
3709 return;
3710 }
3711 for (short i = 0; i < *len_p; i++) {
3712 const Material *orig_material = (*materials)[i];
3713 const char *name = orig_material ? BKE_id_name(orig_material->id) : IFACE_("Empty Material");
3714
3716 &bmain, &gp_object, name, nullptr);
3717
3718 /* If the original object has this material slot but didn't assign any material, then we don't
3719 * have anything to copy color information from. In those cases we still added an empty
3720 * material to keep the material index matching. */
3721 if (!orig_material) {
3722 continue;
3723 }
3724
3725 copy_v4_v4(gp_material->gp_style->fill_rgba, &orig_material->r);
3726
3727 SET_FLAG_FROM_TEST(gp_material->gp_style->flag, !use_fill, GP_MATERIAL_STROKE_SHOW);
3728 SET_FLAG_FROM_TEST(gp_material->gp_style->flag, use_fill, GP_MATERIAL_FILL_SHOW);
3729 }
3730}
3731
3734 Base **r_new_base)
3735{
3736 Object *ob = base.object;
3737 ob->flag |= OB_DONE;
3738 Object *newob = get_object_for_conversion(base, info, r_new_base);
3739 Object *curve_ob = convert_font_to_curve_legacy_generic(ob, newob, info);
3740 BLI_assert(curve_ob->type == OB_CURVES_LEGACY);
3741
3742 Curve *legacy_curve_id = static_cast<Curve *>(curve_ob->data);
3743 Curves *curves_nomain = bke::curve_legacy_to_curves(*legacy_curve_id);
3744
3745 GreasePencil *grease_pencil = BKE_grease_pencil_add(info.bmain,
3746 BKE_id_name(legacy_curve_id->id));
3747 bke::greasepencil::Layer &layer = grease_pencil->add_layer(DATA_("Converted Layer"));
3748
3749 const int current_frame = info.scene->r.cfra;
3750
3751 bke::greasepencil::Drawing *drawing = grease_pencil->insert_frame(layer, current_frame);
3752
3753 blender::bke::CurvesGeometry &curves = curves_nomain->geometry.wrap();
3754
3755 drawing->strokes_for_write() = std::move(curves);
3756 /* Default radius (1.0 unit) is too thick for converted strokes. */
3757 drawing->radii_for_write().fill(0.01f);
3758 drawing->tag_positions_changed();
3759
3760 curve_ob->data = grease_pencil;
3761 curve_ob->type = OB_GREASE_PENCIL;
3762 curve_ob->totcol = grease_pencil->material_array_num;
3763
3764 const bool use_fill = (legacy_curve_id->flag & (CU_FRONT | CU_BACK)) != 0;
3765 add_grease_pencil_materials_for_conversion(*info.bmain, legacy_curve_id->id, *newob, use_fill);
3766
3767 /* We don't need the intermediate font/curve data ID any more. */
3768 BKE_id_delete(info.bmain, legacy_curve_id);
3769
3770 BKE_id_free(nullptr, curves_nomain);
3771
3772 return curve_ob;
3773}
3774
3775static Object *convert_font_to_mesh(Base &base, ObjectConversionInfo &info, Base **r_new_base)
3776{
3777 Object *newob = convert_font_to_curves_legacy(base, info, r_new_base);
3778
3779 /* No assumption should be made that the resulting objects is a mesh, as conversion can
3780 * fail. */
3782
3783 /* Meshes doesn't use the "curve cache". */
3785
3786 return newob;
3787}
3788
3790 const short target,
3792 Base **r_new_base)
3793{
3794 switch (target) {
3795 case OB_MESH:
3796 return convert_font_to_mesh(base, info, r_new_base);
3797 case OB_CURVES_LEGACY:
3798 return convert_font_to_curves_legacy(base, info, r_new_base);
3799 case OB_CURVES:
3800 return convert_font_to_curves(base, info, r_new_base);
3801 case OB_GREASE_PENCIL:
3802 return convert_font_to_grease_pencil(base, info, r_new_base);
3803 default:
3804 return nullptr;
3805 }
3806 return nullptr;
3807}
3808
3811 Base **r_new_base)
3812{
3813 Object *ob = base.object;
3814 ob->flag |= OB_DONE;
3815 Object *newob = get_object_for_conversion(base, info, r_new_base);
3816
3817 /* No assumption should be made that the resulting objects is a mesh, as conversion can
3818 * fail. */
3820
3821 /* Meshes doesn't use the "curve cache". */
3823
3824 return newob;
3825}
3826
3829 Base **r_new_base)
3830{
3831 Object *newob = convert_curves_component_to_curves(base, info, r_new_base);
3832 if (newob) {
3833 return newob;
3834 }
3835 return convert_grease_pencil_component_to_curves(base, info, r_new_base);
3836}
3837
3840 Base **r_new_base)
3841{
3842 Object *ob = base.object;
3843 ob->flag |= OB_DONE;
3844 Object *newob = get_object_for_conversion(base, info, r_new_base);
3845 BLI_assert(newob->type == OB_CURVES_LEGACY);
3846
3847 Curve *legacy_curve_id = static_cast<Curve *>(newob->data);
3848 Curves *curves_nomain = bke::curve_legacy_to_curves(*legacy_curve_id);
3849
3850 GreasePencil *grease_pencil = BKE_grease_pencil_add(info.bmain,
3851 BKE_id_name(legacy_curve_id->id));
3852 bke::greasepencil::Layer &layer = grease_pencil->add_layer(DATA_("Converted Layer"));
3853
3854 const int current_frame = info.scene->r.cfra;
3855
3856 bke::greasepencil::Drawing *drawing = grease_pencil->insert_frame(layer, current_frame);
3857
3858 blender::bke::CurvesGeometry &curves = curves_nomain->geometry.wrap();
3859
3860 drawing->strokes_for_write() = std::move(curves);
3861 /* Default radius (1.0 unit) is too thick for converted strokes. */
3862 drawing->radii_for_write().fill(0.01f);
3863 drawing->tag_positions_changed();
3864
3865 newob->data = grease_pencil;
3866 newob->type = OB_GREASE_PENCIL;
3867
3868 /* Some functions like #BKE_id_material_len_p still uses Object::totcol so this value must be in
3869 * sync. */
3870 newob->totcol = grease_pencil->material_array_num;
3871
3872 const bool use_fill = (legacy_curve_id->flag & (CU_FRONT | CU_BACK)) != 0;
3873 add_grease_pencil_materials_for_conversion(*info.bmain, legacy_curve_id->id, *newob, use_fill);
3874
3875 /* For some reason this must be called, otherwise evaluated id_cow will still be the original
3876 * curves id (and that seems to only happen if "Keep Original" is enabled, and only with this
3877 * specific conversion combination), not sure why. Ref: #138793 */
3878 DEG_id_tag_update(&grease_pencil->id, ID_RECALC_GEOMETRY);
3879
3880 BKE_id_free(nullptr, curves_nomain);
3881
3882 return newob;
3883}
3884
3886 const ObjectType target,
3888 Base **r_new_base)
3889{
3890 switch (target) {
3891 case OB_MESH:
3892 return convert_curves_legacy_to_mesh(base, info, r_new_base);
3893 case OB_CURVES:
3894 return convert_curves_legacy_to_curves(base, info, r_new_base);
3895 case OB_GREASE_PENCIL:
3896 return convert_curves_legacy_to_grease_pencil(base, info, r_new_base);
3897 default:
3898 return nullptr;
3899 }
3900}
3901
3904 bool &r_mball_converted,
3905 Base **r_new_base,
3906 Base **r_act_base)
3907{
3908 Object *ob = base.object;
3909 Object *newob = nullptr;
3910 Object *baseob = nullptr;
3911
3912 base.flag &= ~BASE_SELECTED;
3914
3915 baseob = BKE_mball_basis_find(info.scene, ob);
3916
3917 if (ob != baseob) {
3918 /* If mother-ball is converting it would be marked as done later. */
3919 ob->flag |= OB_DONE;
3920 }
3921
3922 if (!(baseob->flag & OB_DONE)) {
3923 *r_new_base = duplibase_for_convert(
3924 info.bmain, info.depsgraph, info.scene, info.view_layer, &base, baseob);
3925 newob = (*r_new_base)->object;
3926
3927 MetaBall *mb = static_cast<MetaBall *>(newob->data);
3928 id_us_min(&mb->id);
3929
3930 /* Find the evaluated mesh of the basis metaball object. */
3931 Object *object_eval = DEG_get_evaluated(info.depsgraph, baseob);
3932 Mesh *mesh = BKE_mesh_new_from_object_to_bmain(info.bmain, info.depsgraph, object_eval, true);
3933
3934 id_us_plus(&mesh->id);
3935 newob->data = mesh;
3936 newob->type = OB_MESH;
3937
3938 if (info.obact && (info.obact->type == OB_MBALL)) {
3939 *r_act_base = *r_new_base;
3940 }
3941
3942 baseob->flag |= OB_DONE;
3943 r_mball_converted = true;
3944 }
3945
3946 return newob;
3947}
3948
3950 const ObjectType target,
3952 bool &r_mball_converted,
3953 Base **r_new_base,
3954 Base **r_act_base)
3955{
3956 switch (target) {
3957 case OB_MESH:
3958 return convert_mball_to_mesh(base, info, r_mball_converted, r_new_base, r_act_base);
3959 default:
3960 return nullptr;
3961 }
3962}
3963
3966 Base **r_new_base)
3967{
3968 Object *ob = base.object;
3969 ob->flag |= OB_DONE;
3970 Object *newob = get_object_for_conversion(base, info, r_new_base);
3971
3972 BKE_pointcloud_to_mesh(info.bmain, info.depsgraph, info.scene, newob);
3973
3974 if (newob->type == OB_MESH) {
3975 BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
3976 ED_rigidbody_object_remove(info.bmain, info.scene, newob);
3977 }
3978
3979 return newob;
3980}
3981
3983 const ObjectType target,
3985 Base **r_new_base)
3986{
3987 switch (target) {
3988 case OB_MESH:
3989 return convert_pointcloud_to_mesh(base, info, r_new_base);
3990 default:
3991 return nullptr;
3992 }
3993}
3994
3996{
3997 Main *bmain = CTX_data_main(C);
3999 Scene *scene = CTX_data_scene(C);
4000 ViewLayer *view_layer = CTX_data_view_layer(C);
4001
4002 const short target = RNA_enum_get(op->ptr, "target");
4003 bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
4004 const bool do_merge_customdata = RNA_boolean_get(op->ptr, "merge_customdata");
4005
4006 Vector<PointerRNA> selected_editable_bases;
4007 CTX_data_selected_editable_bases(C, &selected_editable_bases);
4008
4009 /* Too expensive to detect on poll(). */
4010 if (selected_editable_bases.is_empty()) {
4011 BKE_report(op->reports, RPT_INFO, "No editable objects to convert");
4012 return OPERATOR_CANCELLED;
4013 }
4014
4015 /* don't forget multiple users! */
4016
4017 {
4018 FOREACH_SCENE_OBJECT_BEGIN (scene, ob) {
4019 ob->flag &= ~OB_DONE;
4020
4021 /* flag data that's not been edited (only needed for !keep_original) */
4022 if (ob->data) {
4023 ((ID *)ob->data)->tag |= ID_TAG_DOIT;
4024 }
4025
4026 /* possible metaball basis is not in this scene */
4027 if (ob->type == OB_MBALL && target == OB_MESH) {
4028 if (BKE_mball_is_basis(ob) == false) {
4029 Object *ob_basis;
4030 ob_basis = BKE_mball_basis_find(scene, ob);
4031 if (ob_basis) {
4032 ob_basis->flag &= ~OB_DONE;
4033 }
4034 }
4035 }
4036 }
4038 }
4039
4041 info.bmain = bmain;
4042 info.depsgraph = depsgraph;
4043 info.scene = scene;
4044 info.view_layer = view_layer;
4045 info.obact = BKE_view_layer_active_object_get(view_layer);
4046 info.keep_original = keep_original;
4047 info.do_merge_customdata = do_merge_customdata;
4048 info.op_props = op->ptr;
4049 info.reports = op->reports;
4050
4051 Base *act_base = nullptr;
4052
4053 /* Ensure we get all meshes calculated with a sufficient data-mask,
4054 * needed since re-evaluating single modifiers causes bugs if they depend
4055 * on other objects data masks too, see: #50950. */
4056 {
4057 for (const PointerRNA &ptr : selected_editable_bases) {
4058 Base *base = static_cast<Base *>(ptr.data);
4059 Object *ob = base->object;
4060
4061 /* The way object type conversion works currently (enforcing conversion of *all* objects
4062 * using converted object-data, even some un-selected/hidden/another scene ones,
4063 * sounds totally bad to me.
4064 * However, changing this is more design than bug-fix, not to mention convoluted code below,
4065 * so that will be for later.
4066 * But at the very least, do not do that with linked IDs! */
4067 if ((!BKE_id_is_editable(bmain, &ob->id) ||
4068 (ob->data && !BKE_id_is_editable(bmain, static_cast<ID *>(ob->data)))) &&
4069 !keep_original)
4070 {
4071 keep_original = true;
4072 BKE_report(op->reports,
4073 RPT_INFO,
4074 "Converting some non-editable object/object data, enforcing 'Keep Original' "
4075 "option to True");
4076 }
4077
4079 }
4080
4081 CustomData_MeshMasks customdata_mask_prev = scene->customdata_mask;
4084 scene->customdata_mask = customdata_mask_prev;
4085 }
4086
4087 bool mball_converted = false;
4088 int incompatible_count = 0;
4089
4090 for (const PointerRNA &ptr : selected_editable_bases) {
4091 Object *newob = nullptr;
4092 Base *base = static_cast<Base *>(ptr.data), *new_base = nullptr;
4093 Object *ob = base->object;
4094
4095 if (ob->flag & OB_DONE || !IS_TAGGED(ob->data)) {
4096 if (ob->type != target) {
4097 base->flag &= ~SELECT;
4098 ob->flag &= ~SELECT;
4099 }
4100
4101 /* obdata already modified */
4102 if (!IS_TAGGED(ob->data)) {
4103 /* When 2 objects with linked data are selected, converting both
4104 * would keep modifiers on all but the converted object #26003. */
4105 if (ob->type == OB_MESH) {
4106 BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */
4107 }
4108 }
4109 }
4110 else {
4111 const ObjectType target_type = ObjectType(target);
4112 switch (ob->type) {
4113 case OB_MESH:
4114 newob = convert_mesh(*base, target_type, info, &new_base);
4115 break;
4116 case OB_CURVES:
4117 newob = convert_curves(*base, target_type, info, &new_base);
4118 break;
4119 case OB_CURVES_LEGACY:
4121 case OB_SURF:
4122 newob = convert_curves_legacy(*base, target_type, info, &new_base);
4123 break;
4124 case OB_FONT:
4125 newob = convert_font(*base, target_type, info, &new_base);
4126 break;
4127 case OB_GREASE_PENCIL:
4128 newob = convert_grease_pencil(*base, target_type, info, &new_base);
4129 break;
4130 case OB_MBALL:
4131 newob = convert_mball(*base, target_type, info, mball_converted, &new_base, &act_base);
4132 break;
4133 case OB_POINTCLOUD:
4134 newob = convert_pointcloud(*base, target_type, info, &new_base);
4135 break;
4136 default:
4137 incompatible_count++;
4138 continue;
4139 }
4140 }
4141
4142 /* Ensure new object has consistent material data with its new obdata. */
4143 if (newob) {
4144 BKE_object_materials_sync_length(bmain, newob, static_cast<ID *>(newob->data));
4145 }
4146
4147 /* tag obdata if it was been changed */
4148
4149 /* If the original object is active then make this object active */
4150 if (new_base) {
4151 if (info.obact && (info.obact == ob)) {
4152 /* Store new active base to update view layer. */
4153 act_base = new_base;
4154 }
4155 new_base = nullptr;
4156 }
4157
4158 if (!keep_original && (ob->flag & OB_DONE)) {
4159 /* NOTE: Tag transform for update because object parenting to curve with path is handled
4160 * differently from all other cases. Converting curve to mesh and mesh to curve will likely
4161 * affect the way children are evaluated.
4162 * It is not enough to tag only geometry and rely on the curve parenting relations because
4163 * this relation is lost when curve is converted to mesh. */
4165 ((ID *)ob->data)->tag &= ~ID_TAG_DOIT; /* flag not to convert this datablock again */
4166 }
4167 }
4168
4169 if (!keep_original) {
4170 if (mball_converted) {
4171 /* We need to remove non-basis MBalls first, otherwise we won't be able to detect them if
4172 * their basis happens to be removed first. */
4173 FOREACH_SCENE_OBJECT_BEGIN (scene, ob_mball) {
4174 if (ob_mball->type == OB_MBALL) {
4175 Object *ob_basis = nullptr;
4176 if (!BKE_mball_is_basis(ob_mball) &&
4177 ((ob_basis = BKE_mball_basis_find(scene, ob_mball)) && (ob_basis->flag & OB_DONE)))
4178 {
4179 base_free_and_unlink(bmain, scene, ob_mball);
4180 }
4181 }
4182 }
4184 FOREACH_SCENE_OBJECT_BEGIN (scene, ob_mball) {
4185 if (ob_mball->type == OB_MBALL) {
4186 if (ob_mball->flag & OB_DONE) {
4187 if (BKE_mball_is_basis(ob_mball)) {
4188 base_free_and_unlink(bmain, scene, ob_mball);
4189 }
4190 }
4191 }
4192 }
4194 }
4195 }
4196
4197 // XXX: editmode_enter(C, 0);
4198 // XXX: exit_editmode(C, EM_FREEDATA|); /* free data, but no undo. */
4199
4200 if (act_base) {
4201 /* active base was changed */
4202 base_activate(C, act_base);
4203 view_layer->basact = act_base;
4204 }
4205 else {
4206 BKE_view_layer_synced_ensure(scene, view_layer);
4207 if (Object *object = BKE_view_layer_active_object_get(view_layer)) {
4208 if (object->flag & OB_DONE) {
4211 }
4212 }
4213 }
4214
4215 if (incompatible_count != 0) {
4216 const char *target_type_name = "";
4217 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "target");
4218 BLI_assert(prop != nullptr);
4219 RNA_property_enum_name(C, op->ptr, prop, target, &target_type_name);
4220 if (incompatible_count == selected_editable_bases.size()) {
4221 BKE_reportf(op->reports,
4222 RPT_INFO,
4223 "None of the objects are compatible with a conversion to \"%s\"",
4224 RPT_(target_type_name));
4225 }
4226 else {
4228 op->reports,
4229 RPT_INFO,
4230 "The selection included %d object type(s) which do not support conversion to \"%s\"",
4231 incompatible_count,
4232 RPT_(target_type_name));
4233 }
4234 }
4235
4241
4242 return OPERATOR_FINISHED;
4243}
4244
4245static void object_convert_ui(bContext * /*C*/, wmOperator *op)
4246{
4247 uiLayout *layout = op->layout;
4248
4249 uiLayoutSetPropSep(layout, true);
4250
4251 layout->prop(op->ptr, "target", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4252 layout->prop(op->ptr, "keep_original", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4253
4254 const int target = RNA_enum_get(op->ptr, "target");
4255 if (target == OB_MESH) {
4256 layout->prop(op->ptr, "merge_customdata", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4257 }
4258 else if (target == OB_GREASE_PENCIL) {
4259 layout->prop(op->ptr, "thickness", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4260 layout->prop(op->ptr, "offset", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4261 layout->prop(op->ptr, "faces", UI_ITEM_NONE, std::nullopt, ICON_NONE);
4262 }
4263}
4264
4266{
4267 PropertyRNA *prop;
4268
4269 /* identifiers */
4270 ot->name = "Convert To";
4271 ot->description = "Convert selected objects to another type";
4272 ot->idname = "OBJECT_OT_convert";
4273
4274 /* API callbacks. */
4275 ot->invoke = WM_menu_invoke;
4276 ot->exec = object_convert_exec;
4277 ot->poll = object_convert_poll;
4278 ot->ui = object_convert_ui;
4279
4280 /* flags */
4281 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4282
4283 /* properties */
4284 ot->prop = prop = RNA_def_enum(
4285 ot->srna, "target", convert_target_items, OB_MESH, "Target", "Type of object to convert to");
4287
4288 prop = RNA_def_boolean(ot->srna,
4289 "keep_original",
4290 false,
4291 "Keep Original",
4292 "Keep original objects instead of replacing them");
4294
4296 ot->srna,
4297 "merge_customdata",
4298 true,
4299 "Merge UVs",
4300 "Merge UV coordinates that share a vertex to account for imprecision in some modifiers");
4301
4302 RNA_def_int(ot->srna, "thickness", 5, 1, 100, "Thickness", "", 1, 100);
4303 RNA_def_boolean(ot->srna, "faces", true, "Export Faces", "Export faces as filled strokes");
4305 "offset",
4306 0.01f,
4307 0.0,
4309 "Stroke Offset",
4310 "Offset strokes from fill",
4311 0.0,
4312 100.00);
4313}
4314
4316
4317/* -------------------------------------------------------------------- */
4320
4322 Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_src, Object *object_new)
4323{
4324 if ((base_src != nullptr) && (base_src->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT)) {
4325 BKE_collection_object_add_from(bmain, scene, base_src->object, object_new);
4326 }
4327 else {
4328 LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
4329 BKE_collection_object_add(bmain, layer_collection->collection, object_new);
4330 }
4331}
4332
4333static void object_add_sync_local_view(Base *base_src, Base *base_new)
4334{
4335 base_new->local_view_bits = base_src->local_view_bits;
4336}
4337
4338static void object_add_sync_rigid_body(Main *bmain, Object *object_src, Object *object_new)
4339{
4340 /* 1) duplis should end up in same collection as the original
4341 * 2) Rigid Body sim participants MUST always be part of a collection...
4342 */
4343 /* XXX: is 2) really a good measure here? */
4344 if (object_src->rigidbody_object || object_src->rigidbody_constraint) {
4345 LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
4346 if (BKE_collection_has_object(collection, object_src)) {
4347 BKE_collection_object_add(bmain, collection, object_new);
4348 }
4349 }
4350 }
4351}
4352
4359 Object *ob,
4360 const eDupli_ID_Flags dupflag,
4361 const eLibIDDuplicateFlags duplicate_options,
4362 Object **r_ob_new)
4363{
4364 if (ob->mode & OB_MODE_POSE) {
4365 return;
4366 }
4367
4368 Object *obn = BKE_object_duplicate(bmain, ob, dupflag, duplicate_options);
4369 if (r_ob_new) {
4370 *r_ob_new = obn;
4371 }
4373}
4374
4376 Scene *scene,
4377 ViewLayer *view_layer,
4378 Object *ob,
4379 const eDupli_ID_Flags dupflag,
4380 const eLibIDDuplicateFlags duplicate_options,
4381 Object **r_ob_new)
4382{
4383 Object *object_new = nullptr;
4384 object_add_duplicate_internal(bmain, ob, dupflag, duplicate_options, &object_new);
4385 if (r_ob_new) {
4386 *r_ob_new = object_new;
4387 }
4388 if (object_new == nullptr) {
4389 return nullptr;
4390 }
4391
4392 BKE_view_layer_synced_ensure(scene, view_layer);
4393 Base *base_src = BKE_view_layer_base_find(view_layer, ob);
4394 object_add_sync_base_collection(bmain, scene, view_layer, base_src, object_new);
4395 BKE_view_layer_synced_ensure(scene, view_layer);
4396 Base *base_new = BKE_view_layer_base_find(view_layer, object_new);
4397 if (base_src && base_new) {
4398 object_add_sync_local_view(base_src, base_new);
4399 }
4400 object_add_sync_rigid_body(bmain, ob, object_new);
4401 return base_new;
4402}
4403
4405 Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, const eDupli_ID_Flags dupflag)
4406{
4407 Base *basen;
4408 Object *ob;
4409
4410 basen = object_add_duplicate_internal(bmain,
4411 scene,
4412 view_layer,
4413 base->object,
4414 dupflag,
4417 nullptr);
4418 if (basen == nullptr) {
4419 return nullptr;
4420 }
4421
4422 ob = basen->object;
4423
4424 /* Link own references to the newly duplicated data #26816.
4425 * Note that this function can be called from edit-mode code, in which case we may have to
4426 * enforce remapping obdata (by default this is forbidden in edit mode). */
4427 const int remap_flag = BKE_object_is_in_editmode(ob) ? ID_REMAP_FORCE_OBDATA_IN_EDITMODE : 0;
4428 BKE_libblock_relink_to_newid(bmain, &ob->id, remap_flag);
4429
4430 /* Correct but the caller must do this. */
4431 // DAG_relations_tag_update(bmain);
4432
4433 if (ob->data != nullptr) {
4435 }
4436
4438
4439 return basen;
4440}
4441
4442/* contextual operator dupli */
4444{
4445 Main *bmain = CTX_data_main(C);
4446 Scene *scene = CTX_data_scene(C);
4447 ViewLayer *view_layer = CTX_data_view_layer(C);
4448 const bool linked = RNA_boolean_get(op->ptr, "linked");
4449 const eDupli_ID_Flags dupflag = (linked) ? (eDupli_ID_Flags)0 : (eDupli_ID_Flags)U.dupflag;
4450
4451 /* We need to handle that here ourselves, because we may duplicate several objects, in which case
4452 * we also want to remap pointers between those... */
4454
4455 /* Duplicate the selected objects, remember data needed to process
4456 * after the sync. */
4457 struct DuplicateObjectLink {
4458 Base *base_src = nullptr;
4459 Object *object_new = nullptr;
4460
4461 DuplicateObjectLink(Base *base_src) : base_src(base_src) {}
4462 };
4463
4464 Vector<DuplicateObjectLink> object_base_links;
4465 CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
4466 object_base_links.append(DuplicateObjectLink(base));
4467 }
4469
4470 bool new_objects_created = false;
4471 for (DuplicateObjectLink &link : object_base_links) {
4473 link.base_src->object,
4474 dupflag,
4476 &link.object_new);
4477 if (link.object_new) {
4478 new_objects_created = true;
4479 }
4480 }
4481
4482 if (!new_objects_created) {
4483 return OPERATOR_CANCELLED;
4484 }
4485
4486 /* Sync that could tag the view_layer out of sync. */
4487 for (DuplicateObjectLink &link : object_base_links) {
4488 /* note that this is safe to do with this context iterator,
4489 * the list is made in advance */
4490 base_select(link.base_src, BA_DESELECT);
4491 if (link.object_new) {
4492 object_add_sync_base_collection(bmain, scene, view_layer, link.base_src, link.object_new);
4493 object_add_sync_rigid_body(bmain, link.base_src->object, link.object_new);
4494 }
4495 }
4496
4497 /* Sync the view layer. Everything else should not tag the view_layer out of sync. */
4498 BKE_view_layer_synced_ensure(scene, view_layer);
4499 const Base *active_base = BKE_view_layer_active_base_get(view_layer);
4500 for (DuplicateObjectLink &link : object_base_links) {
4501 if (!link.object_new) {
4502 continue;
4503 }
4504
4505 Base *base_new = BKE_view_layer_base_find(view_layer, link.object_new);
4506 BLI_assert(base_new);
4507 base_select(base_new, BA_SELECT);
4508 if (active_base == link.base_src) {
4509 base_activate(C, base_new);
4510 }
4511
4512 if (link.object_new->data) {
4513 DEG_id_tag_update(static_cast<ID *>(link.object_new->data), 0);
4514 }
4515
4516 object_add_sync_local_view(link.base_src, base_new);
4517 }
4518
4519 /* Note that this will also clear newid pointers and tags. */
4521
4523
4526
4529
4530 return OPERATOR_FINISHED;
4531}
4532
4534{
4535 PropertyRNA *prop;
4536
4537 /* identifiers */
4538 ot->name = "Duplicate Objects";
4539 ot->description = "Duplicate selected objects";
4540 ot->idname = "OBJECT_OT_duplicate";
4541
4542 /* API callbacks. */
4543 ot->exec = duplicate_exec;
4544 ot->poll = ED_operator_objectmode;
4545
4546 /* flags */
4547 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4548
4549 /* to give to transform */
4550 prop = RNA_def_boolean(ot->srna,
4551 "linked",
4552 false,
4553 "Linked",
4554 "Duplicate object but not object data, linking to the original data");
4556
4557 prop = RNA_def_enum(ot->srna,
4558 "mode",
4561 "Mode",
4562 "");
4564}
4565
4567
4568/* -------------------------------------------------------------------- */
4573
4575{
4576 Main *bmain = CTX_data_main(C);
4577 Scene *scene = CTX_data_scene(C);
4578 ViewLayer *view_layer = CTX_data_view_layer(C);
4579 const bool linked = RNA_boolean_get(op->ptr, "linked");
4580 const eDupli_ID_Flags dupflag = (linked) ? (eDupli_ID_Flags)0 : (eDupli_ID_Flags)U.dupflag;
4581
4582 /* Find object, create fake base. */
4583
4584 Object *ob = reinterpret_cast<Object *>(
4586
4587 if (ob == nullptr) {
4588 BKE_report(op->reports, RPT_ERROR, "Object not found");
4589 return OPERATOR_CANCELLED;
4590 }
4591
4592 /* prepare dupli */
4594 bmain,
4595 scene,
4596 view_layer,
4597 ob,
4598 dupflag,
4599 /* Sub-process flag because the new-ID remapping (#BKE_libblock_relink_to_newid()) in this
4600 * function will only work if the object is already linked in the view layer, which is not
4601 * the case here. So we have to do the new-ID relinking ourselves
4602 * (#copy_object_set_idnew()).
4603 */
4605 nullptr);
4606
4607 if (basen == nullptr) {
4608 BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated");
4609 return OPERATOR_CANCELLED;
4610 }
4611
4613 /* Do immediately, as #copy_object_set_idnew() below operates on visible objects. */
4614 BKE_base_eval_flags(basen);
4615
4616 /* #object_add_duplicate_internal() doesn't deselect other objects,
4617 * unlike #object_add_common() or #BKE_view_layer_base_deselect_all(). */
4618 base_deselect_all(scene, view_layer, nullptr, SEL_DESELECT);
4619 base_select(basen, BA_SELECT);
4620 base_activate(C, basen);
4621
4623
4624 /* TODO(sergey): Only update relations for the current scene. */
4626
4632
4633 PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix");
4634 if (RNA_property_is_set(op->ptr, prop_matrix)) {
4635 Object *ob_add = basen->object;
4637 op->ptr, prop_matrix, ob_add->runtime->object_to_world.base_ptr());
4638 BKE_object_apply_mat4(ob_add, ob_add->object_to_world().ptr(), true, true);
4639
4641 }
4642 else if (CTX_wm_region_view3d(C)) {
4643 int mval[2];
4644 if (object_add_drop_xy_get(C, op, &mval)) {
4645 location_from_view(C, basen->object->loc);
4646 ED_view3d_cursor3d_position(C, mval, false, basen->object->loc);
4647 }
4648 }
4649
4650 return OPERATOR_FINISHED;
4651}
4652
4654{
4655 /* identifiers */
4656 ot->name = "Add Object";
4657 ot->description = "Add named object";
4658 ot->idname = "OBJECT_OT_add_named";
4659
4660 /* API callbacks. */
4662 ot->exec = object_add_named_exec;
4664
4665 /* flags */
4666 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4667
4668 PropertyRNA *prop;
4669 RNA_def_boolean(ot->srna,
4670 "linked",
4671 false,
4672 "Linked",
4673 "Duplicate object but not object data, linking to the original data");
4674
4676
4677 prop = RNA_def_float_matrix(
4678 ot->srna, "matrix", 4, 4, nullptr, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
4680
4682}
4683
4685
4686/* -------------------------------------------------------------------- */
4689
4694{
4695 Main *bmain = CTX_data_main(C);
4696 const Scene *scene = CTX_data_scene(C);
4697 ViewLayer *view_layer = CTX_data_view_layer(C);
4698
4699 Object *ob = reinterpret_cast<Object *>(
4701
4702 if (!ob) {
4703 BKE_view_layer_synced_ensure(scene, view_layer);
4704 ob = BKE_view_layer_active_object_get(view_layer);
4705 }
4706
4707 if (ob == nullptr) {
4708 BKE_report(op->reports, RPT_ERROR, "Object not found");
4709 return OPERATOR_CANCELLED;
4710 }
4711
4712 /* Don't transform a linked object. There's just nothing to do here in this case, so return
4713 * #OPERATOR_FINISHED. */
4714 if (!BKE_id_is_editable(bmain, &ob->id)) {
4715 return OPERATOR_FINISHED;
4716 }
4717
4718 /* Ensure the locations are updated so snap reads the evaluated active location. */
4720
4721 PropertyRNA *prop_matrix = RNA_struct_find_property(op->ptr, "matrix");
4722 if (RNA_property_is_set(op->ptr, prop_matrix)) {
4725 view_layer, nullptr, &params);
4726
4727 float matrix[4][4];
4728 RNA_property_float_get_array(op->ptr, prop_matrix, &matrix[0][0]);
4729
4730 float mat_src_unit[4][4];
4731 float mat_dst_unit[4][4];
4732 float final_delta[4][4];
4733
4734 normalize_m4_m4(mat_src_unit, ob->object_to_world().ptr());
4735 normalize_m4_m4(mat_dst_unit, matrix);
4736 invert_m4(mat_src_unit);
4737 mul_m4_m4m4(final_delta, mat_dst_unit, mat_src_unit);
4738
4739 object_xform_array_m4(objects.data(), objects.size(), final_delta);
4740 }
4741 else if (CTX_wm_region_view3d(C)) {
4742 int mval[2];
4743 if (object_add_drop_xy_get(C, op, &mval)) {
4744 float cursor[3];
4745 location_from_view(C, cursor);
4746 ED_view3d_cursor3d_position(C, mval, false, cursor);
4747
4748 /* Use the active objects location since this is the ID which the user selected to drop.
4749 *
4750 * This transforms all selected objects, so that dropping a single object which links in
4751 * other objects will have their relative transformation preserved.
4752 * For example a child/parent relationship or other objects used with a boolean modifier.
4753 *
4754 * The caller is responsible for ensuring the selection state gives useful results.
4755 * Link/append does this using #FILE_AUTOSELECT. */
4757 }
4758 }
4759
4760 return OPERATOR_FINISHED;
4761}
4762
4764{
4765 /* identifiers */
4766 ot->name = "Place Object Under Mouse";
4767 ot->description = "Snap selected item(s) to the mouse location";
4768 ot->idname = "OBJECT_OT_transform_to_mouse";
4769
4770 /* API callbacks. */
4774
4775 /* flags */
4776 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4777
4778 PropertyRNA *prop;
4779 prop = RNA_def_string(
4780 ot->srna,
4781 "name",
4782 nullptr,
4783 MAX_ID_NAME - 2,
4784 "Name",
4785 "Object name to place (uses the active object when this and 'session_uid' are unset)");
4787 prop = RNA_def_int(ot->srna,
4788 "session_uid",
4789 0,
4790 INT32_MIN,
4791 INT32_MAX,
4792 "Session UUID",
4793 "Session UUID of the object to place (uses the active object when this and "
4794 "'name' are unset)",
4795 INT32_MIN,
4796 INT32_MAX);
4798
4799 prop = RNA_def_float_matrix(
4800 ot->srna, "matrix", 4, 4, nullptr, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
4802
4804}
4805
4807
4808/* -------------------------------------------------------------------- */
4811
4813{
4815
4816 if (ob == nullptr || ob->data == nullptr || !ID_IS_EDITABLE(ob) || ID_IS_OVERRIDE_LIBRARY(ob) ||
4818 {
4819 return false;
4820 }
4821
4822 if (ELEM(ob->type,
4823 OB_MESH,
4825 OB_SURF,
4827 OB_CURVES,
4830 {
4831 return true;
4832 }
4833 return false;
4834}
4835
4837{
4838 Main *bmain = CTX_data_main(C);
4840
4841 if (ob->mode & OB_MODE_EDIT) {
4842 BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode");
4843 return OPERATOR_CANCELLED;
4844 }
4846 BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data");
4847 return OPERATOR_CANCELLED;
4848 }
4850 BKE_reportf(op->reports,
4852 "Cannot edit object '%s' as it is used by override collections",
4853 ob->id.name + 2);
4854 return OPERATOR_CANCELLED;
4855 }
4856
4858 if (ob->type == OB_MESH) {
4860 }
4861 else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF)) {
4863 }
4864 else if (ob->type == OB_ARMATURE) {
4866 }
4867 else if (ob->type == OB_POINTCLOUD) {
4869 }
4870 else if (ob->type == OB_CURVES) {
4872 }
4873 else if (ob->type == OB_GREASE_PENCIL) {
4875 }
4876
4877 if (ret & OPERATOR_FINISHED) {
4878 /* Even though internally failure to invert is accounted for with a fallback,
4879 * show a warning since the result may not be what the user expects. See #80077.
4880 *
4881 * Failure to invert the matrix is typically caused by zero scaled axes
4882 * (which can be caused by constraints, even if the input scale isn't zero).
4883 *
4884 * Internally the join functions use #invert_m4_m4_safe_ortho which creates
4885 * an inevitable matrix from one that has one or more degenerate axes.
4886 *
4887 * In most cases we don't worry about special handling for non-inevitable matrices however for
4888 * joining objects there may be flat 2D objects where it's not obvious the scale is zero.
4889 * In this case, using #invert_m4_m4_safe_ortho works as well as we can expect,
4890 * joining the contents, flattening on the axis that's zero scaled.
4891 * If the zero scale is removed, the data on this axis remains un-scaled
4892 * (something that wouldn't work for #invert_m4_m4_safe). */
4893 float imat_test[4][4];
4894 if (!invert_m4_m4(imat_test, ob->object_to_world().ptr())) {
4895 BKE_report(op->reports,
4897 "Active object final transform has one or more zero scaled axes");
4898 }
4899 }
4900
4901 return ret;
4902}
4903
4905{
4906 /* identifiers */
4907 ot->name = "Join";
4908 ot->description = "Join selected objects into active object";
4909 ot->idname = "OBJECT_OT_join";
4910
4911 /* API callbacks. */
4912 ot->exec = object_join_exec;
4913 ot->poll = object_join_poll;
4914
4915 /* flags */
4916 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4917}
4918
4920
4921/* -------------------------------------------------------------------- */
4924
4926{
4928 if (!ob) {
4929 return false;
4930 }
4931 if (ob->type != OB_MESH) {
4932 return false;
4933 }
4934
4935 if (ob->mode & OB_MODE_EDIT) {
4936 CTX_wm_operator_poll_msg_set(C, "This operation is not supported in edit mode");
4937 return false;
4938 }
4940 CTX_wm_operator_poll_msg_set(C, "Cannot edit external library data");
4941 return false;
4942 }
4943 Main &bmain = *CTX_data_main(C);
4945 CTX_wm_operator_poll_msg_set(C, "Cannot edit object used by override collections");
4946 return false;
4947 }
4948 return true;
4949}
4950
4955
4957{
4958 ot->name = "Join as Shapes";
4959 ot->description =
4960 "Add the vertex positions of selected objects as shape keys or update existing shape keys "
4961 "with matching names";
4962 ot->idname = "OBJECT_OT_join_shapes";
4963
4964 ot->exec = join_shapes_exec;
4966
4967 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4968}
4969
4974
4976{
4977 ot->name = "Update from Objects";
4978 ot->description =
4979 "Update existing shape keys with the vertex positions of selected objects with matching "
4980 "names";
4981 ot->idname = "OBJECT_OT_update_shapes";
4982
4985
4986 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
4987}
4988
4990
4991} // 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_EMPTY_IMAGE_DEPTH_BACK
@ OB_HIDE_VIEWPORT
@ OB_MODIFIER_FLAG_ADD_REST_POSITION
@ OB_DONE
@ 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_SINGLE_ARROW
@ OB_EMPTY_IMAGE
@ OB_EMPTY_IMAGE_HIDE_BACK
@ OB_EMPTY_IMAGE_HIDE_PERSPECTIVE
@ OB_DUPLI
@ OB_DUPLICOLLECTION
@ GREASE_PENCIL_LINEART_SCENE
@ GP_STROKE
@ GREASE_PENCIL_LINEART_COLLECTION
@ GREASE_PENCIL_LINEART_OBJECT
@ GP_MONKEY
@ GP_EMPTY
@ OB_USE_GPENCIL_LIGHTS
@ OB_DRAW_IN_FRONT
@ PAROBJECT
#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
#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
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
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:4227
wmOperatorType * ot
Definition wm_files.cc:4226
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)