Blender V5.0
transform_convert_object.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 "MEM_guardedalloc.h"
10
11#include "BLI_listbase.h"
12#include "BLI_math_matrix.h"
13#include "BLI_math_rotation.h"
14#include "BLI_math_vector.h"
15
16#include "BKE_context.hh"
17#include "BKE_duplilist.hh"
18#include "BKE_layer.hh"
19#include "BKE_lib_id.hh"
20#include "BKE_library.hh"
21#include "BKE_object.hh"
22#include "BKE_pointcache.h"
23#include "BKE_rigidbody.h"
24#include "BKE_scene.hh"
25
26#include "ANIM_action.hh"
27#include "ANIM_keyframing.hh"
28#include "ANIM_rna.hh"
29
30#include "ED_anim_api.hh"
31#include "ED_object.hh"
32
34
35#include "transform.hh"
37#include "transform_snap.hh"
38
39/* Own include. */
40#include "transform_convert.hh"
41
42namespace blender::ed::transform {
43
44/* -------------------------------------------------------------------- */
47
64
66 TransDataContainer * /*tc*/,
67 TransCustomData *custom_data)
68{
69 TransDataObject *tdo = static_cast<TransDataObject *>(custom_data->data);
70 custom_data->data = nullptr;
71
74 }
75
78 }
79 MEM_freeN(tdo);
80}
81
83
84/* -------------------------------------------------------------------- */
93
95{
96 TransDataObject *tdo = static_cast<TransDataObject *>(t->custom.type.data);
97 if (tdo->xds == nullptr) {
98 return;
99 }
100
101 Main *bmain = CTX_data_main(t->context);
103}
104
106
107/* -------------------------------------------------------------------- */
116
118{
119 TransDataObject *tdo = static_cast<TransDataObject *>(t->custom.type.data);
120 if (tdo->xcs == nullptr) {
121 return;
122 }
123
124 Main *bmain = CTX_data_main(t->context);
126}
127
129
130/* -------------------------------------------------------------------- */
136
137/* *********************** Object Transform data ******************* */
138
143{
144 Scene *scene = t->scene;
145 bool constinv;
146 bool skip_invert = false;
147
148 if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
149 float rot[3][3], scale[3];
150 float ctime = BKE_scene_ctime_get(scene);
151
152 /* Only use rigid body transform if simulation is running,
153 * avoids problems with initial setup of rigid bodies. */
155
156 /* Save original object transform. */
157 copy_v3_v3(td_ext->oloc, ob->loc);
158
159 if (ob->rotmode > 0) {
160 copy_v3_v3(td_ext->orot, ob->rot);
161 }
162 else if (ob->rotmode == ROT_MODE_AXISANGLE) {
163 td_ext->orotAngle = ob->rotAngle;
164 copy_v3_v3(td_ext->orotAxis, ob->rotAxis);
165 }
166 else {
167 copy_qt_qt(td_ext->oquat, ob->quat);
168 }
169 /* Update object's loc/rot to get current rigid body transform. */
170 mat4_to_loc_rot_size(ob->loc, rot, scale, ob->object_to_world().ptr());
171 sub_v3_v3(ob->loc, ob->dloc);
172 BKE_object_mat3_to_rot(ob, rot, false); /* `drot` is already corrected here. */
173 }
174 }
175
176 /* `axismtx` has the real orientation. */
177 transform_orientations_create_from_axis(td->axismtx, UNPACK3(ob->object_to_world().ptr()));
178 if (t->orient_type_mask & (1 << V3D_ORIENT_GIMBAL)) {
179 if (!gimbal_axis_object(ob, td_ext->axismtx_gimbal)) {
180 copy_m3_m3(td_ext->axismtx_gimbal, td->axismtx);
181 }
182 }
183
184 td->con = static_cast<bConstraint *>(ob->constraints.first);
185
186 /* HACK: temporarily disable tracking and/or constraints when getting
187 * object matrix, if tracking is on, or if constraints don't need
188 * inverse correction to stop it from screwing up space conversion
189 * matrix later. */
190 constinv = constraints_list_needinv(t, &ob->constraints);
191
192 /* Disable constraints inversion for dummy pass. */
193 if (t->mode == TFM_DUMMY) {
194 skip_invert = true;
195 }
196
197 /* NOTE: This is not really following copy-on-evaluation design and we should not
198 * be re-evaluating the evaluated object. But as the comment above mentioned
199 * this is part of a hack.
200 * More proper solution would be to make a shallow copy of the object and
201 * evaluate that, and access matrix of that evaluated copy of the object.
202 * Might be more tricky than it sounds, if some logic later on accesses the
203 * object matrix via td->ob->object_to_world().ptr(). */
204 Object *object_eval = DEG_get_evaluated(t->depsgraph, ob);
205 if (skip_invert == false && constinv == false) {
206 object_eval->transflag |= OB_NO_CONSTRAINTS; /* #BKE_object_where_is_calc checks this. */
207 /* It is possible to have transform data initialization prior to a
208 * complete dependency graph evaluated. Happens, for example, when
209 * changing transformation mode. */
210 BKE_object_tfm_copy(object_eval, ob);
211 BKE_object_where_is_calc(t->depsgraph, t->scene, object_eval);
212 object_eval->transflag &= ~OB_NO_CONSTRAINTS;
213 }
214 else {
215 BKE_object_where_is_calc(t->depsgraph, t->scene, object_eval);
216 }
217 /* Copy newly evaluated fields to the original object, similar to how
218 * active dependency graph will do it. */
219 copy_m4_m4(ob->runtime->object_to_world.ptr(), object_eval->object_to_world().ptr());
220 /* Only copy negative scale flag, this is the only flag which is modified by
221 * the BKE_object_where_is_calc(). The rest of the flags we need to keep,
222 * otherwise we might lose dupli flags (see #61787). */
224 ob->transflag |= (object_eval->transflag & OB_NEG_SCALE);
225
226 td->extra = ob;
227 td->loc = ob->loc;
228 copy_v3_v3(td->iloc, td->loc);
229
230 if (ob->rotmode > 0) {
231 td_ext->rot = ob->rot;
232 td_ext->rotAxis = nullptr;
233 td_ext->rotAngle = nullptr;
234 td_ext->quat = nullptr;
235
236 copy_v3_v3(td_ext->irot, ob->rot);
237 copy_v3_v3(td_ext->drot, ob->drot);
238 }
239 else if (ob->rotmode == ROT_MODE_AXISANGLE) {
240 td_ext->rot = nullptr;
241 td_ext->rotAxis = ob->rotAxis;
242 td_ext->rotAngle = &ob->rotAngle;
243 td_ext->quat = nullptr;
244
245 td_ext->irotAngle = ob->rotAngle;
246 copy_v3_v3(td_ext->irotAxis, ob->rotAxis);
247/* XXX, not implemented. */
248#if 0
249 td_ext->drotAngle = ob->drotAngle;
250 copy_v3_v3(td_ext->drotAxis, ob->drotAxis);
251#endif
252 }
253 else {
254 td_ext->rot = nullptr;
255 td_ext->rotAxis = nullptr;
256 td_ext->rotAngle = nullptr;
257 td_ext->quat = ob->quat;
258
259 copy_qt_qt(td_ext->iquat, ob->quat);
260 copy_qt_qt(td_ext->dquat, ob->dquat);
261 }
262 td_ext->rotOrder = ob->rotmode;
263
264 td_ext->scale = ob->scale;
265 copy_v3_v3(td_ext->iscale, ob->scale);
266 copy_v3_v3(td_ext->dscale, ob->dscale);
267
268 copy_v3_v3(td->center, ob->object_to_world().location());
269
270 copy_m4_m4(td_ext->obmat, ob->object_to_world().ptr());
271
272 /* Is there a need to set the global<->data space conversion matrices? */
273 if (ob->parent || constinv) {
274 float obmtx[3][3], totmat[3][3], obinv[3][3];
275
276 /* Get the effect of parenting, and/or certain constraints.
277 * NOTE: some Constraints, and also Tracking should never get this
278 * done, as it doesn't work well.
279 */
280 BKE_object_to_mat3(ob, obmtx);
281 copy_m3_m4(totmat, ob->object_to_world().ptr());
282
283 /* If the object scale is zero on any axis, this might result in a zero matrix.
284 * In this case, the transformation would not do anything, see: #50103. */
285 orthogonalize_m3_zero_axes(obmtx, 1.0f);
286 orthogonalize_m3_zero_axes(totmat, 1.0f);
287
288 /* Use safe invert even though the input matrices have had zero axes set to unit length,
289 * in the unlikely case of failure (float precision for eg) this uses unit matrix fallback. */
290 invert_m3_m3_safe_ortho(obinv, totmat);
291 mul_m3_m3m3(td->smtx, obmtx, obinv);
293 }
294 else {
295 /* No conversion to/from data-space. */
296 unit_m3(td->smtx);
297 unit_m3(td->mtx);
298 }
299}
300
302 const Scene *scene,
303 ViewLayer *view_layer)
304{
306 return;
307 }
308 BKE_view_layer_synced_ensure(scene, view_layer);
310 base->object->id.tag &= ~ID_TAG_DOIT;
311 }
312}
313
315{
316 /* Here we only handle object IDs. */
317 if (GS(id->name) != ID_OB) {
318 return;
319 }
320 if (component == DEG_OB_COMP_GEOMETRY) {
321 id->tag |= ID_TAG_DOIT;
322 }
323}
324
326{
327 /* Here we only handle object IDs. */
328 if (GS(id->name) != ID_OB) {
329 return;
330 }
332 return;
333 }
334 id->tag |= ID_TAG_DOIT;
335}
336
338{
340 return;
341 }
342 object->id.tag |= ID_TAG_DOIT;
343
345 t->depsgraph,
346 &object->id,
349
350 /* When we transform parents while skipping children, we only traverse the GEOMETRY-dependent
351 * components. This avoids marking children as not participating in snapping but still marks
352 * objects with modifier dependencies.
353 * Unfortunately, some transform-dependent objects that are not children may also be skipped,
354 * such as constrained ones.
355 * See #121378 for details. */
358}
359
361 const Scene *scene,
362 ViewLayer *view_layer)
363{
365 return;
366 }
367 BKE_view_layer_synced_ensure(scene, view_layer);
369 if (base->object->id.tag & ID_TAG_DOIT) {
370 base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO;
371 }
372 }
373}
374
380{
381 Main *bmain = CTX_data_main(t->context);
382 ViewLayer *view_layer = t->view_layer;
383 View3D *v3d = static_cast<View3D *>(t->view);
384 Scene *scene = t->scene;
385 Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
386 /* NOTE: if Base selected and has parent selected:
387 * base->flag_legacy = BA_WAS_SEL
388 */
389 /* Don't do it if we're not actually going to recalculate anything. */
390 if (t->mode == TFM_DUMMY) {
391 return;
392 }
393 /* Makes sure base flags and object flags are identical. */
395 /* Make sure depsgraph is here. */
397 /* Clear all flags we need. It will be used to detect dependencies. */
398 trans_object_base_deps_flag_prepare(t, scene, view_layer);
399 /* Traverse all bases and set all possible flags. */
400 BKE_view_layer_synced_ensure(scene, view_layer);
402 base->flag_legacy &= ~(BA_WAS_SEL | BA_TRANSFORM_LOCKED_IN_PLACE);
403 if (BASE_SELECTED_EDITABLE(v3d, base)) {
404 Object *ob = base->object;
405 Object *parsel = ob->parent;
406 /* If parent selected, deselect. */
407 while (parsel != nullptr) {
408 if (parsel->base_flag & BASE_SELECTED) {
409 Base *parbase = BKE_view_layer_base_find(view_layer, parsel);
410 if (parbase != nullptr) { /* In rare cases this can fail. */
411 if (BASE_SELECTED_EDITABLE(v3d, parbase)) {
412 break;
413 }
414 }
415 }
416 parsel = parsel->parent;
417 }
418 if (parsel != nullptr) {
419 /* Rotation around local centers are allowed to propagate. */
421 {
422 base->flag_legacy |= BA_TRANSFORM_CHILD;
423 }
424 else {
425 base->flag &= ~BASE_SELECTED;
426 base->flag_legacy |= BA_WAS_SEL;
427 }
428 }
430 }
431 }
432 /* Store temporary bits in base indicating that base is being modified
433 * (directly or indirectly) by transforming objects.
434 */
435 trans_object_base_deps_flag_finish(t, scene, view_layer);
436}
437
438static bool mark_children(Object *ob)
439{
440 if (ob->flag & (SELECT | BA_TRANSFORM_CHILD)) {
441 return true;
442 }
443
444 if (ob->parent) {
445 if (mark_children(ob->parent)) {
447 return true;
448 }
449 }
450
451 return false;
452}
453
455{
456 int total = 0;
457 ViewLayer *view_layer = t->view_layer;
458 View3D *v3d = static_cast<View3D *>(t->view);
459 Scene *scene = t->scene;
460 /* Clear all flags we need. It will be used to detect dependencies. */
461 trans_object_base_deps_flag_prepare(t, scene, view_layer);
462 /* Rotations around local centers are allowed to propagate, so we take all objects. */
464 /* Mark all parents. */
466 if (BASE_SELECTED_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
467 Object *parent = base->object->parent;
468 /* Flag all parents. */
469 while (parent != nullptr) {
470 parent->flag |= BA_TRANSFORM_PARENT;
471 parent = parent->parent;
472 }
473 }
474 }
475 /* Mark all children. */
477 /* All base not already selected or marked that is editable. */
478 if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
479 (base->flag & BASE_SELECTED) == 0 &&
480 (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)))
481 {
482 mark_children(base->object);
483 }
484 }
485 }
486 /* Flush changed flags to all dependencies. */
488 Object *ob = base->object;
489 /* If base is not selected, not a parent of selection or not a child of
490 * selection and it is editable and selectable.
491 */
492 if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
493 (base->flag & BASE_SELECTED) == 0 &&
494 (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)))
495 {
497 total += 1;
498 }
499 }
500 /* Store temporary bits in base indicating that base is being modified
501 * (directly or indirectly) by transforming objects.
502 */
503 trans_object_base_deps_flag_finish(t, scene, view_layer);
504 return total;
505}
506
508{
509 Scene *scene = t->scene;
510 ViewLayer *view_layer = t->view_layer;
511
512 BKE_view_layer_synced_ensure(scene, view_layer);
514 if (base->flag_legacy & BA_WAS_SEL) {
516 }
517
518 base->flag_legacy &= ~(BA_WAS_SEL | BA_SNAP_FIX_DEPS_FIASCO | BA_TEMP_TAG |
521 }
522}
523
525{
526 Main *bmain = CTX_data_main(C);
527 TransData *td = nullptr;
529 const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
530
532
534
535 /* Count. */
536 tc->data_len = CTX_DATA_COUNT(C, selected_bases);
537
538 if (!tc->data_len) {
539 /* Clear here, main transform function escapes too. */
541 return;
542 }
543
544 if (is_prop_edit) {
546 }
547
548 td = tc->data = MEM_calloc_arrayN<TransData>(tc->data_len, "TransOb");
549 tx = tc->data_ext = MEM_calloc_arrayN<TransDataExtension>(tc->data_len, "TransObExtension");
550
552 t->custom.type.data = tdo;
554
557 }
558
559 CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
560 Object *ob = base->object;
561
562 td->flag = TD_SELECTED;
563 td->protectflag = ob->protectflag;
564 tx->rotOrder = ob->rotmode;
565
566 if (base->flag & BA_TRANSFORM_CHILD) {
567 td->flag |= TD_NOCENTER;
568 td->flag |= TD_NO_LOC;
569 }
570
571 /* Select linked objects, but skip them later. */
572 if (!BKE_id_is_editable(bmain, &ob->id)) {
573 td->flag |= TD_SKIP;
574 }
575
577 ID *id = static_cast<ID *>(ob->data);
578 if (!id || id->lib) {
579 td->flag |= TD_SKIP;
580 }
581 else if (BKE_object_is_in_editmode(ob)) {
582 /* NOTE(@ideasman42): The object could have edit-mode data from another view-layer,
583 * it's such a corner-case it can be skipped for now. */
584 td->flag |= TD_SKIP;
585 }
586 }
587
589 if ((td->flag & TD_SKIP) == 0) {
591 }
592 }
593
594 ObjectToTransData(t, td, tx, ob);
595 td->val = nullptr;
596 td++;
597 tx++;
598 }
600
601 if (is_prop_edit) {
602 Scene *scene = t->scene;
603 ViewLayer *view_layer = t->view_layer;
604 View3D *v3d = static_cast<View3D *>(t->view);
605
606 BKE_view_layer_synced_ensure(scene, view_layer);
608 Object *ob = base->object;
609
610 /* If base is not selected, not a parent of selection
611 * or not a child of selection and it is editable and selectable. */
612 if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
613 (base->flag & BASE_SELECTED) == 0 && BASE_EDITABLE(v3d, base) &&
614 BASE_SELECTABLE(v3d, base))
615 {
616 td->protectflag = ob->protectflag;
617 tx->rotOrder = ob->rotmode;
618
619 ObjectToTransData(t, td, tx, ob);
620 td->val = nullptr;
621 td++;
622 tx++;
623 }
624 }
625 }
626
628 Set<Object *> objects_in_transdata;
629 td = tc->data;
630 for (int i = 0; i < tc->data_len; i++, td++) {
631 if ((td->flag & TD_SKIP) == 0) {
632 objects_in_transdata.add(static_cast<Object *>(td->extra));
633 }
634 }
635
636 Scene *scene = t->scene;
637 ViewLayer *view_layer = t->view_layer;
638 View3D *v3d = static_cast<View3D *>(t->view);
639
640 BKE_view_layer_synced_ensure(scene, view_layer);
642 Object *ob = base->object;
643
644 /* If base is not selected, not a parent of selection
645 * or not a child of selection and it is editable and selectable. */
646 if ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0 &&
647 BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base))
648 {
649
650 Object *ob_parent = ob->parent;
651 if (ob_parent != nullptr) {
652 if (!objects_in_transdata.contains(ob)) {
653 bool parent_in_transdata = false;
654 while (ob_parent != nullptr) {
655 if (objects_in_transdata.contains(ob_parent)) {
656 parent_in_transdata = true;
657 break;
658 }
659 ob_parent = ob_parent->parent;
660 }
661 if (parent_in_transdata) {
663 }
664 }
665 }
666 }
667 }
668 }
669
671
673
674#define BASE_XFORM_INDIRECT(base) \
675\
676 ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0)
677
678 Set<Object *> objects_in_transdata;
679 GHash *objects_parent_root = BLI_ghash_ptr_new_ex(__func__, tc->data_len);
680 td = tc->data;
681 for (int i = 0; i < tc->data_len; i++, td++) {
682 if ((td->flag & TD_SKIP) == 0) {
683 objects_in_transdata.add(static_cast<Object *>(td->extra));
684 }
685 }
686
687 Scene *scene = t->scene;
688 ViewLayer *view_layer = t->view_layer;
689
690 BKE_view_layer_synced_ensure(scene, view_layer);
692 Object *ob = base->object;
693 if (ob->parent != nullptr) {
694 if (ob->parent && !objects_in_transdata.contains(ob->parent) &&
695 !objects_in_transdata.contains(ob))
696 {
697 if ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0) {
698 Base *base_parent = BKE_view_layer_base_find(view_layer, ob->parent);
699 if (base_parent && !BASE_XFORM_INDIRECT(base_parent)) {
700 Object *ob_parent_recurse = ob->parent;
701 if (ob_parent_recurse != nullptr) {
702 while (ob_parent_recurse != nullptr) {
703 if (objects_in_transdata.contains(ob_parent_recurse)) {
704 break;
705 }
706 ob_parent_recurse = ob_parent_recurse->parent;
707 }
708
709 if (ob_parent_recurse) {
711 tdo->xcs, ob, ob_parent_recurse, object::XFORM_OB_SKIP_CHILD_PARENT_APPLY);
712 BLI_ghash_insert(objects_parent_root, ob, ob_parent_recurse);
713 base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE;
714 base->flag_legacy &= ~BA_SNAP_FIX_DEPS_FIASCO;
715 }
716 }
717 }
718 }
719 }
720 }
721 }
722
724 Object *ob = base->object;
725
726 if (BASE_XFORM_INDIRECT(base) || objects_in_transdata.contains(ob)) {
727 /* Pass. */
728 }
729 else if (ob->parent != nullptr) {
730 Base *base_parent = BKE_view_layer_base_find(view_layer, ob->parent);
731 if (base_parent) {
732 if (BASE_XFORM_INDIRECT(base_parent) || objects_in_transdata.contains(ob->parent)) {
735 base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE;
736 base->flag_legacy &= ~BA_SNAP_FIX_DEPS_FIASCO;
737 }
738 else {
739 Object *ob_parent_recurse = static_cast<Object *>(
740 BLI_ghash_lookup(objects_parent_root, ob->parent));
741 if (ob_parent_recurse) {
743 tdo->xcs,
744 ob,
745 ob_parent_recurse,
747 }
748 }
749 }
750 }
751 }
752 BLI_ghash_free(objects_parent_root, nullptr, nullptr);
753
754#undef BASE_XFORM_INDIRECT
755 }
756}
757
759
760/* -------------------------------------------------------------------- */
763
764/* Return if we need to update motion paths, only if they already exist,
765 * and we will insert a keyframe at the end of transform. */
767{
768 /* XXX: there's potential here for problems with unkeyed rotations/scale,
769 * but for now (until proper data-locality for baking operations),
770 * this should be a better fix for #24451 and #37755
771 */
772
773 if (animrig::autokeyframe_cfra_can_key(scene, &ob->id)) {
774 return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
775 }
776
777 return false;
778}
779
781
782/* -------------------------------------------------------------------- */
785
786/* Given the transform mode `tmode` return a Vector of RNA paths that were possibly modified during
787 * that transformation. */
789 const eTfmMode tmode,
790 Scene *scene,
791 ViewLayer *view_layer,
792 Object *ob,
793 const StringRef rotation_path,
794 const bool transforming_more_than_one_object)
795{
796 Vector<RNAPath> rna_paths;
797
798 /* Handle the cases where we always need to key location, regardless of
799 * transform mode. */
801 BKE_view_layer_synced_ensure(scene, view_layer);
802 if (ob != BKE_view_layer_active_object_get(view_layer)) {
803 rna_paths.append({"location"});
804 }
805 }
806 else if (transforming_more_than_one_object &&
808 {
809 rna_paths.append({"location"});
810 }
812 rna_paths.append({"location"});
813 }
814
815 /* Handle the transform-mode-specific cases. */
816 switch (tmode) {
817 case TFM_TRANSLATION:
818 rna_paths.append_non_duplicates({"location"});
819 break;
820
821 case TFM_ROTATION:
822 case TFM_TRACKBALL:
823 if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
824 rna_paths.append({rotation_path});
825 }
826 break;
827
828 case TFM_RESIZE:
829 if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
830 rna_paths.append({"scale"});
831 }
832 break;
833
834 default:
835 rna_paths.append_non_duplicates({"location"});
836 rna_paths.append({rotation_path});
837 rna_paths.append({"scale"});
838 }
839
840 return rna_paths;
841}
842
844 Scene *scene,
845 Object *ob,
846 const eTfmMode tmode,
847 const bool transforming_more_than_one_object)
848{
849 Vector<RNAPath> rna_paths;
850 ViewLayer *view_layer = CTX_data_view_layer(C);
852
855 tmode, scene, view_layer, ob, rotation_path, transforming_more_than_one_object);
856 }
857 else {
858 rna_paths = {{"location"}, {rotation_path}, {"scale"}};
859 }
860 animrig::autokeyframe_object(C, scene, ob, rna_paths.as_span());
861}
862
864{
865 bool motionpath_update = false;
866
867 if (t->state != TRANS_CANCEL) {
869 }
870
872 TransData *td = tc->data;
873
874 for (int i = 0; i < tc->data_len; i++, td++) {
875 Object *ob = static_cast<Object *>(td->extra);
876 if (td->flag & TD_SKIP) {
877 continue;
878 }
879
880 /* If animtimer is running, and the object already has animation data,
881 * check if the auto-record feature means that we should record 'samples'
882 * (i.e. uneditable animation values). */
883
884 /* TODO: auto-keyframe calls need some setting to specify to add samples
885 * (FPoints) instead of keyframes? */
886 if ((t->animtimer) && animrig::is_autokey_on(t->scene)) {
887 animrecord_check_state(t, &ob->id);
888 autokeyframe_object(t->context, t->scene, ob, t->mode, t->data_len_all > 1);
889 }
890
891 motionpath_update |= motionpath_need_update_object(t->scene, ob);
892
893 /* Sets recalc flags fully, instead of flushing existing ones
894 * otherwise proxies don't function correctly. */
896 }
897 }
898
899 if (motionpath_update) {
900 /* Update motion paths once for all transformed objects. */
903 }
904
907 }
908
911 }
912}
913
915
916/* -------------------------------------------------------------------- */
919
921{
923
924 Object *ob;
925 const bool canceled = (t->state == TRANS_CANCEL);
926
928 bool motionpath_update = false;
929
930 if (animrig::is_autokey_on(t->scene) && !canceled) {
932 }
933
934 for (int i = 0; i < tc->data_len; i++) {
935 TransData *td = tc->data + i;
936 TransDataExtension *td_ext = tc->data_ext + i;
937 ListBase pidlist;
938 ob = static_cast<Object *>(td->extra);
939
940 if (td->flag & TD_SKIP) {
941 continue;
942 }
943
944 /* Flag object caches as outdated. */
946 LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
947 if (pid->type != PTCACHE_TYPE_PARTICLES) {
948 /* Particles don't need reset on geometry change. */
949 pid->cache->flag |= PTCACHE_OUTDATED;
950 }
951 }
952 BLI_freelistN(&pidlist);
953
954 /* Point-cache refresh. */
957 }
958
959 /* Needed for proper updating of "quick cached" dynamics.
960 * Creates troubles for moving animated objects without
961 * auto-key though, probably needed is an animation-system override?
962 * NOTE(@jahka): Please remove if some other solution is found. */
964
965 /* Set auto-key if necessary. */
966 if (!canceled) {
967 autokeyframe_object(C, t->scene, ob, t->mode, tc->data_len > 1);
968 }
969
970 motionpath_update |= motionpath_need_update_object(t->scene, ob);
971
972 /* Restore rigid body transform. */
973 if (ob->rigidbody_object && canceled) {
974 float ctime = BKE_scene_ctime_get(t->scene);
977 ob, td_ext->oloc, td_ext->orot, td_ext->oquat, td_ext->orotAxis, td_ext->orotAngle);
978 }
979 }
980 }
981
982 if (motionpath_update) {
983 /* Update motion paths once for all transformed objects. */
984 const object::eObjectPathCalcRange range = canceled ?
988 }
989
991}
992
994
996 /*flags*/ 0,
997 /*create_trans_data*/ createTransObject,
998 /*recalc_data*/ recalcData_objects,
999 /*special_aftertrans_update*/ special_aftertrans_update__object,
1000};
1001
1002} // namespace blender::ed::transform
Functions and classes to work with Actions.
Functions to insert, delete or modify keyframes.
Helper functions for animation to interact with the RNA system.
#define CTX_DATA_BEGIN(C, Type, instance, member)
#define CTX_DATA_COUNT(C, member)
Main * CTX_data_main(const bContext *C)
#define CTX_DATA_END
ViewLayer * CTX_data_view_layer(const bContext *C)
constexpr int MAX_DUPLI_RECUR
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2523
General operations, lookup, etc. for blender objects.
void BKE_object_mat3_to_rot(Object *ob, float r_mat[3][3], bool use_compat)
bool BKE_object_is_in_editmode(const Object *ob)
void BKE_object_tfm_copy(Object *object_dst, const Object *object_src)
void BKE_object_to_mat3(const Object *ob, float r_mat[3][3])
void BKE_object_where_is_calc(Depsgraph *depsgraph, Scene *scene, Object *ob)
void BKE_ptcache_ids_from_object(struct ListBase *lb, struct Object *ob, struct Scene *scene, int duplis)
#define PTCACHE_TYPE_PARTICLES
#define PTCACHE_RESET_OUTDATED
int BKE_ptcache_object_reset(struct Scene *scene, struct Object *ob, int mode)
API for Blender-side Rigid Body stuff.
void BKE_rigidbody_aftertrans_update(struct Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle)
bool BKE_rigidbody_check_sim_running(struct RigidBodyWorld *rbw, float ctime)
float BKE_scene_ctime_get(const Scene *scene)
Definition scene.cc:2370
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3416
void BKE_scene_base_flag_to_objects(const Scene *scene, ViewLayer *view_layer)
Definition scene.cc:2850
#define BLI_assert(a)
Definition BLI_assert.h:46
GHash * BLI_ghash_ptr_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void copy_m3_m3(float m1[3][3], const float m2[3][3])
void unit_m3(float m[3][3])
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4])
void invert_m3_m3_safe_ortho(float inverse[3][3], const float mat[3][3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
bool orthogonalize_m3_zero_axes(float m[3][3], float unit_length)
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
void copy_qt_qt(float q[4], const float a[4])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define UNPACK3(a)
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
eDepsObjectComponentType
@ DEG_OB_COMP_GEOMETRY
@ DEG_OB_COMP_TRANSFORM
void DEG_graph_relations_update(Depsgraph *graph)
void DEG_foreach_dependent_ID_component(const Depsgraph *depsgraph, const ID *id, eDepsObjectComponentType source_component_type, int flags, DEGForeachIDComponentCallback callback)
@ DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_TAG_DOIT
Definition DNA_ID.h:1036
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1054
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ ID_OB
@ MOTIONPATH_BAKE_HAS_PATHS
eRotationModes
@ ROT_MODE_AXISANGLE
@ BA_WAS_SEL
@ BA_TRANSFORM_CHILD
@ BA_TRANSFORM_LOCKED_IN_PLACE
@ BA_TEMP_TAG
@ BA_TRANSFORM_PARENT
@ BA_SNAP_FIX_DEPS_FIASCO
@ OB_NO_CONSTRAINTS
@ OB_NEG_SCALE
@ PTCACHE_OUTDATED
#define BASE_SELECTED(v3d, base)
#define BASE_SELECTED_EDITABLE(v3d, base)
#define BASE_EDITABLE(v3d, base)
@ SCE_XFORM_AXIS_ALIGN
#define BASE_SELECTABLE(v3d, base)
@ AUTOKEY_FLAG_INSERTNEEDED
@ V3D_AROUND_ACTIVE
@ V3D_AROUND_CURSOR
@ V3D_AROUND_LOCAL_ORIGINS
@ V3D_ORIENT_GIMBAL
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
void ANIM_deselect_keys_in_animation_editors(bContext *C)
Definition anim_deps.cc:478
BPy_StructRNA * depsgraph
bool contains(const Key &key) const
Definition BLI_set.hh:310
bool add(const Key &key)
Definition BLI_set.hh:248
void append(const T &value)
void append_non_duplicates(const T &value)
Span< T > as_span() const
#define SELECT
#define rot(x, k)
#define GS(x)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
bool is_autokey_on(const Scene *scene)
bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
StringRef get_rotation_mode_path(eRotationModes rotation_mode)
Definition anim_rna.cc:82
void autokeyframe_object(bContext *C, const Scene *scene, Object *ob, Span< RNAPath > rna_paths)
bool is_keying_flag(const Scene *scene, eKeying_Flag flag)
@ OBJECT_PATH_CALC_RANGE_CURRENT_FRAME
Definition ED_object.hh:373
@ XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM
Definition ED_object.hh:139
@ XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT
Definition ED_object.hh:144
void motion_paths_recalc_selected(bContext *C, Scene *scene, eObjectPathCalcRange range)
void data_xform_container_destroy(XFormObjectData_Container *xds)
void base_select(Base *base, eObjectSelect_Mode mode)
XFormObjectSkipChild_Container * xform_skip_child_container_create()
void data_xform_container_update_all(XFormObjectData_Container *xds, Main *bmain, Depsgraph *depsgraph)
void object_xform_skip_child_container_destroy(XFormObjectSkipChild_Container *xcs)
void object_xform_skip_child_container_item_ensure(XFormObjectSkipChild_Container *xcs, Object *ob, Object *ob_parent_recurse, int mode)
void data_xform_container_item_ensure(XFormObjectData_Container *xds, Object *ob)
void object_xform_skip_child_container_update_all(XFormObjectSkipChild_Container *xcs, Main *bmain, Depsgraph *depsgraph)
XFormObjectData_Container * data_xform_container_create()
static void trans_obdata_in_obmode_update_all(TransInfo *t)
static int count_proportional_objects(TransInfo *t)
static void freeTransObjectCustomData(TransInfo *t, TransDataContainer *, TransCustomData *custom_data)
void animrecord_check_state(TransInfo *t, ID *id)
static void ObjectToTransData(TransInfo *t, TransData *td, TransDataExtension *td_ext, Object *ob)
static Vector< RNAPath > get_affected_rna_paths_from_transform_mode(const eTfmMode tmode, ToolSettings *toolsettings, const StringRef rotation_path, const bool targetless_ik, const bool is_connected, const bool transforming_more_than_one_bone)
static void special_aftertrans_update__object(bContext *C, TransInfo *t)
void transform_snap_project_individual_apply(TransInfo *t)
static void autokeyframe_object(bContext *C, Scene *scene, Object *ob, const eTfmMode tmode, const bool transforming_more_than_one_object)
bool constraints_list_needinv(TransInfo *t, ListBase *list)
static void recalcData_objects(TransInfo *t)
static void flush_trans_object_base_deps_flag(const TransInfo *t, Object *object)
static void tag_trans_objects_dep_fn(ID *id, eDepsObjectComponentType component)
static void createTransObject(bContext *C, TransInfo *t)
static bool motionpath_need_update_object(Scene *scene, Object *ob)
static void set_trans_object_base_flags(TransInfo *t)
static void tag_trans_objects_with_geometry_dep_only_fn(ID *id, eDepsObjectComponentType component)
bool transform_orientations_create_from_axis(float mat[3][3], const float x[3], const float y[3], const float z[3])
static bool mark_children(Object *ob)
TransConvertTypeInfo TransConvertType_Object
static void trans_object_base_deps_flag_prepare(const TransInfo *t, const Scene *scene, ViewLayer *view_layer)
bool gimbal_axis_object(Object *ob, float gmat[3][3])
static void trans_object_base_deps_flag_finish(const TransInfo *t, const Scene *scene, ViewLayer *view_layer)
static void clear_trans_object_base_flags(TransInfo *t)
static void trans_obchild_in_obmode_update_all(TransInfo *t)
Definition DNA_ID.h:414
struct Library * lib
Definition DNA_ID.h:420
char name[258]
Definition DNA_ID.h:432
void * first
short transflag
ListBase constraints
short base_flag
ObjectRuntimeHandle * runtime
float drot[3]
float dquat[4]
struct RigidBodyOb * rigidbody_object
float loc[3]
float dloc[3]
float scale[3]
float rot[3]
float drotAxis[3]
float quat[4]
float rotAxis[3]
float drotAngle
float dscale[3]
short protectflag
struct Object * parent
bAnimVizSettings avs
struct RigidBodyWorld * rigidbody_world
struct ToolSettings * toolsettings
void(* free_cb)(TransInfo *, TransDataContainer *tc, TransCustomData *custom_data)
Definition transform.hh:633
object::XFormObjectData_Container * xds
object::XFormObjectSkipChild_Container * xcs
TransCustomDataContainer custom
Definition transform.hh:974
i
Definition text_draw.cc:230
#define TRANS_DATA_CONTAINER_FIRST_SINGLE(t)
Definition transform.hh:39
#define FOREACH_TRANS_DATA_CONTAINER(t, th)
Definition transform.hh:42
conversion and adaptation of different datablocks to a common struct.
#define BASE_XFORM_INDIRECT(base)