2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): none yet.
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/transform/transform_generics.c
29 * \ingroup edtransform
35 #include "MEM_guardedalloc.h"
37 #include "BLI_sys_types.h" /* for intptr_t support */
39 #include "DNA_anim_types.h"
40 #include "DNA_armature_types.h"
41 #include "DNA_brush_types.h"
42 #include "DNA_gpencil_types.h"
43 #include "DNA_lattice_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_sequence_types.h"
46 #include "DNA_space_types.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_object_types.h"
49 #include "DNA_mesh_types.h"
50 #include "DNA_view3d_types.h"
51 #include "DNA_modifier_types.h"
52 #include "DNA_movieclip_types.h"
53 #include "DNA_mask_types.h"
54 #include "DNA_meta_types.h"
57 #include "BLI_blenlib.h"
59 #include "BLI_utildefines.h"
61 #include "BLT_translation.h"
63 #include "RNA_access.h"
66 #include "BIF_glutil.h"
70 #include "BKE_animsys.h"
71 #include "BKE_action.h"
72 #include "BKE_armature.h"
73 #include "BKE_curve.h"
74 #include "BKE_depsgraph.h"
75 #include "BKE_fcurve.h"
76 #include "BKE_lattice.h"
77 #include "BKE_library.h"
79 #include "BKE_context.h"
80 #include "BKE_paint.h"
81 #include "BKE_sequencer.h"
82 #include "BKE_editmesh.h"
83 #include "BKE_tracking.h"
86 #include "ED_anim_api.h"
87 #include "ED_armature.h"
89 #include "ED_keyframing.h"
90 #include "ED_markers.h"
92 #include "ED_object.h"
93 #include "ED_particle.h"
94 #include "ED_screen_types.h"
95 #include "ED_space_api.h"
96 #include "ED_uvedit.h"
97 #include "ED_view3d.h"
98 #include "ED_curve.h" /* for curve_editnurbs */
100 #include "ED_screen.h"
102 #include "WM_types.h"
105 #include "UI_resources.h"
106 #include "UI_view2d.h"
108 #include "transform.h"
110 /* ************************** Functions *************************** */
112 void getViewVector(TransInfo *t, float coord[3], float vec[3])
114 if (t->persp != RV3D_ORTHO) {
115 sub_v3_v3v3(vec, coord, t->viewinv[3]);
118 copy_v3_v3(vec, t->viewinv[2]);
123 /* ************************** GENERICS **************************** */
126 static void clipMirrorModifier(TransInfo *t, Object *ob)
128 ModifierData *md = ob->modifiers.first;
129 float tolerance[3] = {0.0f, 0.0f, 0.0f};
132 for (; md; md = md->next) {
133 if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
134 MirrorModifierData *mmd = (MirrorModifierData *) md;
136 if (mmd->flag & MOD_MIR_CLIPPING) {
138 if (mmd->flag & MOD_MIR_AXIS_X) {
140 tolerance[0] = mmd->tolerance;
142 if (mmd->flag & MOD_MIR_AXIS_Y) {
144 tolerance[1] = mmd->tolerance;
146 if (mmd->flag & MOD_MIR_AXIS_Z) {
148 tolerance[2] = mmd->tolerance;
151 float mtx[4][4], imtx[4][4];
153 TransData *td = t->data;
155 if (mmd->mirror_ob) {
158 invert_m4_m4(obinv, mmd->mirror_ob->obmat);
159 mul_m4_m4m4(mtx, obinv, ob->obmat);
160 invert_m4_m4(imtx, mtx);
163 for (i = 0; i < t->total; i++, td++) {
165 float loc[3], iloc[3];
167 if (td->flag & TD_NOACTION)
172 if (td->flag & TD_SKIP)
175 copy_v3_v3(loc, td->loc);
176 copy_v3_v3(iloc, td->iloc);
178 if (mmd->mirror_ob) {
180 mul_m4_v3(mtx, iloc);
185 if (fabsf(iloc[0]) <= tolerance[0] ||
186 loc[0] * iloc[0] < 0.0f)
194 if (fabsf(iloc[1]) <= tolerance[1] ||
195 loc[1] * iloc[1] < 0.0f)
202 if (fabsf(iloc[2]) <= tolerance[2] ||
203 loc[2] * iloc[2] < 0.0f)
210 if (mmd->mirror_ob) {
211 mul_m4_v3(imtx, loc);
213 copy_v3_v3(td->loc, loc);
223 /* assumes obedit set to mesh object */
224 static void editbmesh_apply_to_mirror(TransInfo *t)
226 TransData *td = t->data;
230 for (i = 0; i < t->total; i++, td++) {
231 if (td->flag & TD_NOACTION)
235 if (td->flag & TD_SKIP)
240 eve->co[0] = -td->loc[0];
241 eve->co[1] = td->loc[1];
242 eve->co[2] = td->loc[2];
245 if (td->flag & TD_MIRROR_EDGE) {
251 /* for the realtime animation recording feature, handle overlapping data */
252 static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer)
254 ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL;
257 if (ELEM(NULL, scene, id, sad))
260 /* check if we need a new strip if:
261 * - if animtimer is running
262 * - we're not only keying for available channels
263 * - the option to add new actions for each round is not enabled
265 if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL) == 0 && (scene->toolsettings->autokey_flag & ANIMRECORD_FLAG_WITHNLA)) {
266 /* if playback has just looped around, we need to add a new NLA track+strip to allow a clean pass to occur */
267 if ((sad) && (sad->flag & ANIMPLAY_FLAG_JUMPED)) {
268 AnimData *adt = BKE_animdata_from_id(id);
269 const bool is_first = (adt) && (adt->nla_tracks.first == NULL);
271 /* perform push-down manually with some differences
272 * NOTE: BKE_nla_action_pushdown() sync warning...
274 if ((adt->action) && !(adt->flag & ADT_NLA_EDIT_ON)) {
277 /* only push down if action is more than 1-2 frames long */
278 calc_action_range(adt->action, &astart, &aend, 1);
279 if (aend > astart + 2.0f) {
280 NlaStrip *strip = BKE_nlastack_add_strip(adt, adt->action);
282 /* clear reference to action now that we've pushed it onto the stack */
283 id_us_min(&adt->action->id);
286 /* adjust blending + extend so that they will behave correctly */
287 strip->extendmode = NLASTRIP_EXTEND_NOTHING;
288 strip->flag &= ~(NLASTRIP_FLAG_AUTO_BLENDS | NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
290 /* copy current "action blending" settings from adt to the strip,
291 * as it was keyframed with these settings, so omitting them will
292 * change the effect [T54766]
294 if (is_first == false) {
295 strip->blendmode = adt->act_blendmode;
296 strip->influence = adt->act_influence;
298 if (adt->act_influence < 1.0f) {
299 /* enable "user-controlled" influence (which will insert a default keyframe)
300 * so that the influence doesn't get lost on the new update
302 * NOTE: An alternative way would have been to instead hack the influence
303 * to not get always get reset to full strength if NLASTRIP_FLAG_USR_INFLUENCE
304 * is disabled but auto-blending isn't being used. However, that approach
305 * is a bit hacky/hard to discover, and may cause backwards compatability issues,
306 * so it's better to just do it this way.
308 strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
309 BKE_nlastrip_validate_fcurves(strip);
313 /* also, adjust the AnimData's action extend mode to be on
314 * 'nothing' so that previous result still play
316 adt->act_extendmode = NLASTRIP_EXTEND_NOTHING;
323 static bool fcu_test_selected(FCurve *fcu)
325 BezTriple *bezt = fcu->bezt;
328 if (bezt == NULL) /* ignore baked */
331 for (i = 0; i < fcu->totvert; i++, bezt++) {
332 if (BEZT_ISSEL_ANY(bezt)) return 1;
338 /* helper for recalcData() - for Action Editor transforms */
339 static void recalcData_actedit(TransInfo *t)
341 Scene *scene = t->scene;
342 SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
344 bAnimContext ac = {NULL};
345 ListBase anim_data = {NULL, NULL};
349 /* initialize relevant anim-context 'context' data from TransInfo data */
350 /* NOTE: sync this with the code in ANIM_animdata_get_context() */
355 ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
356 ac.spacetype = (t->sa) ? t->sa->spacetype : 0;
357 ac.regiontype = (t->ar) ? t->ar->regiontype : 0;
359 ANIM_animdata_context_getdata(&ac);
362 if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
363 /* flush transform values back to actual coordinates */
364 flushTransIntFrameActionData(t);
367 /* get animdata blocks visible in editor, assuming that these will be the ones where things changed */
368 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
369 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
371 /* just tag these animdata-blocks to recalc, assuming that some data there changed
372 * BUT only do this if realtime updates are enabled
374 if ((saction->flag & SACTION_NOREALTIMEUPDATES) == 0) {
375 for (ale = anim_data.first; ale; ale = ale->next) {
376 /* set refresh tags for objects using this animation */
377 ANIM_list_elem_update(t->scene, ale);
381 /* now free temp channels */
382 ANIM_animdata_freelist(&anim_data);
385 /* helper for recalcData() - for Graph Editor transforms */
386 static void recalcData_graphedit(TransInfo *t)
388 SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
391 ListBase anim_data = {NULL, NULL};
392 bAnimContext ac = {NULL};
398 /* initialize relevant anim-context 'context' data from TransInfo data */
399 /* NOTE: sync this with the code in ANIM_animdata_get_context() */
400 scene = ac.scene = t->scene;
404 ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
405 ac.spacetype = (t->sa) ? t->sa->spacetype : 0;
406 ac.regiontype = (t->ar) ? t->ar->regiontype : 0;
408 ANIM_animdata_context_getdata(&ac);
410 /* do the flush first */
411 flushTransGraphData(t);
413 /* get curves to check if a re-sort is needed */
414 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
415 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
417 /* now test if there is a need to re-sort */
418 for (ale = anim_data.first; ale; ale = ale->next) {
419 FCurve *fcu = (FCurve *)ale->key_data;
421 /* ignore FC-Curves without any selected verts */
422 if (!fcu_test_selected(fcu))
425 /* watch it: if the time is wrong: do not correct handles yet */
426 if (test_time_fcurve(fcu))
429 calchandles_fcurve(fcu);
431 /* set refresh tags for objects using this animation,
432 * BUT only if realtime updates are enabled
434 if ((sipo->flag & SIPO_NOREALTIMEUPDATES) == 0)
435 ANIM_list_elem_update(t->scene, ale);
438 /* do resort and other updates? */
439 if (dosort) remake_graph_transdata(t, &anim_data);
441 /* now free temp channels */
442 ANIM_animdata_freelist(&anim_data);
445 /* helper for recalcData() - for NLA Editor transforms */
446 static void recalcData_nla(TransInfo *t)
448 TransDataNla *tdn = t->custom.type.data;
449 SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first;
450 Scene *scene = t->scene;
454 /* for each strip we've got, perform some additional validation of the values that got set before
455 * using RNA to set the value (which does some special operations when setting these values to make
456 * sure that everything works ok)
458 for (i = 0; i < t->total; i++, tdn++) {
459 NlaStrip *strip = tdn->strip;
460 PointerRNA strip_ptr;
461 short pExceeded, nExceeded, iter;
462 int delta_y1, delta_y2;
464 /* if this tdn has no handles, that means it is just a dummy that should be skipped */
465 if (tdn->handle == 0)
468 /* set refresh tags for objects using this animation,
469 * BUT only if realtime updates are enabled
471 if ((snla->flag & SNLA_NOREALTIMEUPDATES) == 0)
472 ANIM_id_update(t->scene, tdn->id);
474 /* if canceling transform, just write the values without validating, then move on */
475 if (t->state == TRANS_CANCEL) {
476 /* clear the values by directly overwriting the originals, but also need to restore
477 * endpoints of neighboring transition-strips
481 strip->start = tdn->h1[0];
483 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION))
484 strip->prev->end = tdn->h1[0];
487 strip->end = tdn->h2[0];
489 if ((strip->next) && (strip->next->type == NLASTRIP_TYPE_TRANSITION))
490 strip->next->start = tdn->h2[0];
492 /* flush transforms to child strips (since this should be a meta) */
493 BKE_nlameta_flush_transforms(strip);
495 /* restore to original track (if needed) */
496 if (tdn->oldTrack != tdn->nlt) {
497 /* just append to end of list for now, since strips get sorted in special_aftertrans_update() */
498 BLI_remlink(&tdn->nlt->strips, strip);
499 BLI_addtail(&tdn->oldTrack->strips, strip);
505 /* firstly, check if the proposed transform locations would overlap with any neighboring strips
506 * (barring transitions) which are absolute barriers since they are not being moved
508 * this is done as a iterative procedure (done 5 times max for now)
510 for (iter = 0; iter < 5; iter++) {
511 pExceeded = ((strip->prev) && (strip->prev->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h1[0] < strip->prev->end));
512 nExceeded = ((strip->next) && (strip->next->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h2[0] > strip->next->start));
514 if ((pExceeded && nExceeded) || (iter == 4)) {
515 /* both endpoints exceeded (or iteration ping-pong'd meaning that we need a compromise)
516 * - simply crop strip to fit within the bounds of the strips bounding it
517 * - if there were no neighbors, clear the transforms (make it default to the strip's current values)
519 if (strip->prev && strip->next) {
520 tdn->h1[0] = strip->prev->end;
521 tdn->h2[0] = strip->next->start;
524 tdn->h1[0] = strip->start;
525 tdn->h2[0] = strip->end;
528 else if (nExceeded) {
530 float offset = tdn->h2[0] - strip->next->start;
532 tdn->h1[0] -= offset;
533 tdn->h2[0] -= offset;
535 else if (pExceeded) {
537 float offset = strip->prev->end - tdn->h1[0];
539 tdn->h1[0] += offset;
540 tdn->h2[0] += offset;
542 else /* all is fine and well */
546 /* handle auto-snapping
547 * NOTE: only do this when transform is still running, or we can't restore
549 if (t->state != TRANS_CANCEL) {
550 switch (snla->autosnap) {
551 case SACTSNAP_FRAME: /* snap to nearest frame */
552 case SACTSNAP_STEP: /* frame step - this is basically the same, since we don't have any remapping going on */
554 tdn->h1[0] = floorf(tdn->h1[0] + 0.5f);
555 tdn->h2[0] = floorf(tdn->h2[0] + 0.5f);
559 case SACTSNAP_SECOND: /* snap to nearest second */
560 case SACTSNAP_TSTEP: /* second step - this is basically the same, since we don't have any remapping going on */
562 /* This case behaves differently from the rest, since lengths of strips
563 * may not be multiples of a second. If we just naively resize adjust
564 * the handles, things may not work correctly. Instead, we only snap
565 * the first handle, and move the other to fit.
567 * FIXME: we do run into problems here when user attempts to negatively
568 * scale the strip, as it then just compresses down and refuses
569 * to expand out the other end.
571 float h1_new = (float)(floor(((double)tdn->h1[0] / secf) + 0.5) * secf);
572 float delta = h1_new - tdn->h1[0];
579 case SACTSNAP_MARKER: /* snap to nearest marker */
581 tdn->h1[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h1[0]);
582 tdn->h2[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h2[0]);
588 /* Use RNA to write the values to ensure that constraints on these are obeyed
589 * (e.g. for transition strips, the values are taken from the neighbors)
591 * NOTE: we write these twice to avoid truncation errors which can arise when
592 * moving the strips a large distance using numeric input [#33852]
594 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
596 RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
597 RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
599 RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
600 RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
602 /* flush transforms to child strips (since this should be a meta) */
603 BKE_nlameta_flush_transforms(strip);
606 /* now, check if we need to try and move track
607 * - we need to calculate both, as only one may have been altered by transform if only 1 handle moved
609 delta_y1 = ((int)tdn->h1[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
610 delta_y2 = ((int)tdn->h2[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
612 if (delta_y1 || delta_y2) {
614 int delta = (delta_y2) ? delta_y2 : delta_y1;
617 /* move in the requested direction, checking at each layer if there's space for strip to pass through,
618 * stopping on the last track available or that we're able to fit in
621 for (track = tdn->nlt->next, n = 0; (track) && (n < delta); track = track->next, n++) {
622 /* check if space in this track for the strip */
623 if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
624 /* move strip to this track */
625 BLI_remlink(&tdn->nlt->strips, strip);
626 BKE_nlatrack_add_strip(track, strip);
631 else /* can't move any further */
636 /* make delta 'positive' before using it, since we now know to go backwards */
639 for (track = tdn->nlt->prev, n = 0; (track) && (n < delta); track = track->prev, n++) {
640 /* check if space in this track for the strip */
641 if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
642 /* move strip to this track */
643 BLI_remlink(&tdn->nlt->strips, strip);
644 BKE_nlatrack_add_strip(track, strip);
649 else /* can't move any further */
657 static void recalcData_mask_common(TransInfo *t)
659 Mask *mask = CTX_data_edit_mask(t->context);
661 flushTransMasking(t);
663 DAG_id_tag_update(&mask->id, 0);
666 /* helper for recalcData() - for Image Editor transforms */
667 static void recalcData_image(TransInfo *t)
669 if (t->options & CTX_MASK) {
670 recalcData_mask_common(t);
672 else if (t->options & CTX_PAINT_CURVE) {
673 flushTransPaintCurve(t);
675 else if (t->obedit && t->obedit->type == OB_MESH) {
676 SpaceImage *sima = t->sa->spacedata.first;
679 if (sima->flag & SI_LIVE_UNWRAP)
680 ED_uvedit_live_unwrap_re_solve();
682 DAG_id_tag_update(t->obedit->data, 0);
686 /* helper for recalcData() - for Movie Clip transforms */
687 static void recalcData_spaceclip(TransInfo *t)
689 SpaceClip *sc = t->sa->spacedata.first;
691 if (ED_space_clip_check_show_trackedit(sc)) {
692 MovieClip *clip = ED_space_clip_get_clip(sc);
693 ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
694 MovieTrackingTrack *track;
695 int framenr = ED_space_clip_get_clip_frame_number(sc);
697 flushTransTracking(t);
699 track = tracksbase->first;
701 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
702 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
704 if (t->mode == TFM_TRANSLATION) {
705 if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT))
706 BKE_tracking_marker_clamp(marker, CLAMP_PAT_POS);
707 if (TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH))
708 BKE_tracking_marker_clamp(marker, CLAMP_SEARCH_POS);
710 else if (t->mode == TFM_RESIZE) {
711 if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT))
712 BKE_tracking_marker_clamp(marker, CLAMP_PAT_DIM);
713 if (TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH))
714 BKE_tracking_marker_clamp(marker, CLAMP_SEARCH_DIM);
716 else if (t->mode == TFM_ROTATION) {
717 if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT))
718 BKE_tracking_marker_clamp(marker, CLAMP_PAT_POS);
725 DAG_id_tag_update(&clip->id, 0);
727 else if (t->options & CTX_MASK) {
728 recalcData_mask_common(t);
732 /* helper for recalcData() - for object transforms, typically in the 3D view */
733 static void recalcData_objects(TransInfo *t)
735 Base *base = t->scene->basact;
738 if (ELEM(t->obedit->type, OB_CURVE, OB_SURF)) {
739 Curve *cu = t->obedit->data;
740 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
741 Nurb *nu = nurbs->first;
743 if (t->state != TRANS_CANCEL) {
744 clipMirrorModifier(t, t->obedit);
748 DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
750 if (t->state == TRANS_CANCEL) {
752 BKE_nurb_handles_calc(nu); /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
757 /* Normal updating */
760 BKE_nurb_handles_calc(nu);
765 else if (t->obedit->type == OB_LATTICE) {
766 Lattice *la = t->obedit->data;
768 if (t->state != TRANS_CANCEL) {
772 DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
774 if (la->editlatt->latt->flag & LT_OUTSIDE) outside_lattice(la->editlatt->latt);
776 else if (t->obedit->type == OB_MESH) {
777 BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
778 /* mirror modifier clipping? */
779 if (t->state != TRANS_CANCEL) {
780 /* apply clipping after so we never project past the clip plane [#25423] */
782 clipMirrorModifier(t, t->obedit);
784 if ((t->options & CTX_NO_MIRROR) == 0 && (t->flag & T_MIRROR))
785 editbmesh_apply_to_mirror(t);
787 if (t->mode == TFM_EDGE_SLIDE) {
788 projectEdgeSlideData(t, false);
790 else if (t->mode == TFM_VERT_SLIDE) {
791 projectVertSlideData(t, false);
794 DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
796 EDBM_mesh_normals_update(em);
797 BKE_editmesh_tessface_calc(em);
799 else if (t->obedit->type == OB_ARMATURE) { /* no recalc flag, does pose */
800 bArmature *arm = t->obedit->data;
801 ListBase *edbo = arm->edbo;
802 EditBone *ebo, *ebo_parent;
803 TransData *td = t->data;
806 if (t->state != TRANS_CANCEL) {
810 /* Ensure all bones are correctly adjusted */
811 for (ebo = edbo->first; ebo; ebo = ebo->next) {
812 ebo_parent = (ebo->flag & BONE_CONNECTED) ? ebo->parent : NULL;
815 /* If this bone has a parent tip that has been moved */
816 if (ebo_parent->flag & BONE_TIPSEL) {
817 copy_v3_v3(ebo->head, ebo_parent->tail);
818 if (t->mode == TFM_BONE_ENVELOPE) ebo->rad_head = ebo_parent->rad_tail;
820 /* If this bone has a parent tip that has NOT been moved */
822 copy_v3_v3(ebo_parent->tail, ebo->head);
823 if (t->mode == TFM_BONE_ENVELOPE) ebo_parent->rad_tail = ebo->rad_head;
827 /* on extrude bones, oldlength==0.0f, so we scale radius of points */
828 ebo->length = len_v3v3(ebo->head, ebo->tail);
829 if (ebo->oldlength == 0.0f) {
830 ebo->rad_head = 0.25f * ebo->length;
831 ebo->rad_tail = 0.10f * ebo->length;
832 ebo->dist = 0.25f * ebo->length;
834 if (ebo->rad_head > ebo->parent->rad_tail)
835 ebo->rad_head = ebo->parent->rad_tail;
838 else if (t->mode != TFM_BONE_ENVELOPE) {
839 /* if bones change length, lets do that for the deform distance as well */
840 ebo->dist *= ebo->length / ebo->oldlength;
841 ebo->rad_head *= ebo->length / ebo->oldlength;
842 ebo->rad_tail *= ebo->length / ebo->oldlength;
843 ebo->oldlength = ebo->length;
846 ebo_parent->rad_tail = ebo->rad_head;
851 if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONE_ENVELOPE_DIST, TFM_BONESIZE)) {
853 for (i = 0; i < t->total; i++, td++) {
855 float vec[3], up_axis[3];
861 if (t->state == TRANS_CANCEL) {
863 ebo->roll = td->ival;
866 copy_v3_v3(up_axis, td->axismtx[2]);
868 sub_v3_v3v3(vec, ebo->tail, ebo->head);
870 rotation_between_vecs_to_quat(qrot, td->axismtx[1], vec);
871 mul_qt_v3(qrot, up_axis);
873 /* roll has a tendency to flip in certain orientations - [#34283], [#33974] */
874 roll = ED_armature_ebone_roll_to_vector(ebo, up_axis, false);
875 ebo->roll = angle_compat_rad(roll, td->ival);
881 if (arm->flag & ARM_MIRROR_EDIT) {
882 if (t->state != TRANS_CANCEL)
883 ED_armature_edit_transform_mirror_update(t->obedit);
889 if (t->state != TRANS_CANCEL) {
892 DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */
895 else if ((t->flag & T_POSE) && t->poseobj) {
896 Object *ob = t->poseobj;
897 bArmature *arm = ob->data;
899 /* if animtimer is running, and the object already has animation data,
900 * check if the auto-record feature means that we should record 'samples'
901 * (i.e. uneditable animation values)
903 * context is needed for keying set poll() functions.
905 // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
906 if ((t->animtimer) && (t->context) && IS_AUTOKEY_ON(t->scene)) {
907 int targetless_ik = (t->flag & T_AUTOIK); // XXX this currently doesn't work, since flags aren't set yet!
909 animrecord_check_state(t->scene, &ob->id, t->animtimer);
910 autokeyframe_pose_cb_func(t->context, t->scene, (View3D *)t->view, ob, t->mode, targetless_ik);
913 /* old optimize trick... this enforces to bypass the depgraph */
914 if (!(arm->flag & ARM_DELAYDEFORM)) {
915 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */
916 /* transformation of pose may affect IK tree, make sure it is rebuilt */
917 BIK_clear_data(ob->pose);
920 BKE_pose_where_is(t->scene, ob);
922 else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, base->object)) {
923 if (t->state != TRANS_CANCEL) {
926 flushTransParticles(t);
931 if (t->state != TRANS_CANCEL) {
935 for (i = 0; i < t->total; i++) {
936 TransData *td = t->data + i;
939 if (td->flag & TD_NOACTION)
942 if (td->flag & TD_SKIP)
945 /* if animtimer is running, and the object already has animation data,
946 * check if the auto-record feature means that we should record 'samples'
947 * (i.e. uneditable animation values)
949 // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
950 if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
951 animrecord_check_state(t->scene, &ob->id, t->animtimer);
952 autokeyframe_ob_cb_func(t->context, t->scene, (View3D *)t->view, ob, t->mode);
955 /* sets recalc flags fully, instead of flushing existing ones
956 * otherwise proxies don't function correctly
958 DAG_id_tag_update(&ob->id, OB_RECALC_OB);
960 if (t->flag & T_TEXTURE)
961 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
966 /* helper for recalcData() - for sequencer transforms */
967 static void recalcData_sequencer(TransInfo *t)
971 Sequence *seq_prev = NULL;
973 for (a = 0, td = t->data; a < t->total; a++, td++) {
974 TransDataSeq *tdsq = (TransDataSeq *) td->extra;
975 Sequence *seq = tdsq->seq;
977 if (seq != seq_prev) {
978 if (BKE_sequence_tx_fullupdate_test(seq)) {
979 /* A few effect strip types need a complete recache on transform. */
980 BKE_sequence_invalidate_cache(t->scene, seq);
983 BKE_sequence_invalidate_dependent(t->scene, seq);
990 BKE_sequencer_preprocessed_cache_cleanup();
995 /* force recalculation of triangles during transformation */
996 static void recalcData_gpencil_strokes(TransInfo *t)
998 TransData *td = t->data;
999 for (int i = 0; i < t->total; i++, td++) {
1000 bGPDstroke *gps = td->extra;
1002 gps->flag |= GP_STROKE_RECALC_CACHES;
1007 /* called for updating while transform acts, once per redraw */
1008 void recalcData(TransInfo *t)
1010 /* if tests must match createTransData for correct updates */
1011 if (t->options & CTX_TEXTURE) {
1012 recalcData_objects(t);
1014 else if (t->options & CTX_EDGE) {
1015 recalcData_objects(t);
1017 else if (t->options & CTX_PAINT_CURVE) {
1018 flushTransPaintCurve(t);
1020 else if (t->options & CTX_GPENCIL_STROKES) {
1021 /* set recalc triangle cache flag */
1022 recalcData_gpencil_strokes(t);
1024 else if (t->spacetype == SPACE_IMAGE) {
1025 recalcData_image(t);
1027 else if (t->spacetype == SPACE_ACTION) {
1028 recalcData_actedit(t);
1030 else if (t->spacetype == SPACE_NLA) {
1033 else if (t->spacetype == SPACE_SEQ) {
1034 recalcData_sequencer(t);
1036 else if (t->spacetype == SPACE_IPO) {
1037 recalcData_graphedit(t);
1039 else if (t->spacetype == SPACE_NODE) {
1042 else if (t->spacetype == SPACE_CLIP) {
1043 recalcData_spaceclip(t);
1046 recalcData_objects(t);
1050 void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis, short options)
1052 float v1[3], v2[3], v3[3];
1053 unsigned char col[3], col2[3];
1055 if (t->spacetype == SPACE_VIEW3D) {
1056 View3D *v3d = t->view;
1060 //if (t->obedit) glLoadMatrixf(t->obedit->obmat); // sets opengl viewing
1063 copy_v3_v3(v3, dir);
1064 mul_v3_fl(v3, v3d->far);
1066 sub_v3_v3v3(v2, center, v3);
1067 add_v3_v3v3(v1, center, v3);
1069 if (options & DRAWLIGHT) {
1070 col[0] = col[1] = col[2] = 220;
1073 UI_GetThemeColor3ubv(TH_GRID, col);
1075 UI_make_axis_color(col, col2, axis);
1089 * Free data before switching to another mode.
1091 void resetTransModal(TransInfo *t)
1093 if (t->mode == TFM_EDGE_SLIDE) {
1094 freeEdgeSlideVerts(t, &t->custom.mode);
1096 else if (t->mode == TFM_VERT_SLIDE) {
1097 freeVertSlideVerts(t, &t->custom.mode);
1101 void resetTransRestrictions(TransInfo *t)
1103 t->flag &= ~T_ALL_RESTRICTIONS;
1106 static int initTransInfo_edit_pet_to_flag(const int proportional)
1108 switch (proportional) {
1111 case PROP_EDIT_CONNECTED:
1112 return T_PROP_EDIT | T_PROP_CONNECTED;
1113 case PROP_EDIT_PROJECTED:
1114 return T_PROP_EDIT | T_PROP_PROJECTED;
1121 * Setup internal data, mouse, vectors
1123 * \note \a op and \a event can be NULL
1125 * \see #saveTransform does the reverse.
1127 void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
1129 Scene *sce = CTX_data_scene(C);
1130 ToolSettings *ts = CTX_data_tool_settings(C);
1131 ARegion *ar = CTX_wm_region(C);
1132 ScrArea *sa = CTX_wm_area(C);
1133 Object *obedit = CTX_data_edit_object(C);
1134 Object *ob = CTX_data_active_object(C);
1135 bGPdata *gpd = CTX_data_gpencil_data(C);
1143 t->reports = op ? op->reports : NULL;
1146 copy_m3_m4(t->obedit_mat, obedit->obmat);
1147 normalize_m3(t->obedit_mat);
1153 t->helpline = HLP_NONE;
1157 t->redraw = TREDRAW_HARD; /* redraw first time */
1160 t->mouse.imval[0] = event->mval[0];
1161 t->mouse.imval[1] = event->mval[1];
1164 t->mouse.imval[0] = 0;
1165 t->mouse.imval[1] = 0;
1168 t->con.imval[0] = t->mouse.imval[0];
1169 t->con.imval[1] = t->mouse.imval[1];
1171 t->mval[0] = t->mouse.imval[0];
1172 t->mval[1] = t->mouse.imval[1];
1174 t->transform = NULL;
1175 t->handleEvent = NULL;
1183 zero_v3(t->center_global);
1187 /* if there's an event, we're modal */
1192 /* Crease needs edge flag */
1193 if (ELEM(t->mode, TFM_CREASE, TFM_BWEIGHT)) {
1194 t->options |= CTX_EDGE;
1197 t->remove_on_cancel = false;
1199 if (op && (prop = RNA_struct_find_property(op->ptr, "remove_on_cancel")) && RNA_property_is_set(op->ptr, prop)) {
1200 if (RNA_property_boolean_get(op->ptr, prop)) {
1201 t->remove_on_cancel = true;
1205 /* GPencil editing context */
1206 if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
1207 t->options |= CTX_GPENCIL_STROKES;
1210 /* Assign the space type, some exceptions for running in different mode */
1212 /* background mode */
1213 t->spacetype = SPACE_EMPTY;
1215 else if ((ar == NULL) && (sa->spacetype == SPACE_VIEW3D)) {
1216 /* running in the text editor */
1217 t->spacetype = SPACE_EMPTY;
1220 /* normal operation */
1221 t->spacetype = sa->spacetype;
1224 /* handle T_ALT_TRANSFORM initialization, we may use for different operators */
1226 const char *prop_id = NULL;
1227 if (t->mode == TFM_SHRINKFATTEN) {
1228 prop_id = "use_even_offset";
1231 if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id)) &&
1232 RNA_property_is_set(op->ptr, prop))
1234 SET_FLAG_FROM_TEST(t->flag, RNA_property_boolean_get(op->ptr, prop), T_ALT_TRANSFORM);
1238 if (t->spacetype == SPACE_VIEW3D) {
1239 View3D *v3d = sa->spacedata.first;
1240 bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
1243 t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
1245 /* turn manipulator off during transform */
1246 // FIXME: but don't do this when USING the manipulator...
1247 if (t->flag & T_MODAL) {
1248 t->twtype = v3d->twtype;
1252 if (v3d->flag & V3D_ALIGN) t->flag |= T_V3D_ALIGN;
1253 t->around = v3d->around;
1255 /* bend always uses the cursor */
1256 if (t->mode == TFM_BEND) {
1257 t->around = V3D_AROUND_CURSOR;
1260 t->current_orientation = v3d->twmode;
1262 /* exceptional case */
1263 if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
1264 if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
1265 const bool use_island = transdata_check_local_islands(t, t->around);
1267 if (obedit && !use_island) {
1268 t->options |= CTX_NO_PET;
1273 if (ob && ob->mode & OB_MODE_ALL_PAINT) {
1274 Paint *p = BKE_paint_get_active_from_context(C);
1275 if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
1276 t->options |= CTX_PAINT_CURVE;
1280 /* initialize UV transform from */
1281 if (op && ((prop = RNA_struct_find_property(op->ptr, "correct_uv")))) {
1282 if (RNA_property_is_set(op->ptr, prop)) {
1283 if (RNA_property_boolean_get(op->ptr, prop)) {
1284 t->settings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT;
1287 t->settings->uvcalc_flag &= ~UVCALC_TRANSFORM_CORRECT;
1291 RNA_property_boolean_set(op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0);
1296 else if (t->spacetype == SPACE_IMAGE) {
1297 SpaceImage *sima = sa->spacedata.first;
1298 // XXX for now, get View2D from the active region
1300 t->around = sima->around;
1302 if (ED_space_image_show_uvedit(sima, t->obedit)) {
1305 else if (sima->mode == SI_MODE_MASK) {
1306 t->options |= CTX_MASK;
1308 else if (sima->mode == SI_MODE_PAINT) {
1309 Paint *p = &sce->toolsettings->imapaint.paint;
1310 if (p->brush && (p->brush->flag & BRUSH_CURVE)) {
1311 t->options |= CTX_PAINT_CURVE;
1314 /* image not in uv edit, nor in mask mode, can happen for some tools */
1316 else if (t->spacetype == SPACE_NODE) {
1317 // XXX for now, get View2D from the active region
1319 t->around = V3D_AROUND_CENTER_BOUNDS;
1321 else if (t->spacetype == SPACE_IPO) {
1322 SpaceIpo *sipo = sa->spacedata.first;
1324 t->around = sipo->around;
1326 else if (t->spacetype == SPACE_CLIP) {
1327 SpaceClip *sclip = sa->spacedata.first;
1329 t->around = sclip->around;
1331 if (ED_space_clip_check_show_trackedit(sclip))
1332 t->options |= CTX_MOVIECLIP;
1333 else if (ED_space_clip_check_show_maskedit(sclip))
1334 t->options |= CTX_MASK;
1338 // XXX for now, get View2D from the active region
1340 // XXX for now, the center point is the midpoint of the data
1345 t->around = V3D_AROUND_CENTER_BOUNDS;
1348 if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
1349 RNA_property_is_set(op->ptr, prop)))
1351 t->current_orientation = RNA_property_enum_get(op->ptr, prop);
1353 if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C)) {
1354 t->current_orientation = V3D_MANIP_GLOBAL;
1358 if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
1359 RNA_property_is_set(op->ptr, prop)))
1361 if (RNA_property_boolean_get(op->ptr, prop)) {
1362 t->flag |= T_RELEASE_CONFIRM;
1366 if (U.flag & USER_RELEASECONFIRM) {
1367 t->flag |= T_RELEASE_CONFIRM;
1371 if (op && ((prop = RNA_struct_find_property(op->ptr, "mirror")) &&
1372 RNA_property_is_set(op->ptr, prop)))
1374 if (RNA_property_boolean_get(op->ptr, prop)) {
1375 t->flag |= T_MIRROR;
1379 // Need stuff to take it from edit mesh or whatnot here
1380 else if (t->spacetype == SPACE_VIEW3D) {
1381 if (t->obedit && t->obedit->type == OB_MESH && (((Mesh *)t->obedit->data)->editflag & ME_EDIT_MIRROR_X)) {
1382 t->flag |= T_MIRROR;
1387 /* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */
1388 if (op && (prop = RNA_struct_find_property(op->ptr, "proportional"))) {
1389 if (RNA_property_is_set(op->ptr, prop)) {
1390 t->flag |= initTransInfo_edit_pet_to_flag(RNA_property_enum_get(op->ptr, prop));
1393 /* use settings from scene only if modal */
1394 if (t->flag & T_MODAL) {
1395 if ((t->options & CTX_NO_PET) == 0) {
1396 if (t->spacetype == SPACE_IPO) {
1397 t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_fcurve);
1399 else if (t->spacetype == SPACE_ACTION) {
1400 t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action);
1402 else if (t->obedit) {
1403 t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional);
1405 else if (t->options & CTX_GPENCIL_STROKES) {
1406 t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional);
1408 else if (t->options & CTX_MASK) {
1409 if (ts->proportional_mask) {
1410 t->flag |= T_PROP_EDIT;
1412 if (ts->proportional == PROP_EDIT_CONNECTED) {
1413 t->flag |= T_PROP_CONNECTED;
1417 else if (t->obedit == NULL && ts->proportional_objects) {
1418 t->flag |= T_PROP_EDIT;
1424 if (op && ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) &&
1425 RNA_property_is_set(op->ptr, prop)))
1427 t->prop_size = RNA_property_float_get(op->ptr, prop);
1430 t->prop_size = ts->proportional_size;
1434 /* TRANSFORM_FIX_ME rna restrictions */
1435 if (t->prop_size <= 0.00001f) {
1436 printf("Proportional size (%f) under 0.00001, resetting to 1!\n", t->prop_size);
1437 t->prop_size = 1.0f;
1440 if (op && ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) &&
1441 RNA_property_is_set(op->ptr, prop)))
1443 t->prop_mode = RNA_property_enum_get(op->ptr, prop);
1446 t->prop_mode = ts->prop_mode;
1449 else { /* add not pet option to context when not available */
1450 t->options |= CTX_NO_PET;
1453 // Mirror is not supported with PET, turn it off.
1455 if (t->flag & T_PROP_EDIT) {
1456 t->flag &= ~T_MIRROR;
1460 setTransformViewAspect(t, t->aspect);
1462 if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && RNA_property_is_set(op->ptr, prop)) {
1463 RNA_property_float_get_array(op->ptr, prop, t->center);
1464 mul_v3_v3(t->center, t->aspect);
1465 t->flag |= T_OVERRIDE_CENTER;
1468 setTransformViewMatrices(t);
1469 initNumInput(&t->num);
1472 /* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
1473 void postTrans(bContext *C, TransInfo *t)
1477 if (t->draw_handle_view)
1478 ED_region_draw_cb_exit(t->ar->type, t->draw_handle_view);
1479 if (t->draw_handle_apply)
1480 ED_region_draw_cb_exit(t->ar->type, t->draw_handle_apply);
1481 if (t->draw_handle_pixel)
1482 ED_region_draw_cb_exit(t->ar->type, t->draw_handle_pixel);
1483 if (t->draw_handle_cursor)
1484 WM_paint_cursor_end(CTX_wm_manager(C), t->draw_handle_cursor);
1486 /* Free all custom-data */
1488 TransCustomData *custom_data = &t->custom.first_elem;
1489 for (int i = 0; i < TRANS_CUSTOM_DATA_ELEM_MAX; i++, custom_data++) {
1490 if (custom_data->free_cb) {
1491 /* Can take over freeing t->data and data2d etc... */
1492 custom_data->free_cb(t, custom_data);
1493 BLI_assert(custom_data->data == NULL);
1495 else if ((custom_data->data != NULL) && custom_data->use_free) {
1496 MEM_freeN(custom_data->data);
1497 custom_data->data = NULL;
1502 /* postTrans can be called when nothing is selected, so data is NULL already */
1505 /* free data malloced per trans-data */
1506 if ((t->obedit && ELEM(t->obedit->type, OB_CURVE, OB_SURF)) ||
1507 (t->spacetype == SPACE_IPO))
1510 for (a = 0, td = t->data; a < t->total; a++, td++) {
1511 if (td->flag & TD_BEZTRIPLE) {
1512 MEM_freeN(td->hdata);
1519 BLI_freelistN(&t->tsnap.points);
1521 if (t->ext) MEM_freeN(t->ext);
1523 MEM_freeN(t->data2d);
1527 if (t->spacetype == SPACE_IMAGE) {
1528 if (t->options & (CTX_MASK | CTX_PAINT_CURVE)) {
1532 SpaceImage *sima = t->sa->spacedata.first;
1533 if (sima->flag & SI_LIVE_UNWRAP)
1534 ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL);
1537 else if (t->spacetype == SPACE_VIEW3D) {
1538 View3D *v3d = t->sa->spacedata.first;
1539 /* restore manipulator */
1540 if (t->flag & T_MODAL) {
1541 v3d->twtype = t->twtype;
1545 if (t->mouse.data) {
1546 MEM_freeN(t->mouse.data);
1552 void applyTransObjects(TransInfo *t)
1556 for (td = t->data; td < t->data + t->total; td++) {
1557 copy_v3_v3(td->iloc, td->loc);
1559 copy_v3_v3(td->ext->irot, td->ext->rot);
1561 if (td->ext->size) {
1562 copy_v3_v3(td->ext->isize, td->ext->size);
1568 static void restoreElement(TransData *td)
1570 /* TransData for crease has no loc */
1572 copy_v3_v3(td->loc, td->iloc);
1575 *td->val = td->ival;
1578 if (td->ext && (td->flag & TD_NO_EXT) == 0) {
1580 copy_v3_v3(td->ext->rot, td->ext->irot);
1582 if (td->ext->rotAngle) {
1583 *td->ext->rotAngle = td->ext->irotAngle;
1585 if (td->ext->rotAxis) {
1586 copy_v3_v3(td->ext->rotAxis, td->ext->irotAxis);
1588 /* XXX, drotAngle & drotAxis not used yet */
1589 if (td->ext->size) {
1590 copy_v3_v3(td->ext->size, td->ext->isize);
1592 if (td->ext->quat) {
1593 copy_qt_qt(td->ext->quat, td->ext->iquat);
1597 if (td->flag & TD_BEZTRIPLE) {
1598 *(td->hdata->h1) = td->hdata->ih1;
1599 *(td->hdata->h2) = td->hdata->ih2;
1603 void restoreTransObjects(TransInfo *t)
1608 for (td = t->data; td < t->data + t->total; td++) {
1612 for (td2d = t->data2d; t->data2d && td2d < t->data2d + t->total; td2d++) {
1614 td2d->h1[0] = td2d->ih1[0];
1615 td2d->h1[1] = td2d->ih1[1];
1618 td2d->h2[0] = td2d->ih2[0];
1619 td2d->h2[1] = td2d->ih2[1];
1628 void calculateCenter2D(TransInfo *t)
1630 BLI_assert(!is_zero_v3(t->aspect));
1632 if (t->flag & (T_EDIT | T_POSE)) {
1633 Object *ob = t->obedit ? t->obedit : t->poseobj;
1636 copy_v3_v3(vec, t->center);
1637 mul_m4_v3(ob->obmat, vec);
1638 projectFloatView(t, vec, t->center2d);
1641 projectFloatView(t, t->center, t->center2d);
1645 void calculateCenterGlobal(
1646 TransInfo *t, const float center_local[3],
1647 float r_center_global[3])
1649 /* setting constraint center */
1650 /* note, init functions may over-ride t->center */
1651 if (t->flag & (T_EDIT | T_POSE)) {
1652 Object *ob = t->obedit ? t->obedit : t->poseobj;
1653 mul_v3_m4v3(r_center_global, ob->obmat, center_local);
1656 copy_v3_v3(r_center_global, center_local);
1660 void calculateCenterCursor(TransInfo *t, float r_center[3])
1662 const float *cursor;
1664 cursor = ED_view3d_cursor3d_get(t->scene, t->view);
1665 copy_v3_v3(r_center, cursor);
1667 /* If edit or pose mode, move cursor in local space */
1668 if (t->flag & (T_EDIT | T_POSE)) {
1669 Object *ob = t->obedit ? t->obedit : t->poseobj;
1670 float mat[3][3], imat[3][3];
1672 sub_v3_v3v3(r_center, r_center, ob->obmat[3]);
1673 copy_m3_m4(mat, ob->obmat);
1674 invert_m3_m3(imat, mat);
1675 mul_m3_v3(imat, r_center);
1677 else if (t->options & CTX_PAINT_CURVE) {
1678 if (ED_view3d_project_float_global(t->ar, cursor, r_center, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
1679 r_center[0] = t->ar->winx / 2.0f;
1680 r_center[1] = t->ar->winy / 2.0f;
1686 void calculateCenterCursor2D(TransInfo *t, float r_center[2])
1688 const float *cursor = NULL;
1690 if (t->spacetype == SPACE_IMAGE) {
1691 SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
1692 cursor = sima->cursor;
1694 else if (t->spacetype == SPACE_CLIP) {
1695 SpaceClip *space_clip = (SpaceClip *) t->sa->spacedata.first;
1696 cursor = space_clip->cursor;
1700 if (t->options & CTX_MASK) {
1703 if (t->spacetype == SPACE_IMAGE) {
1704 SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
1705 BKE_mask_coord_from_image(sima->image, &sima->iuser, co, cursor);
1707 else if (t->spacetype == SPACE_CLIP) {
1708 SpaceClip *space_clip = (SpaceClip *) t->sa->spacedata.first;
1709 BKE_mask_coord_from_movieclip(space_clip->clip, &space_clip->user, co, cursor);
1712 BLI_assert(!"Shall not happen");
1715 r_center[0] = co[0] * t->aspect[0];
1716 r_center[1] = co[1] * t->aspect[1];
1718 else if (t->options & CTX_PAINT_CURVE) {
1719 if (t->spacetype == SPACE_IMAGE) {
1720 r_center[0] = UI_view2d_view_to_region_x(&t->ar->v2d, cursor[0]);
1721 r_center[1] = UI_view2d_view_to_region_y(&t->ar->v2d, cursor[1]);
1725 r_center[0] = cursor[0] * t->aspect[0];
1726 r_center[1] = cursor[1] * t->aspect[1];
1731 void calculateCenterCursorGraph2D(TransInfo *t, float r_center[2])
1733 SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
1734 Scene *scene = t->scene;
1736 /* cursor is combination of current frame, and graph-editor cursor value */
1737 if (sipo->mode == SIPO_MODE_DRIVERS) {
1738 r_center[0] = sipo->cursorTime;
1739 r_center[1] = sipo->cursorVal;
1742 r_center[0] = (float)(scene->r.cfra);
1743 r_center[1] = sipo->cursorVal;
1747 void calculateCenterMedian(TransInfo *t, float r_center[3])
1749 float partial[3] = {0.0f, 0.0f, 0.0f};
1753 for (i = 0; i < t->total; i++) {
1754 if (t->data[i].flag & TD_SELECTED) {
1755 if (!(t->data[i].flag & TD_NOCENTER)) {
1756 add_v3_v3(partial, t->data[i].center);
1762 mul_v3_fl(partial, 1.0f / (float)total);
1764 copy_v3_v3(r_center, partial);
1767 void calculateCenterBound(TransInfo *t, float r_center[3])
1772 for (i = 0; i < t->total; i++) {
1774 if (t->data[i].flag & TD_SELECTED) {
1775 if (!(t->data[i].flag & TD_NOCENTER))
1776 minmax_v3v3_v3(min, max, t->data[i].center);
1780 copy_v3_v3(max, t->data[i].center);
1781 copy_v3_v3(min, t->data[i].center);
1784 mid_v3_v3v3(r_center, min, max);
1788 * \param select_only only get active center from data being transformed.
1790 bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
1795 if (ED_object_editmode_calc_active_center(t->obedit, select_only, r_center)) {
1799 else if (t->flag & T_POSE) {
1800 Scene *scene = t->scene;
1803 bPoseChannel *pchan = BKE_pose_channel_active(ob);
1804 if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) {
1805 copy_v3_v3(r_center, pchan->pose_head);
1810 else if (t->options & CTX_PAINT_CURVE) {
1811 Paint *p = BKE_paint_get_active(t->scene);
1812 Brush *br = p->brush;
1813 PaintCurve *pc = br->paint_curve;
1814 copy_v3_v3(r_center, pc->points[pc->add_index - 1].bez.vec[1]);
1820 Scene *scene = t->scene;
1822 if (ob && (!select_only || (ob->flag & SELECT))) {
1823 copy_v3_v3(r_center, ob->obmat[3]);
1831 static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[3])
1834 case V3D_AROUND_CENTER_BOUNDS:
1835 calculateCenterBound(t, r_center);
1837 case V3D_AROUND_CENTER_MEAN:
1838 calculateCenterMedian(t, r_center);
1840 case V3D_AROUND_CURSOR:
1841 if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP))
1842 calculateCenterCursor2D(t, r_center);
1843 else if (t->spacetype == SPACE_IPO)
1844 calculateCenterCursorGraph2D(t, r_center);
1846 calculateCenterCursor(t, r_center);
1848 case V3D_AROUND_LOCAL_ORIGINS:
1849 /* Individual element center uses median center for helpline and such */
1850 calculateCenterMedian(t, r_center);
1852 case V3D_AROUND_ACTIVE:
1854 if (calculateCenterActive(t, false, r_center)) {
1859 calculateCenterMedian(t, r_center);
1866 void calculateCenter(TransInfo *t)
1868 if ((t->flag & T_OVERRIDE_CENTER) == 0) {
1869 calculateCenter_FromAround(t, t->around, t->center);
1871 calculateCenterGlobal(t, t->center, t->center_global);
1873 /* avoid calculating again */
1875 TransCenterData *cd = &t->center_cache[t->around];
1876 copy_v3_v3(cd->local, t->center);
1877 copy_v3_v3(cd->global, t->center_global);
1881 calculateCenter2D(t);
1883 /* for panning from cameraview */
1884 if ((t->flag & T_OBJECT) && (t->flag & T_OVERRIDE_CENTER) == 0) {
1885 if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
1887 if (t->flag & T_CAMERA) {
1889 /* persinv is nasty, use viewinv instead, always right */
1890 copy_v3_v3(axis, t->viewinv[2]);
1893 /* 6.0 = 6 grid units */
1894 axis[0] = t->center[0] - 6.0f * axis[0];
1895 axis[1] = t->center[1] - 6.0f * axis[1];
1896 axis[2] = t->center[2] - 6.0f * axis[2];
1898 projectFloatView(t, axis, t->center2d);
1900 /* rotate only needs correct 2d center, grab needs ED_view3d_calc_zfac() value */
1901 if (t->mode == TFM_TRANSLATION) {
1902 copy_v3_v3(t->center, axis);
1903 copy_v3_v3(t->center_global, t->center);
1909 if (t->spacetype == SPACE_VIEW3D) {
1910 /* ED_view3d_calc_zfac() defines a factor for perspective depth correction, used in ED_view3d_win_to_delta() */
1912 /* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW
1913 * and never used in other cases.
1915 * We need special case here as well, since ED_view3d_calc_zfac will crash when called
1916 * for a region different from RGN_TYPE_WINDOW.
1918 if (t->ar->regiontype == RGN_TYPE_WINDOW) {
1919 t->zfac = ED_view3d_calc_zfac(t->ar->regiondata, t->center_global, NULL);
1927 BLI_STATIC_ASSERT(ARRAY_SIZE(((TransInfo *)NULL)->center_cache) == (V3D_AROUND_ACTIVE + 1), "test size");
1930 * Lazy initialize transform center data, when we need to access center values from other types.
1932 const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
1934 BLI_assert(around <= V3D_AROUND_ACTIVE);
1935 TransCenterData *cd = &t->center_cache[around];
1936 if (cd->is_set == false) {
1937 calculateCenter_FromAround(t, around, cd->local);
1938 calculateCenterGlobal(t, cd->local, cd->global);
1944 void calculatePropRatio(TransInfo *t)
1946 TransData *td = t->data;
1949 const bool connected = (t->flag & T_PROP_CONNECTED) != 0;
1951 t->proptext[0] = '\0';
1953 if (t->flag & T_PROP_EDIT) {
1954 const char *pet_id = NULL;
1955 for (i = 0; i < t->total; i++, td++) {
1956 if (td->flag & TD_SELECTED) {
1959 else if (t->flag & T_MIRROR && td->loc[0] * t->mirror < -0.00001f) {
1960 td->flag |= TD_SKIP;
1964 else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) ||
1965 (connected == 0 && td->rdist > t->prop_size))
1968 * The elements are sorted according to their dist member in the array,
1969 * that means we can stop when it finds one element outside of the propsize.
1970 * do not set 'td->flag |= TD_NOACTION', the prop circle is being changed.
1977 /* Use rdist for falloff calculations, it is the real distance */
1978 td->flag &= ~TD_NOACTION;
1981 dist = (t->prop_size - td->dist) / t->prop_size;
1983 dist = (t->prop_size - td->rdist) / t->prop_size;
1986 * Clamp to positive numbers.
1987 * Certain corner cases with connectivity and individual centers
1988 * can give values of rdist larger than propsize.
1993 switch (t->prop_mode) {
1995 td->factor = dist * dist;
1998 td->factor = 3.0f * dist * dist - 2.0f * dist * dist * dist;
2001 td->factor = sqrtf(dist);
2010 td->factor = sqrtf(2 * dist - dist * dist);
2013 td->factor = BLI_frand() * dist;
2015 case PROP_INVSQUARE:
2016 td->factor = dist * (2.0f - dist);
2024 switch (t->prop_mode) {
2026 pet_id = N_("(Sharp)");
2029 pet_id = N_("(Smooth)");
2032 pet_id = N_("(Root)");
2035 pet_id = N_("(Linear)");
2038 pet_id = N_("(Constant)");
2041 pet_id = N_("(Sphere)");
2044 pet_id = N_("(Random)");
2046 case PROP_INVSQUARE:
2047 pet_id = N_("(InvSquare)");
2054 BLI_strncpy(t->proptext, IFACE_(pet_id), sizeof(t->proptext));
2058 for (i = 0; i < t->total; i++, td++) {
2065 * Rotate an element, low level code, ignore protected channels.
2066 * (use for objects or pose-bones)
2067 * Similar to #ElementRotation.
2069 void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot)
2076 float dmat[3][3]; /* delta rotation */
2077 float dmat_inv[3][3];
2079 mul_m3_m3m3(totmat, mat, td->mtx);
2080 mul_m3_m3m3(smat, td->smtx, mat);
2082 /* logic from BKE_object_rot_to_mat3 */
2084 if (td->ext->rotOrder > 0) {
2085 eulO_to_mat3(dmat, td->ext->drot, td->ext->rotOrder);
2087 else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
2089 axis_angle_to_mat3(dmat, td->ext->drotAxis, td->ext->drotAngle);
2096 normalize_qt_qt(tquat, td->ext->dquat);
2097 quat_to_mat3(dmat, tquat);
2100 invert_m3_m3(dmat_inv, dmat);
2104 if (td->ext->rotOrder == ROT_MODE_QUAT) {
2107 /* calculate the total rotatation */
2108 quat_to_mat3(obmat, td->ext->iquat);
2110 mul_m3_m3m3(obmat, dmat, obmat);
2113 /* mat = transform, obmat = object rotation */
2114 mul_m3_m3m3(fmat, smat, obmat);
2117 mul_m3_m3m3(fmat, dmat_inv, fmat);
2120 mat3_to_quat(quat, fmat);
2123 copy_qt_qt(td->ext->quat, quat);
2125 else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
2126 float axis[3], angle;
2128 /* calculate the total rotatation */
2129 axis_angle_to_mat3(obmat, td->ext->irotAxis, td->ext->irotAngle);
2131 mul_m3_m3m3(obmat, dmat, obmat);
2134 /* mat = transform, obmat = object rotation */
2135 mul_m3_m3m3(fmat, smat, obmat);
2138 mul_m3_m3m3(fmat, dmat_inv, fmat);
2141 mat3_to_axis_angle(axis, &angle, fmat);
2144 copy_v3_v3(td->ext->rotAxis, axis);
2145 *td->ext->rotAngle = angle;
2150 /* calculate the total rotatation */
2151 eulO_to_mat3(obmat, td->ext->irot, td->ext->rotOrder);
2153 mul_m3_m3m3(obmat, dmat, obmat);
2156 /* mat = transform, obmat = object rotation */
2157 mul_m3_m3m3(fmat, smat, obmat);
2160 mul_m3_m3m3(fmat, dmat_inv, fmat);
2163 mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
2166 copy_v3_v3(td->ext->rot, eul);