Blender V4.3
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
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_layer.hh"
18#include "BKE_lib_id.hh"
19#include "BKE_object.hh"
20#include "BKE_pointcache.h"
21#include "BKE_rigidbody.h"
22#include "BKE_scene.hh"
23
24#include "ANIM_action.hh"
25#include "ANIM_keyframing.hh"
26#include "ANIM_rna.hh"
27
28#include "ED_anim_api.hh"
29#include "ED_object.hh"
30
32
33#include "transform.hh"
35#include "transform_snap.hh"
36
37/* Own include. */
38#include "transform_convert.hh"
39
40/* -------------------------------------------------------------------- */
60
62 TransDataContainer * /*tc*/,
63 TransCustomData *custom_data)
64{
65 TransDataObject *tdo = static_cast<TransDataObject *>(custom_data->data);
66 custom_data->data = nullptr;
67
70 }
71
74 }
75 MEM_freeN(tdo);
76}
77
80/* -------------------------------------------------------------------- */
91{
92 TransDataObject *tdo = static_cast<TransDataObject *>(t->custom.type.data);
93 if (tdo->xds == nullptr) {
94 return;
95 }
96
97 Main *bmain = CTX_data_main(t->context);
99}
100
103/* -------------------------------------------------------------------- */
114{
115 TransDataObject *tdo = static_cast<TransDataObject *>(t->custom.type.data);
116 if (tdo->xcs == nullptr) {
117 return;
118 }
119
120 Main *bmain = CTX_data_main(t->context);
122}
123
126/* -------------------------------------------------------------------- */
133/* *********************** Object Transform data ******************* */
134
139{
140 Scene *scene = t->scene;
141 bool constinv;
142 bool skip_invert = false;
143
144 if (t->mode != TFM_DUMMY && ob->rigidbody_object) {
145 float rot[3][3], scale[3];
146 float ctime = BKE_scene_ctime_get(scene);
147
148 /* Only use rigid body transform if simulation is running,
149 * avoids problems with initial setup of rigid bodies. */
150 if (BKE_rigidbody_check_sim_running(scene->rigidbody_world, ctime)) {
151
152 /* Save original object transform. */
153 copy_v3_v3(td->ext->oloc, ob->loc);
154
155 if (ob->rotmode > 0) {
156 copy_v3_v3(td->ext->orot, ob->rot);
157 }
158 else if (ob->rotmode == ROT_MODE_AXISANGLE) {
159 td->ext->orotAngle = ob->rotAngle;
160 copy_v3_v3(td->ext->orotAxis, ob->rotAxis);
161 }
162 else {
163 copy_qt_qt(td->ext->oquat, ob->quat);
164 }
165 /* Update object's loc/rot to get current rigid body transform. */
166 mat4_to_loc_rot_size(ob->loc, rot, scale, ob->object_to_world().ptr());
167 sub_v3_v3(ob->loc, ob->dloc);
168 BKE_object_mat3_to_rot(ob, rot, false); /* `drot` is already corrected here. */
169 }
170 }
171
172 /* `axismtx` has the real orientation. */
173 transform_orientations_create_from_axis(td->axismtx, UNPACK3(ob->object_to_world().ptr()));
174 if (t->orient_type_mask & (1 << V3D_ORIENT_GIMBAL)) {
175 if (!gimbal_axis_object(ob, td->ext->axismtx_gimbal)) {
177 }
178 }
179
180 td->con = static_cast<bConstraint *>(ob->constraints.first);
181
182 /* HACK: temporarily disable tracking and/or constraints when getting
183 * object matrix, if tracking is on, or if constraints don't need
184 * inverse correction to stop it from screwing up space conversion
185 * matrix later. */
186 constinv = constraints_list_needinv(t, &ob->constraints);
187
188 /* Disable constraints inversion for dummy pass. */
189 if (t->mode == TFM_DUMMY) {
190 skip_invert = true;
191 }
192
193 /* NOTE: This is not really following copy-on-evaluation design and we should not
194 * be re-evaluating the evaluated object. But as the comment above mentioned
195 * this is part of a hack.
196 * More proper solution would be to make a shallow copy of the object and
197 * evaluate that, and access matrix of that evaluated copy of the object.
198 * Might be more tricky than it sounds, if some logic later on accesses the
199 * object matrix via td->ob->object_to_world().ptr(). */
200 Object *object_eval = DEG_get_evaluated_object(t->depsgraph, ob);
201 if (skip_invert == false && constinv == false) {
202 object_eval->transflag |= OB_NO_CONSTRAINTS; /* #BKE_object_where_is_calc checks this. */
203 /* It is possible to have transform data initialization prior to a
204 * complete dependency graph evaluated. Happens, for example, when
205 * changing transformation mode. */
206 BKE_object_tfm_copy(object_eval, ob);
207 BKE_object_where_is_calc(t->depsgraph, t->scene, object_eval);
208 object_eval->transflag &= ~OB_NO_CONSTRAINTS;
209 }
210 else {
211 BKE_object_where_is_calc(t->depsgraph, t->scene, object_eval);
212 }
213 /* Copy newly evaluated fields to the original object, similar to how
214 * active dependency graph will do it. */
215 copy_m4_m4(ob->runtime->object_to_world.ptr(), object_eval->object_to_world().ptr());
216 /* Only copy negative scale flag, this is the only flag which is modified by
217 * the BKE_object_where_is_calc(). The rest of the flags we need to keep,
218 * otherwise we might lose dupli flags (see #61787). */
219 ob->transflag &= ~OB_NEG_SCALE;
220 ob->transflag |= (object_eval->transflag & OB_NEG_SCALE);
221
222 td->ob = ob;
223
224 td->loc = ob->loc;
225 copy_v3_v3(td->iloc, td->loc);
226
227 if (ob->rotmode > 0) {
228 td->ext->rot = ob->rot;
229 td->ext->rotAxis = nullptr;
230 td->ext->rotAngle = nullptr;
231 td->ext->quat = nullptr;
232
233 copy_v3_v3(td->ext->irot, ob->rot);
234 copy_v3_v3(td->ext->drot, ob->drot);
235 }
236 else if (ob->rotmode == ROT_MODE_AXISANGLE) {
237 td->ext->rot = nullptr;
238 td->ext->rotAxis = ob->rotAxis;
239 td->ext->rotAngle = &ob->rotAngle;
240 td->ext->quat = nullptr;
241
242 td->ext->irotAngle = ob->rotAngle;
243 copy_v3_v3(td->ext->irotAxis, ob->rotAxis);
244/* XXX, not implemented. */
245#if 0
246 td->ext->drotAngle = ob->drotAngle;
247 copy_v3_v3(td->ext->drotAxis, ob->drotAxis);
248#endif
249 }
250 else {
251 td->ext->rot = nullptr;
252 td->ext->rotAxis = nullptr;
253 td->ext->rotAngle = nullptr;
254 td->ext->quat = ob->quat;
255
256 copy_qt_qt(td->ext->iquat, ob->quat);
257 copy_qt_qt(td->ext->dquat, ob->dquat);
258 }
259 td->ext->rotOrder = ob->rotmode;
260
261 td->ext->size = ob->scale;
262 copy_v3_v3(td->ext->isize, ob->scale);
263 copy_v3_v3(td->ext->dscale, ob->dscale);
264
265 copy_v3_v3(td->center, ob->object_to_world().location());
266
267 copy_m4_m4(td->ext->obmat, ob->object_to_world().ptr());
268
269 /* Is there a need to set the global<->data space conversion matrices? */
270 if (ob->parent || constinv) {
271 float obmtx[3][3], totmat[3][3], obinv[3][3];
272
273 /* Get the effect of parenting, and/or certain constraints.
274 * NOTE: some Constraints, and also Tracking should never get this
275 * done, as it doesn't work well.
276 */
277 BKE_object_to_mat3(ob, obmtx);
278 copy_m3_m4(totmat, ob->object_to_world().ptr());
279
280 /* If the object scale is zero on any axis, this might result in a zero matrix.
281 * In this case, the transformation would not do anything, see: #50103. */
282 orthogonalize_m3_zero_axes(obmtx, 1.0f);
283 orthogonalize_m3_zero_axes(totmat, 1.0f);
284
285 /* Use safe invert even though the input matrices have had zero axes set to unit length,
286 * in the unlikely case of failure (float precision for eg) this uses unit matrix fallback. */
287 invert_m3_m3_safe_ortho(obinv, totmat);
288 mul_m3_m3m3(td->smtx, obmtx, obinv);
290 }
291 else {
292 /* No conversion to/from data-space. */
293 unit_m3(td->smtx);
294 unit_m3(td->mtx);
295 }
296}
297
298static void trans_object_base_deps_flag_prepare(const Scene *scene, ViewLayer *view_layer)
299{
300 BKE_view_layer_synced_ensure(scene, view_layer);
302 base->object->id.tag &= ~ID_TAG_DOIT;
303 }
304}
305
307{
308 /* Here we only handle object IDs. */
309 if (GS(id->name) != ID_OB) {
310 return;
311 }
313 return;
314 }
315 id->tag |= ID_TAG_DOIT;
316}
317
327
329 const Scene *scene,
330 ViewLayer *view_layer)
331{
332
333 if ((t->options & CTX_OBMODE_XFORM_OBDATA) == 0) {
334 BKE_view_layer_synced_ensure(scene, view_layer);
336 if (base->object->id.tag & ID_TAG_DOIT) {
337 base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO;
338 }
339 }
340 }
341}
342
348{
349 Main *bmain = CTX_data_main(t->context);
350 ViewLayer *view_layer = t->view_layer;
351 View3D *v3d = static_cast<View3D *>(t->view);
352 Scene *scene = t->scene;
353 Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
354 /* NOTE: if Base selected and has parent selected:
355 * base->flag_legacy = BA_WAS_SEL
356 */
357 /* Don't do it if we're not actually going to recalculate anything. */
358 if (t->mode == TFM_DUMMY) {
359 return;
360 }
361 /* Makes sure base flags and object flags are identical. */
363 /* Make sure depsgraph is here. */
365 /* Clear all flags we need. It will be used to detect dependencies. */
366 trans_object_base_deps_flag_prepare(scene, view_layer);
367 /* Traverse all bases and set all possible flags. */
368 BKE_view_layer_synced_ensure(scene, view_layer);
370 base->flag_legacy &= ~(BA_WAS_SEL | BA_TRANSFORM_LOCKED_IN_PLACE);
371 if (BASE_SELECTED_EDITABLE(v3d, base)) {
372 Object *ob = base->object;
373 Object *parsel = ob->parent;
374 /* If parent selected, deselect. */
375 while (parsel != nullptr) {
376 if (parsel->base_flag & BASE_SELECTED) {
377 Base *parbase = BKE_view_layer_base_find(view_layer, parsel);
378 if (parbase != nullptr) { /* In rare cases this can fail. */
379 if (BASE_SELECTED_EDITABLE(v3d, parbase)) {
380 break;
381 }
382 }
383 }
384 parsel = parsel->parent;
385 }
386 if (parsel != nullptr) {
387 /* Rotation around local centers are allowed to propagate. */
389 {
390 base->flag_legacy |= BA_TRANSFORM_CHILD;
391 }
392 else {
393 base->flag &= ~BASE_SELECTED;
394 base->flag_legacy |= BA_WAS_SEL;
395 }
396 }
398 }
399 }
400 /* Store temporary bits in base indicating that base is being modified
401 * (directly or indirectly) by transforming objects.
402 */
403 trans_object_base_deps_flag_finish(t, scene, view_layer);
404}
405
406static bool mark_children(Object *ob)
407{
408 if (ob->flag & (SELECT | BA_TRANSFORM_CHILD)) {
409 return true;
410 }
411
412 if (ob->parent) {
413 if (mark_children(ob->parent)) {
415 return true;
416 }
417 }
418
419 return false;
420}
421
423{
424 int total = 0;
425 ViewLayer *view_layer = t->view_layer;
426 View3D *v3d = static_cast<View3D *>(t->view);
427 Main *bmain = CTX_data_main(t->context);
428 Scene *scene = t->scene;
429 Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer);
430 /* Clear all flags we need. It will be used to detect dependencies. */
431 trans_object_base_deps_flag_prepare(scene, view_layer);
432 /* Rotations around local centers are allowed to propagate, so we take all objects. */
434 /* Mark all parents. */
436 if (BASE_SELECTED_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
437 Object *parent = base->object->parent;
438 /* Flag all parents. */
439 while (parent != nullptr) {
440 parent->flag |= BA_TRANSFORM_PARENT;
441 parent = parent->parent;
442 }
443 }
444 }
445 /* Mark all children. */
447 /* All base not already selected or marked that is editable. */
448 if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
449 (base->flag & BASE_SELECTED) == 0 &&
450 (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)))
451 {
452 mark_children(base->object);
453 }
454 }
455 }
456 /* Flush changed flags to all dependencies. */
458 Object *ob = base->object;
459 /* If base is not selected, not a parent of selection or not a child of
460 * selection and it is editable and selectable.
461 */
462 if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
463 (base->flag & BASE_SELECTED) == 0 &&
464 (BASE_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)))
465 {
467 total += 1;
468 }
469 }
470 /* Store temporary bits in base indicating that base is being modified
471 * (directly or indirectly) by transforming objects.
472 */
473 trans_object_base_deps_flag_finish(t, scene, view_layer);
474 return total;
475}
476
478{
479 Scene *scene = t->scene;
480 ViewLayer *view_layer = t->view_layer;
481
482 BKE_view_layer_synced_ensure(scene, view_layer);
484 if (base->flag_legacy & BA_WAS_SEL) {
486 }
487
488 base->flag_legacy &= ~(BA_WAS_SEL | BA_SNAP_FIX_DEPS_FIASCO | BA_TEMP_TAG |
491 }
492}
493
495{
496 using namespace blender::ed;
497 Main *bmain = CTX_data_main(C);
498 TransData *td = nullptr;
500 const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
501
503
505
506 /* Count. */
507 tc->data_len = CTX_DATA_COUNT(C, selected_bases);
508
509 if (!tc->data_len) {
510 /* Clear here, main transform function escapes too. */
512 return;
513 }
514
515 if (is_prop_edit) {
517 }
518
519 td = tc->data = static_cast<TransData *>(
520 MEM_callocN(tc->data_len * sizeof(TransData), "TransOb"));
521 tx = tc->data_ext = static_cast<TransDataExtension *>(
522 MEM_callocN(tc->data_len * sizeof(TransDataExtension), "TransObExtension"));
523
524 TransDataObject *tdo = static_cast<TransDataObject *>(MEM_callocN(sizeof(*tdo), __func__));
525 t->custom.type.data = tdo;
527
529 tdo->xds = object::data_xform_container_create();
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) {
564 object::data_xform_container_item_ensure(tdo->xds, ob);
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 GSet *objects_in_transdata = BLI_gset_ptr_new_ex(__func__, tc->data_len);
604 td = tc->data;
605 for (int i = 0; i < tc->data_len; i++, td++) {
606 if ((td->flag & TD_SKIP) == 0) {
607 BLI_gset_add(objects_in_transdata, td->ob);
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 (!BLI_gset_haskey(objects_in_transdata, ob)) {
628 bool parent_in_transdata = false;
629 while (ob_parent != nullptr) {
630 if (BLI_gset_haskey(objects_in_transdata, ob_parent)) {
631 parent_in_transdata = true;
632 break;
633 }
634 ob_parent = ob_parent->parent;
635 }
636 if (parent_in_transdata) {
637 object::data_xform_container_item_ensure(tdo->xds, ob);
638 }
639 }
640 }
641 }
642 }
643 BLI_gset_free(objects_in_transdata, nullptr);
644 }
645
647
648 tdo->xcs = object::xform_skip_child_container_create();
649
650#define BASE_XFORM_INDIRECT(base) \
651\
652 ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0)
653
654 GSet *objects_in_transdata = BLI_gset_ptr_new_ex(__func__, tc->data_len);
655 GHash *objects_parent_root = BLI_ghash_ptr_new_ex(__func__, tc->data_len);
656 td = tc->data;
657 for (int i = 0; i < tc->data_len; i++, td++) {
658 if ((td->flag & TD_SKIP) == 0) {
659 BLI_gset_add(objects_in_transdata, td->ob);
660 }
661 }
662
663 Scene *scene = t->scene;
664 ViewLayer *view_layer = t->view_layer;
665
666 BKE_view_layer_synced_ensure(scene, view_layer);
668 Object *ob = base->object;
669 if (ob->parent != nullptr) {
670 if (ob->parent && !BLI_gset_haskey(objects_in_transdata, ob->parent) &&
671 !BLI_gset_haskey(objects_in_transdata, ob))
672 {
673 if ((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0) {
674 Base *base_parent = BKE_view_layer_base_find(view_layer, ob->parent);
675 if (base_parent && !BASE_XFORM_INDIRECT(base_parent)) {
676 Object *ob_parent_recurse = ob->parent;
677 if (ob_parent_recurse != nullptr) {
678 while (ob_parent_recurse != nullptr) {
679 if (BLI_gset_haskey(objects_in_transdata, ob_parent_recurse)) {
680 break;
681 }
682 ob_parent_recurse = ob_parent_recurse->parent;
683 }
684
685 if (ob_parent_recurse) {
686 object::object_xform_skip_child_container_item_ensure(
687 tdo->xcs, ob, ob_parent_recurse, object::XFORM_OB_SKIP_CHILD_PARENT_APPLY);
688 BLI_ghash_insert(objects_parent_root, ob, ob_parent_recurse);
689 base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE;
690 }
691 }
692 }
693 }
694 }
695 }
696 }
697
699 Object *ob = base->object;
700
701 if (BASE_XFORM_INDIRECT(base) || BLI_gset_haskey(objects_in_transdata, ob)) {
702 /* Pass. */
703 }
704 else if (ob->parent != nullptr) {
705 Base *base_parent = BKE_view_layer_base_find(view_layer, ob->parent);
706 if (base_parent) {
707 if (BASE_XFORM_INDIRECT(base_parent) ||
708 BLI_gset_haskey(objects_in_transdata, ob->parent))
709 {
710 object::object_xform_skip_child_container_item_ensure(
711 tdo->xcs, ob, nullptr, object::XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM);
712 base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE;
713 }
714 else {
715 Object *ob_parent_recurse = static_cast<Object *>(
716 BLI_ghash_lookup(objects_parent_root, ob->parent));
717 if (ob_parent_recurse) {
718 object::object_xform_skip_child_container_item_ensure(
719 tdo->xcs,
720 ob,
721 ob_parent_recurse,
722 object::XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT);
723 }
724 }
725 }
726 }
727 }
728 BLI_gset_free(objects_in_transdata, nullptr);
729 BLI_ghash_free(objects_parent_root, nullptr, nullptr);
730
731#undef BASE_XFORM_INDIRECT
732 }
733}
734
737/* -------------------------------------------------------------------- */
741/* Return if we need to update motion paths, only if they already exist,
742 * and we will insert a keyframe at the end of transform. */
744{
745 /* XXX: there's potential here for problems with unkeyed rotations/scale,
746 * but for now (until proper data-locality for baking operations),
747 * this should be a better fix for #24451 and #37755
748 */
749
751 return (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) != 0;
752 }
753
754 return false;
755}
756
759/* -------------------------------------------------------------------- */
763/* Given the transform mode `tmode` return a Vector of RNA paths that were possibly modified during
764 * that transformation. */
766 const eTfmMode tmode,
767 Scene *scene,
768 ViewLayer *view_layer,
769 Object *ob,
770 const blender::StringRef rotation_path,
771 const bool transforming_more_than_one_object)
772{
773 blender::Vector<RNAPath> rna_paths;
774
775 /* Handle the cases where we always need to key location, regardless of
776 * transform mode. */
777 if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
778 BKE_view_layer_synced_ensure(scene, view_layer);
779 if (ob != BKE_view_layer_active_object_get(view_layer)) {
780 rna_paths.append({"location"});
781 }
782 }
783 else if (transforming_more_than_one_object &&
784 scene->toolsettings->transform_pivot_point != V3D_AROUND_LOCAL_ORIGINS)
785 {
786 rna_paths.append({"location"});
787 }
788 else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
789 rna_paths.append({"location"});
790 }
791
792 /* Handle the transform-mode-specific cases. */
793 switch (tmode) {
794 case TFM_TRANSLATION:
795 rna_paths.append_non_duplicates({"location"});
796 break;
797
798 case TFM_ROTATION:
799 case TFM_TRACKBALL:
800 if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
801 rna_paths.append({rotation_path});
802 }
803 break;
804
805 case TFM_RESIZE:
806 if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
807 rna_paths.append({"scale"});
808 }
809 break;
810
811 default:
812 rna_paths.append_non_duplicates({"location"});
813 rna_paths.append({rotation_path});
814 rna_paths.append({"scale"});
815 }
816
817 return rna_paths;
818}
819
821 Scene *scene,
822 Object *ob,
823 const eTfmMode tmode,
824 const bool transforming_more_than_one_object)
825{
826 blender::Vector<RNAPath> rna_paths;
827 ViewLayer *view_layer = CTX_data_view_layer(C);
830
833 tmode, scene, view_layer, ob, rotation_path, transforming_more_than_one_object);
834 }
835 else {
836 rna_paths = {{"location"}, {rotation_path}, {"scale"}};
837 }
838 blender::animrig::autokeyframe_object(C, scene, ob, rna_paths.as_span());
839}
840
842{
843 using namespace blender::ed;
844 bool motionpath_update = false;
845
846 if (t->state != TRANS_CANCEL) {
848 }
849
851 TransData *td = tc->data;
852
853 for (int i = 0; i < tc->data_len; i++, td++) {
854 Object *ob = td->ob;
855 if (td->flag & TD_SKIP) {
856 continue;
857 }
858
859 /* If animtimer is running, and the object already has animation data,
860 * check if the auto-record feature means that we should record 'samples'
861 * (i.e. uneditable animation values). */
862
863 /* TODO: auto-keyframe calls need some setting to specify to add samples
864 * (FPoints) instead of keyframes? */
866 animrecord_check_state(t, &ob->id);
867 autokeyframe_object(t->context, t->scene, ob, t->mode, t->data_len_all > 1);
868 }
869
870 motionpath_update |= motionpath_need_update_object(t->scene, ob);
871
872 /* Sets recalc flags fully, instead of flushing existing ones
873 * otherwise proxies don't function correctly. */
875 }
876 }
877
878 if (motionpath_update) {
879 /* Update motion paths once for all transformed objects. */
880 object::motion_paths_recalc_selected(
881 t->context, t->scene, object::OBJECT_PATH_CALC_RANGE_CURRENT_FRAME);
882 }
883
886 }
887
890 }
891}
892
895/* -------------------------------------------------------------------- */
900{
901 using namespace blender::ed;
903
904 Object *ob;
905 const bool canceled = (t->state == TRANS_CANCEL);
906
908 bool motionpath_update = false;
909
910 if (blender::animrig::is_autokey_on(t->scene) && !canceled) {
912 for (int i = 0; i < tc->data_len; i++) {
913 const TransData *td = &tc->data[i];
914 objects.append(td->ob);
915 }
917 }
918
919 for (int i = 0; i < tc->data_len; i++) {
920 TransData *td = tc->data + i;
921 ListBase pidlist;
922 ob = td->ob;
923
924 if (td->flag & TD_SKIP) {
925 continue;
926 }
927
928 /* Flag object caches as outdated. */
930 LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
931 if (pid->type != PTCACHE_TYPE_PARTICLES) {
932 /* Particles don't need reset on geometry change. */
933 pid->cache->flag |= PTCACHE_OUTDATED;
934 }
935 }
936 BLI_freelistN(&pidlist);
937
938 /* Point-cache refresh. */
941 }
942
943 /* Needed for proper updating of "quick cached" dynamics.
944 * Creates troubles for moving animated objects without
945 * auto-key though, probably needed is an animation-system override?
946 * NOTE(@jahka): Please remove if some other solution is found. */
948
949 /* Set auto-key if necessary. */
950 if (!canceled) {
951 autokeyframe_object(C, t->scene, ob, t->mode, tc->data_len > 1);
952 }
953
954 motionpath_update |= motionpath_need_update_object(t->scene, ob);
955
956 /* Restore rigid body transform. */
957 if (ob->rigidbody_object && canceled) {
958 float ctime = BKE_scene_ctime_get(t->scene);
961 td->ext->oloc,
962 td->ext->orot,
963 td->ext->oquat,
964 td->ext->orotAxis,
965 td->ext->orotAngle);
966 }
967 }
968 }
969
970 if (motionpath_update) {
971 /* Update motion paths once for all transformed objects. */
972 const object::eObjectPathCalcRange range = canceled ?
973 object::OBJECT_PATH_CALC_RANGE_CURRENT_FRAME :
974 object::OBJECT_PATH_CALC_RANGE_CHANGED;
975 object::motion_paths_recalc_selected(C, t->scene, range);
976 }
977
979}
980
984 /*flags*/ 0,
985 /*create_trans_data*/ createTransObject,
986 /*recalc_data*/ recalcData_objects,
987 /*special_aftertrans_update*/ special_aftertrans_update__object,
988};
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)
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:2456
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:2317
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3377
void BKE_scene_base_flag_to_objects(const Scene *scene, ViewLayer *view_layer)
Definition scene.cc:2812
#define BLI_assert(a)
Definition BLI_assert.h:50
struct GSet GSet
Definition BLI_ghash.h:341
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:1004
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.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.c:1034
GSet * BLI_gset_ptr_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.c:966
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
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
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ ID_TAG_DOIT
Definition DNA_ID.h:1003
@ ID_OB
@ MOTIONPATH_BAKE_HAS_PATHS
eRotationModes
@ ROT_MODE_AXISANGLE
#define MAX_DUPLI_RECUR
@ 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)
@ SCE_XFORM_AXIS_ALIGN
#define BASE_EDITABLE(v3d, base)
#define BASE_SELECTABLE(v3d, base)
@ AUTOKEY_FLAG_INSERTNEEDED
@ V3D_AROUND_ACTIVE
@ V3D_AROUND_CURSOR
@ V3D_AROUND_LOCAL_ORIGINS
@ V3D_ORIENT_GIMBAL
eTfmMode
@ TFM_RESIZE
@ TFM_ROTATION
@ TFM_TRANSLATION
@ TFM_DUMMY
@ TFM_TRACKBALL
Read Guarded memory(de)allocation.
void ANIM_deselect_keys_in_animation_editors(bContext *C)
Definition anim_deps.cc:472
void append(const T &value)
void append_non_duplicates(const T &value)
Span< T > as_span() const
#define SELECT
const Depsgraph * depsgraph
#define rot(x, k)
#define GS(x)
Definition iris.cc:202
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void autokeyframe_object(bContext *C, Scene *scene, Object *ob, Span< RNAPath > rna_paths)
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:73
bool is_keying_flag(const Scene *scene, eKeying_Flag flag)
void data_xform_container_destroy(XFormObjectData_Container *xds)
void base_select(Base *base, eObjectSelect_Mode mode)
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_update_all(XFormObjectSkipChild_Container *xcs, Main *bmain, Depsgraph *depsgraph)
Definition DNA_ID.h:413
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
TransCustomData type
Definition transform.hh:425
void(* free_cb)(TransInfo *, TransDataContainer *tc, TransCustomData *custom_data)
Definition transform.hh:409
TransData * data
Definition transform.hh:445
TransDataExtension * data_ext
Definition transform.hh:447
float axismtx_gimbal[3][3]
blender::ed::object::XFormObjectData_Container * xds
blender::ed::object::XFormObjectSkipChild_Container * xcs
float smtx[3][3]
float axismtx[3][3]
float mtx[3][3]
TransDataExtension * ext
bConstraint * con
eTfmMode mode
Definition transform.hh:517
short around
Definition transform.hh:580
void * view
Definition transform.hh:647
int data_len_all
Definition transform.hh:510
wmTimer * animtimer
Definition transform.hh:657
eTState state
Definition transform.hh:527
TransCustomDataContainer custom
Definition transform.hh:676
Scene * scene
Definition transform.hh:654
ViewLayer * view_layer
Definition transform.hh:655
eTFlag flag
Definition transform.hh:523
int orient_type_mask
Definition transform.hh:619
Depsgraph * depsgraph
Definition transform.hh:653
bContext * context
Definition transform.hh:649
eTContext options
Definition transform.hh:521
@ CTX_OBMODE_XFORM_OBDATA
Definition transform.hh:80
@ CTX_OBMODE_XFORM_SKIP_CHILDREN
Definition transform.hh:82
@ CTX_OBJECT
Definition transform.hh:71
@ T_PROP_EDIT
Definition transform.hh:98
#define TRANS_DATA_CONTAINER_FIRST_SINGLE(t)
Definition transform.hh:851
@ TRANS_CANCEL
Definition transform.hh:210
#define FOREACH_TRANS_DATA_CONTAINER(t, th)
Definition transform.hh:854
void animrecord_check_state(TransInfo *t, ID *id)
bool constraints_list_needinv(TransInfo *t, ListBase *list)
conversion and adaptation of different datablocks to a common struct.
static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
static void autokeyframe_object(bContext *C, Scene *scene, Object *ob, const eTfmMode tmode, const bool transforming_more_than_one_object)
static void trans_object_base_deps_flag_finish(const TransInfo *t, const Scene *scene, ViewLayer *view_layer)
static void special_aftertrans_update__object(bContext *C, TransInfo *t)
static void set_trans_object_base_flags(TransInfo *t)
static void set_trans_object_base_deps_flag_cb(ID *id, eDepsObjectComponentType component)
static void recalcData_objects(TransInfo *t)
static bool motionpath_need_update_object(Scene *scene, Object *ob)
static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object)
static void trans_obchild_in_obmode_update_all(TransInfo *t)
static void clear_trans_object_base_flags(TransInfo *t)
#define BASE_XFORM_INDIRECT(base)
static int count_proportional_objects(TransInfo *t)
static void createTransObject(bContext *C, TransInfo *t)
static bool mark_children(Object *ob)
static blender::Vector< RNAPath > get_affected_rna_paths_from_transform_mode(const eTfmMode tmode, Scene *scene, ViewLayer *view_layer, Object *ob, const blender::StringRef rotation_path, const bool transforming_more_than_one_object)
static void freeTransObjectCustomData(TransInfo *t, TransDataContainer *, TransCustomData *custom_data)
static void trans_obdata_in_obmode_update_all(TransInfo *t)
static void trans_object_base_deps_flag_prepare(const Scene *scene, ViewLayer *view_layer)
TransConvertTypeInfo TransConvertType_Object
@ TD_SELECTED
@ TD_SKIP
@ TD_NO_LOC
@ TD_NOCENTER
bool transform_orientations_create_from_axis(float mat[3][3], const float x[3], const float y[3], const float z[3])
bool gimbal_axis_object(Object *ob, float gmat[3][3])
void transform_snap_project_individual_apply(TransInfo *t)