Blender V4.5
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)) {
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
301static void trans_object_base_deps_flag_prepare(const Scene *scene, ViewLayer *view_layer)
302{
303 BKE_view_layer_synced_ensure(scene, view_layer);
305 base->object->id.tag &= ~ID_TAG_DOIT;
306 }
307}
308
310{
311 /* Here we only handle object IDs. */
312 if (GS(id->name) != ID_OB) {
313 return;
314 }
316 return;
317 }
318 id->tag |= ID_TAG_DOIT;
319}
320
330
332 const Scene *scene,
333 ViewLayer *view_layer)
334{
335
336 if ((t->options & CTX_OBMODE_XFORM_OBDATA) == 0) {
337 BKE_view_layer_synced_ensure(scene, view_layer);
339 if (base->object->id.tag & ID_TAG_DOIT) {
340 base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO;
341 }
342 }
343 }
344}
345
351{
352 Main *bmain = CTX_data_main(t->context);
353 ViewLayer *view_layer = t->view_layer;
354 View3D *v3d = static_cast<View3D *>(t->view);
355 Scene *scene = t->scene;
356 Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
357 /* NOTE: if Base selected and has parent selected:
358 * base->flag_legacy = BA_WAS_SEL
359 */
360 /* Don't do it if we're not actually going to recalculate anything. */
361 if (t->mode == TFM_DUMMY) {
362 return;
363 }
364 /* Makes sure base flags and object flags are identical. */
366 /* Make sure depsgraph is here. */
368 /* Clear all flags we need. It will be used to detect dependencies. */
369 trans_object_base_deps_flag_prepare(scene, view_layer);
370 /* Traverse all bases and set all possible flags. */
371 BKE_view_layer_synced_ensure(scene, view_layer);
373 base->flag_legacy &= ~(BA_WAS_SEL | BA_TRANSFORM_LOCKED_IN_PLACE);
374 if (BASE_SELECTED_EDITABLE(v3d, base)) {
375 Object *ob = base->object;
376 Object *parsel = ob->parent;
377 /* If parent selected, deselect. */
378 while (parsel != nullptr) {
379 if (parsel->base_flag & BASE_SELECTED) {
380 Base *parbase = BKE_view_layer_base_find(view_layer, parsel);
381 if (parbase != nullptr) { /* In rare cases this can fail. */
382 if (BASE_SELECTED_EDITABLE(v3d, parbase)) {
383 break;
384 }
385 }
386 }
387 parsel = parsel->parent;
388 }
389 if (parsel != nullptr) {
390 /* Rotation around local centers are allowed to propagate. */
392 {
393 base->flag_legacy |= BA_TRANSFORM_CHILD;
394 }
395 else {
396 base->flag &= ~BASE_SELECTED;
397 base->flag_legacy |= BA_WAS_SEL;
398 }
399 }
401 }
402 }
403 /* Store temporary bits in base indicating that base is being modified
404 * (directly or indirectly) by transforming objects.
405 */
406 trans_object_base_deps_flag_finish(t, scene, view_layer);
407}
408
409static bool mark_children(Object *ob)
410{
411 if (ob->flag & (SELECT | BA_TRANSFORM_CHILD)) {
412 return true;
413 }
414
415 if (ob->parent) {
416 if (mark_children(ob->parent)) {
418 return true;
419 }
420 }
421
422 return false;
423}
424
426{
427 int total = 0;
428 ViewLayer *view_layer = t->view_layer;
429 View3D *v3d = static_cast<View3D *>(t->view);
430 Main *bmain = CTX_data_main(t->context);
431 Scene *scene = t->scene;
432 Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
433 /* Clear all flags we need. It will be used to detect dependencies. */
434 trans_object_base_deps_flag_prepare(scene, view_layer);
435 /* Rotations around local centers are allowed to propagate, so we take all objects. */
437 /* Mark all parents. */
439 if (BASE_SELECTED_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
440 Object *parent = base->object->parent;
441 /* Flag all parents. */
442 while (parent != nullptr) {
443 parent->flag |= BA_TRANSFORM_PARENT;
444 parent = parent->parent;
445 }
446 }
447 }
448 /* Mark all children. */
450 /* All base not already selected or marked that is editable. */
451 if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
452 (base->flag & BASE_SELECTED) == 0 &&
453 (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)))
454 {
455 mark_children(base->object);
456 }
457 }
458 }
459 /* Flush changed flags to all dependencies. */
461 Object *ob = base->object;
462 /* If base is not selected, not a parent of selection or not a child of
463 * selection and it is editable and selectable.
464 */
465 if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
466 (base->flag & BASE_SELECTED) == 0 &&
467 (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)))
468 {
470 total += 1;
471 }
472 }
473 /* Store temporary bits in base indicating that base is being modified
474 * (directly or indirectly) by transforming objects.
475 */
476 trans_object_base_deps_flag_finish(t, scene, view_layer);
477 return total;
478}
479
481{
482 Scene *scene = t->scene;
483 ViewLayer *view_layer = t->view_layer;
484
485 BKE_view_layer_synced_ensure(scene, view_layer);
487 if (base->flag_legacy & BA_WAS_SEL) {
489 }
490
491 base->flag_legacy &= ~(BA_WAS_SEL | BA_SNAP_FIX_DEPS_FIASCO | BA_TEMP_TAG |
494 }
495}
496
498{
499 Main *bmain = CTX_data_main(C);
500 TransData *td = nullptr;
502 const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
503
505
507
508 /* Count. */
509 tc->data_len = CTX_DATA_COUNT(C, selected_bases);
510
511 if (!tc->data_len) {
512 /* Clear here, main transform function escapes too. */
514 return;
515 }
516
517 if (is_prop_edit) {
519 }
520
521 td = tc->data = MEM_calloc_arrayN<TransData>(tc->data_len, "TransOb");
522 tx = tc->data_ext = MEM_calloc_arrayN<TransDataExtension>(tc->data_len, "TransObExtension");
523
525 t->custom.type.data = tdo;
527
530 }
531
532 CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
533 Object *ob = base->object;
534
535 td->flag = TD_SELECTED;
536 td->protectflag = ob->protectflag;
537 td->ext = tx;
538 td->ext->rotOrder = ob->rotmode;
539
540 if (base->flag & BA_TRANSFORM_CHILD) {
541 td->flag |= TD_NOCENTER;
542 td->flag |= TD_NO_LOC;
543 }
544
545 /* Select linked objects, but skip them later. */
546 if (!BKE_id_is_editable(bmain, &ob->id)) {
547 td->flag |= TD_SKIP;
548 }
549
551 ID *id = static_cast<ID *>(ob->data);
552 if (!id || id->lib) {
553 td->flag |= TD_SKIP;
554 }
555 else if (BKE_object_is_in_editmode(ob)) {
556 /* NOTE(@ideasman42): The object could have edit-mode data from another view-layer,
557 * it's such a corner-case it can be skipped for now. */
558 td->flag |= TD_SKIP;
559 }
560 }
561
563 if ((td->flag & TD_SKIP) == 0) {
565 }
566 }
567
568 ObjectToTransData(t, td, ob);
569 td->val = nullptr;
570 td++;
571 tx++;
572 }
574
575 if (is_prop_edit) {
576 Scene *scene = t->scene;
577 ViewLayer *view_layer = t->view_layer;
578 View3D *v3d = static_cast<View3D *>(t->view);
579
580 BKE_view_layer_synced_ensure(scene, view_layer);
582 Object *ob = base->object;
583
584 /* If base is not selected, not a parent of selection
585 * or not a child of selection and it is editable and selectable. */
586 if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
587 (base->flag & BASE_SELECTED) == 0 && BASE_EDITABLE(v3d, base) &&
588 BASE_SELECTABLE(v3d, base))
589 {
590 td->protectflag = ob->protectflag;
591 td->ext = tx;
592 td->ext->rotOrder = ob->rotmode;
593
594 ObjectToTransData(t, td, ob);
595 td->val = nullptr;
596 td++;
597 tx++;
598 }
599 }
600 }
601
603 Set<Object *> objects_in_transdata;
604 td = tc->data;
605 for (int i = 0; i < tc->data_len; i++, td++) {
606 if ((td->flag & TD_SKIP) == 0) {
607 objects_in_transdata.add(static_cast<Object *>(td->extra));
608 }
609 }
610
611 Scene *scene = t->scene;
612 ViewLayer *view_layer = t->view_layer;
613 View3D *v3d = static_cast<View3D *>(t->view);
614
615 BKE_view_layer_synced_ensure(scene, view_layer);
617 Object *ob = base->object;
618
619 /* If base is not selected, not a parent of selection
620 * or not a child of selection and it is editable and selectable. */
621 if ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0 &&
622 BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base))
623 {
624
625 Object *ob_parent = ob->parent;
626 if (ob_parent != nullptr) {
627 if (!objects_in_transdata.contains(ob)) {
628 bool parent_in_transdata = false;
629 while (ob_parent != nullptr) {
630 if (objects_in_transdata.contains(ob_parent)) {
631 parent_in_transdata = true;
632 break;
633 }
634 ob_parent = ob_parent->parent;
635 }
636 if (parent_in_transdata) {
638 }
639 }
640 }
641 }
642 }
643 }
644
646
648
649#define BASE_XFORM_INDIRECT(base) \
650\
651 ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0)
652
653 Set<Object *> objects_in_transdata;
654 GHash *objects_parent_root = BLI_ghash_ptr_new_ex(__func__, tc->data_len);
655 td = tc->data;
656 for (int i = 0; i < tc->data_len; i++, td++) {
657 if ((td->flag & TD_SKIP) == 0) {
658 objects_in_transdata.add(static_cast<Object *>(td->extra));
659 }
660 }
661
662 Scene *scene = t->scene;
663 ViewLayer *view_layer = t->view_layer;
664
665 BKE_view_layer_synced_ensure(scene, view_layer);
667 Object *ob = base->object;
668 if (ob->parent != nullptr) {
669 if (ob->parent && !objects_in_transdata.contains(ob->parent) &&
670 !objects_in_transdata.contains(ob))
671 {
672 if ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0) {
673 Base *base_parent = BKE_view_layer_base_find(view_layer, ob->parent);
674 if (base_parent && !BASE_XFORM_INDIRECT(base_parent)) {
675 Object *ob_parent_recurse = ob->parent;
676 if (ob_parent_recurse != nullptr) {
677 while (ob_parent_recurse != nullptr) {
678 if (objects_in_transdata.contains(ob_parent_recurse)) {
679 break;
680 }
681 ob_parent_recurse = ob_parent_recurse->parent;
682 }
683
684 if (ob_parent_recurse) {
686 tdo->xcs, ob, ob_parent_recurse, object::XFORM_OB_SKIP_CHILD_PARENT_APPLY);
687 BLI_ghash_insert(objects_parent_root, ob, ob_parent_recurse);
688 base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE;
689 }
690 }
691 }
692 }
693 }
694 }
695 }
696
698 Object *ob = base->object;
699
700 if (BASE_XFORM_INDIRECT(base) || objects_in_transdata.contains(ob)) {
701 /* Pass. */
702 }
703 else if (ob->parent != nullptr) {
704 Base *base_parent = BKE_view_layer_base_find(view_layer, ob->parent);
705 if (base_parent) {
706 if (BASE_XFORM_INDIRECT(base_parent) || objects_in_transdata.contains(ob->parent)) {
709 base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE;
710 }
711 else {
712 Object *ob_parent_recurse = static_cast<Object *>(
713 BLI_ghash_lookup(objects_parent_root, ob->parent));
714 if (ob_parent_recurse) {
716 tdo->xcs,
717 ob,
718 ob_parent_recurse,
720 }
721 }
722 }
723 }
724 }
725 BLI_ghash_free(objects_parent_root, nullptr, nullptr);
726
727#undef BASE_XFORM_INDIRECT
728 }
729}
730
732
733/* -------------------------------------------------------------------- */
736
737/* Return if we need to update motion paths, only if they already exist,
738 * and we will insert a keyframe at the end of transform. */
740{
741 /* XXX: there's potential here for problems with unkeyed rotations/scale,
742 * but for now (until proper data-locality for baking operations),
743 * this should be a better fix for #24451 and #37755
744 */
745
746 if (animrig::autokeyframe_cfra_can_key(scene, &ob->id)) {
747 return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
748 }
749
750 return false;
751}
752
754
755/* -------------------------------------------------------------------- */
758
759/* Given the transform mode `tmode` return a Vector of RNA paths that were possibly modified during
760 * that transformation. */
762 const eTfmMode tmode,
763 Scene *scene,
764 ViewLayer *view_layer,
765 Object *ob,
766 const StringRef rotation_path,
767 const bool transforming_more_than_one_object)
768{
769 Vector<RNAPath> rna_paths;
770
771 /* Handle the cases where we always need to key location, regardless of
772 * transform mode. */
774 BKE_view_layer_synced_ensure(scene, view_layer);
775 if (ob != BKE_view_layer_active_object_get(view_layer)) {
776 rna_paths.append({"location"});
777 }
778 }
779 else if (transforming_more_than_one_object &&
781 {
782 rna_paths.append({"location"});
783 }
785 rna_paths.append({"location"});
786 }
787
788 /* Handle the transform-mode-specific cases. */
789 switch (tmode) {
790 case TFM_TRANSLATION:
791 rna_paths.append_non_duplicates({"location"});
792 break;
793
794 case TFM_ROTATION:
795 case TFM_TRACKBALL:
796 if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
797 rna_paths.append({rotation_path});
798 }
799 break;
800
801 case TFM_RESIZE:
802 if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
803 rna_paths.append({"scale"});
804 }
805 break;
806
807 default:
808 rna_paths.append_non_duplicates({"location"});
809 rna_paths.append({rotation_path});
810 rna_paths.append({"scale"});
811 }
812
813 return rna_paths;
814}
815
817 Scene *scene,
818 Object *ob,
819 const eTfmMode tmode,
820 const bool transforming_more_than_one_object)
821{
822 Vector<RNAPath> rna_paths;
823 ViewLayer *view_layer = CTX_data_view_layer(C);
825
828 tmode, scene, view_layer, ob, rotation_path, transforming_more_than_one_object);
829 }
830 else {
831 rna_paths = {{"location"}, {rotation_path}, {"scale"}};
832 }
833 animrig::autokeyframe_object(C, scene, ob, rna_paths.as_span());
834}
835
837{
838 bool motionpath_update = false;
839
840 if (t->state != TRANS_CANCEL) {
842 }
843
845 TransData *td = tc->data;
846
847 for (int i = 0; i < tc->data_len; i++, td++) {
848 Object *ob = static_cast<Object *>(td->extra);
849 if (td->flag & TD_SKIP) {
850 continue;
851 }
852
853 /* If animtimer is running, and the object already has animation data,
854 * check if the auto-record feature means that we should record 'samples'
855 * (i.e. uneditable animation values). */
856
857 /* TODO: auto-keyframe calls need some setting to specify to add samples
858 * (FPoints) instead of keyframes? */
859 if ((t->animtimer) && animrig::is_autokey_on(t->scene)) {
860 animrecord_check_state(t, &ob->id);
861 autokeyframe_object(t->context, t->scene, ob, t->mode, t->data_len_all > 1);
862 }
863
864 motionpath_update |= motionpath_need_update_object(t->scene, ob);
865
866 /* Sets recalc flags fully, instead of flushing existing ones
867 * otherwise proxies don't function correctly. */
869 }
870 }
871
872 if (motionpath_update) {
873 /* Update motion paths once for all transformed objects. */
876 }
877
880 }
881
884 }
885}
886
888
889/* -------------------------------------------------------------------- */
892
894{
896
897 Object *ob;
898 const bool canceled = (t->state == TRANS_CANCEL);
899
901 bool motionpath_update = false;
902
903 if (animrig::is_autokey_on(t->scene) && !canceled) {
905 }
906
907 for (int i = 0; i < tc->data_len; i++) {
908 TransData *td = tc->data + i;
909 ListBase pidlist;
910 ob = static_cast<Object *>(td->extra);
911
912 if (td->flag & TD_SKIP) {
913 continue;
914 }
915
916 /* Flag object caches as outdated. */
918 LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
919 if (pid->type != PTCACHE_TYPE_PARTICLES) {
920 /* Particles don't need reset on geometry change. */
921 pid->cache->flag |= PTCACHE_OUTDATED;
922 }
923 }
924 BLI_freelistN(&pidlist);
925
926 /* Point-cache refresh. */
929 }
930
931 /* Needed for proper updating of "quick cached" dynamics.
932 * Creates troubles for moving animated objects without
933 * auto-key though, probably needed is an animation-system override?
934 * NOTE(@jahka): Please remove if some other solution is found. */
936
937 /* Set auto-key if necessary. */
938 if (!canceled) {
939 autokeyframe_object(C, t->scene, ob, t->mode, tc->data_len > 1);
940 }
941
942 motionpath_update |= motionpath_need_update_object(t->scene, ob);
943
944 /* Restore rigid body transform. */
945 if (ob->rigidbody_object && canceled) {
946 float ctime = BKE_scene_ctime_get(t->scene);
949 td->ext->oloc,
950 td->ext->orot,
951 td->ext->oquat,
952 td->ext->orotAxis,
953 td->ext->orotAngle);
954 }
955 }
956 }
957
958 if (motionpath_update) {
959 /* Update motion paths once for all transformed objects. */
960 const object::eObjectPathCalcRange range = canceled ?
964 }
965
967}
968
970
972 /*flags*/ 0,
973 /*create_trans_data*/ createTransObject,
974 /*recalc_data*/ recalcData_objects,
975 /*special_aftertrans_update*/ special_aftertrans_update__object,
976};
977
978} // 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:2503
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:2367
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3427
void BKE_scene_base_flag_to_objects(const Scene *scene, ViewLayer *view_layer)
Definition scene.cc:2862
#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)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:962
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ ID_TAG_DOIT
Definition DNA_ID.h:944
@ ID_OB
@ MOTIONPATH_BAKE_HAS_PATHS
eRotationModes
@ ROT_MODE_AXISANGLE
@ OB_NO_CONSTRAINTS
@ OB_NEG_SCALE
@ BA_WAS_SEL
@ BA_TRANSFORM_CHILD
@ BA_TRANSFORM_LOCKED_IN_PLACE
@ BA_TEMP_TAG
@ BA_TRANSFORM_PARENT
@ BA_SNAP_FIX_DEPS_FIASCO
@ 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(a)
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:359
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()
@ XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM
Definition ED_object.hh:125
@ XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT
Definition ED_object.hh:130
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 trans_object_base_deps_flag_prepare(const Scene *scene, ViewLayer *view_layer)
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 createTransObject(bContext *C, TransInfo *t)
static bool motionpath_need_update_object(Scene *scene, Object *ob)
static void set_trans_object_base_flags(TransInfo *t)
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)
static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
TransConvertTypeInfo TransConvertType_Object
static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object)
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 set_trans_object_base_deps_flag_cb(ID *id, eDepsObjectComponentType component)
static void trans_obchild_in_obmode_update_all(TransInfo *t)
Definition DNA_ID.h:404
struct Library * lib
Definition DNA_ID.h:410
char name[66]
Definition DNA_ID.h:415
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:628
object::XFormObjectData_Container * xds
object::XFormObjectSkipChild_Container * xcs
TransCustomDataContainer custom
Definition transform.hh:968
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)