Transform: fix rotate redo behavior
[blender.git] / source / blender / editors / transform / transform_generics.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edtransform
22  */
23
24 #include <string.h>
25 #include <math.h>
26
27 #include "MEM_guardedalloc.h"
28
29 #include "BLI_sys_types.h" /* for intptr_t support */
30
31 #include "DNA_anim_types.h"
32 #include "DNA_armature_types.h"
33 #include "DNA_brush_types.h"
34 #include "DNA_gpencil_types.h"
35 #include "DNA_lattice_types.h"
36 #include "DNA_screen_types.h"
37 #include "DNA_sequence_types.h"
38 #include "DNA_space_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_mesh_types.h"
42 #include "DNA_view3d_types.h"
43 #include "DNA_modifier_types.h"
44 #include "DNA_movieclip_types.h"
45 #include "DNA_mask_types.h"
46 #include "DNA_meta_types.h"
47
48 #include "BLI_math.h"
49 #include "BLI_blenlib.h"
50 #include "BLI_rand.h"
51 #include "BLI_utildefines.h"
52
53 #include "PIL_time.h"
54
55 #include "BLT_translation.h"
56
57 #include "RNA_access.h"
58
59 #include "GPU_immediate.h"
60 #include "GPU_matrix.h"
61
62 #include "BIK_api.h"
63
64 #include "BKE_action.h"
65 #include "BKE_animsys.h"
66 #include "BKE_armature.h"
67 #include "BKE_context.h"
68 #include "BKE_curve.h"
69 #include "BKE_editmesh.h"
70 #include "BKE_fcurve.h"
71 #include "BKE_gpencil.h"
72 #include "BKE_lattice.h"
73 #include "BKE_layer.h"
74 #include "BKE_library.h"
75 #include "BKE_mask.h"
76 #include "BKE_nla.h"
77 #include "BKE_paint.h"
78 #include "BKE_scene.h"
79 #include "BKE_sequencer.h"
80 #include "BKE_tracking.h"
81 #include "BKE_workspace.h"
82
83 #include "DEG_depsgraph.h"
84
85 #include "ED_anim_api.h"
86 #include "ED_armature.h"
87 #include "ED_image.h"
88 #include "ED_keyframing.h"
89 #include "ED_markers.h"
90 #include "ED_mesh.h"
91 #include "ED_object.h"
92 #include "ED_particle.h"
93 #include "ED_screen_types.h"
94 #include "ED_space_api.h"
95 #include "ED_uvedit.h"
96 #include "ED_view3d.h"
97 #include "ED_curve.h" /* for curve_editnurbs */
98 #include "ED_clip.h"
99 #include "ED_screen.h"
100 #include "ED_gpencil.h"
101
102 #include "WM_types.h"
103 #include "WM_api.h"
104
105 #include "RE_engine.h"
106
107 #include "UI_resources.h"
108 #include "UI_view2d.h"
109
110 #include "transform.h"
111
112 /* ************************** Functions *************************** */
113
114 void getViewVector(const TransInfo *t, const float coord[3], float vec[3])
115 {
116         if (t->persp != RV3D_ORTHO) {
117                 sub_v3_v3v3(vec, coord, t->viewinv[3]);
118         }
119         else {
120                 copy_v3_v3(vec, t->viewinv[2]);
121         }
122         normalize_v3(vec);
123 }
124
125 /* ************************** GENERICS **************************** */
126
127
128 static void clipMirrorModifier(TransInfo *t)
129 {
130         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
131                 Object *ob = tc->obedit;
132                 ModifierData *md = ob->modifiers.first;
133                 float tolerance[3] = {0.0f, 0.0f, 0.0f};
134                 int axis = 0;
135
136                 for (; md; md = md->next) {
137                         if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
138                                 MirrorModifierData *mmd = (MirrorModifierData *) md;
139
140                                 if (mmd->flag & MOD_MIR_CLIPPING) {
141                                         axis = 0;
142                                         if (mmd->flag & MOD_MIR_AXIS_X) {
143                                                 axis |= 1;
144                                                 tolerance[0] = mmd->tolerance;
145                                         }
146                                         if (mmd->flag & MOD_MIR_AXIS_Y) {
147                                                 axis |= 2;
148                                                 tolerance[1] = mmd->tolerance;
149                                         }
150                                         if (mmd->flag & MOD_MIR_AXIS_Z) {
151                                                 axis |= 4;
152                                                 tolerance[2] = mmd->tolerance;
153                                         }
154                                         if (axis) {
155                                                 float mtx[4][4], imtx[4][4];
156                                                 int i;
157
158                                                 if (mmd->mirror_ob) {
159                                                         float obinv[4][4];
160
161                                                         invert_m4_m4(obinv, mmd->mirror_ob->obmat);
162                                                         mul_m4_m4m4(mtx, obinv, ob->obmat);
163                                                         invert_m4_m4(imtx, mtx);
164                                                 }
165
166                                                 TransData *td = tc->data;
167                                                 for (i = 0; i < tc->data_len; i++, td++) {
168                                                         int clip;
169                                                         float loc[3], iloc[3];
170
171                                                         if (td->flag & TD_NOACTION)
172                                                                 break;
173                                                         if (td->loc == NULL)
174                                                                 break;
175
176                                                         if (td->flag & TD_SKIP)
177                                                                 continue;
178
179                                                         copy_v3_v3(loc,  td->loc);
180                                                         copy_v3_v3(iloc, td->iloc);
181
182                                                         if (mmd->mirror_ob) {
183                                                                 mul_m4_v3(mtx, loc);
184                                                                 mul_m4_v3(mtx, iloc);
185                                                         }
186
187                                                         clip = 0;
188                                                         if (axis & 1) {
189                                                                 if (fabsf(iloc[0]) <= tolerance[0] ||
190                                                                     loc[0] * iloc[0] < 0.0f)
191                                                                 {
192                                                                         loc[0] = 0.0f;
193                                                                         clip = 1;
194                                                                 }
195                                                         }
196
197                                                         if (axis & 2) {
198                                                                 if (fabsf(iloc[1]) <= tolerance[1] ||
199                                                                     loc[1] * iloc[1] < 0.0f)
200                                                                 {
201                                                                         loc[1] = 0.0f;
202                                                                         clip = 1;
203                                                                 }
204                                                         }
205                                                         if (axis & 4) {
206                                                                 if (fabsf(iloc[2]) <= tolerance[2] ||
207                                                                     loc[2] * iloc[2] < 0.0f)
208                                                                 {
209                                                                         loc[2] = 0.0f;
210                                                                         clip = 1;
211                                                                 }
212                                                         }
213                                                         if (clip) {
214                                                                 if (mmd->mirror_ob) {
215                                                                         mul_m4_v3(imtx, loc);
216                                                                 }
217                                                                 copy_v3_v3(td->loc, loc);
218                                                         }
219                                                 }
220                                         }
221
222                                 }
223                         }
224                 }
225         }
226 }
227
228 /* assumes obedit set to mesh object */
229 static void editbmesh_apply_to_mirror(TransInfo *t)
230 {
231         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
232                 if (tc->mirror.axis_flag) {
233                         TransData *td = tc->data;
234                         BMVert *eve;
235                         int i;
236
237                         for (i = 0; i < tc->data_len; i++, td++) {
238                                 if (td->flag & TD_NOACTION)
239                                         break;
240                                 if (td->loc == NULL)
241                                         break;
242                                 if (td->flag & TD_SKIP)
243                                         continue;
244
245                                 eve = td->extra;
246                                 if (eve) {
247                                         eve->co[0] = -td->loc[0];
248                                         eve->co[1] = td->loc[1];
249                                         eve->co[2] = td->loc[2];
250                                 }
251
252                                 if (td->flag & TD_MIRROR_EDGE) {
253                                         td->loc[0] = 0;
254                                 }
255                         }
256                 }
257         }
258 }
259
260 /* for the realtime animation recording feature, handle overlapping data */
261 static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer)
262 {
263         ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL;
264
265         /* sanity checks */
266         if (ELEM(NULL, scene, id, sad))
267                 return;
268
269         /* check if we need a new strip if:
270          * - if animtimer is running
271          * - we're not only keying for available channels
272          * - the option to add new actions for each round is not enabled
273          */
274         if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL) == 0 && (scene->toolsettings->autokey_flag & ANIMRECORD_FLAG_WITHNLA)) {
275                 /* if playback has just looped around,
276                  * we need to add a new NLA track+strip to allow a clean pass to occur */
277                 if ((sad) && (sad->flag & ANIMPLAY_FLAG_JUMPED)) {
278                         AnimData *adt = BKE_animdata_from_id(id);
279                         const bool is_first = (adt) && (adt->nla_tracks.first == NULL);
280
281                         /* perform push-down manually with some differences
282                          * NOTE: BKE_nla_action_pushdown() sync warning...
283                          */
284                         if ((adt->action) && !(adt->flag & ADT_NLA_EDIT_ON)) {
285                                 float astart, aend;
286
287                                 /* only push down if action is more than 1-2 frames long */
288                                 calc_action_range(adt->action, &astart, &aend, 1);
289                                 if (aend > astart + 2.0f) {
290                                         NlaStrip *strip = BKE_nlastack_add_strip(adt, adt->action);
291
292                                         /* clear reference to action now that we've pushed it onto the stack */
293                                         id_us_min(&adt->action->id);
294                                         adt->action = NULL;
295
296                                         /* adjust blending + extend so that they will behave correctly */
297                                         strip->extendmode = NLASTRIP_EXTEND_NOTHING;
298                                         strip->flag &= ~(NLASTRIP_FLAG_AUTO_BLENDS | NLASTRIP_FLAG_SELECT | NLASTRIP_FLAG_ACTIVE);
299
300                                         /* copy current "action blending" settings from adt to the strip,
301                                          * as it was keyframed with these settings, so omitting them will
302                                          * change the effect  [T54766]
303                                          */
304                                         if (is_first == false) {
305                                                 strip->blendmode = adt->act_blendmode;
306                                                 strip->influence = adt->act_influence;
307
308                                                 if (adt->act_influence < 1.0f) {
309                                                         /* enable "user-controlled" influence (which will insert a default keyframe)
310                                                          * so that the influence doesn't get lost on the new update
311                                                          *
312                                                          * NOTE: An alternative way would have been to instead hack the influence
313                                                          * to not get always get reset to full strength if NLASTRIP_FLAG_USR_INFLUENCE
314                                                          * is disabled but auto-blending isn't being used. However, that approach
315                                                          * is a bit hacky/hard to discover, and may cause backwards compatibility issues,
316                                                          * so it's better to just do it this way.
317                                                          */
318                                                         strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
319                                                         BKE_nlastrip_validate_fcurves(strip);
320                                                 }
321                                         }
322
323                                         /* also, adjust the AnimData's action extend mode to be on
324                                          * 'nothing' so that previous result still play
325                                          */
326                                         adt->act_extendmode = NLASTRIP_EXTEND_NOTHING;
327                                 }
328                         }
329                 }
330         }
331 }
332
333 static bool fcu_test_selected(FCurve *fcu)
334 {
335         BezTriple *bezt = fcu->bezt;
336         unsigned int i;
337
338         if (bezt == NULL) /* ignore baked */
339                 return 0;
340
341         for (i = 0; i < fcu->totvert; i++, bezt++) {
342                 if (BEZT_ISSEL_ANY(bezt)) return 1;
343         }
344
345         return 0;
346 }
347
348 /* helper for recalcData() - for Action Editor transforms */
349 static void recalcData_actedit(TransInfo *t)
350 {
351         ViewLayer *view_layer = t->view_layer;
352         SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
353
354         bAnimContext ac = {NULL};
355         ListBase anim_data = {NULL, NULL};
356         bAnimListElem *ale;
357         int filter;
358
359         /* initialize relevant anim-context 'context' data from TransInfo data */
360         /* NOTE: sync this with the code in ANIM_animdata_get_context() */
361         ac.bmain = CTX_data_main(t->context);
362         ac.scene = t->scene;
363         ac.view_layer = t->view_layer;
364         ac.obact = OBACT(view_layer);
365         ac.sa = t->sa;
366         ac.ar = t->ar;
367         ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
368         ac.spacetype = (t->sa) ? t->sa->spacetype : 0;
369         ac.regiontype = (t->ar) ? t->ar->regiontype : 0;
370
371         ANIM_animdata_context_getdata(&ac);
372
373         /* perform flush */
374         if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
375                 /* flush transform values back to actual coordinates */
376                 flushTransIntFrameActionData(t);
377         }
378
379         if (ac.datatype != ANIMCONT_MASK) {
380                 /* get animdata blocks visible in editor, assuming that these will be the ones where things changed */
381                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
382                 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
383
384                 /* just tag these animdata-blocks to recalc, assuming that some data there changed
385                  * BUT only do this if realtime updates are enabled
386                  */
387                 if ((saction->flag & SACTION_NOREALTIMEUPDATES) == 0) {
388                         for (ale = anim_data.first; ale; ale = ale->next) {
389                                 /* set refresh tags for objects using this animation */
390                                 ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale);
391                         }
392                 }
393
394                 /* now free temp channels */
395                 ANIM_animdata_freelist(&anim_data);
396         }
397 }
398 /* helper for recalcData() - for Graph Editor transforms */
399 static void recalcData_graphedit(TransInfo *t)
400 {
401         SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
402         ViewLayer *view_layer = t->view_layer;
403
404         ListBase anim_data = {NULL, NULL};
405         bAnimContext ac = {NULL};
406         int filter;
407
408         bAnimListElem *ale;
409         int dosort = 0;
410
411         /* initialize relevant anim-context 'context' data from TransInfo data */
412         /* NOTE: sync this with the code in ANIM_animdata_get_context() */
413         ac.bmain = CTX_data_main(t->context);
414         ac.scene = t->scene;
415         ac.view_layer = t->view_layer;
416         ac.obact = OBACT(view_layer);
417         ac.sa = t->sa;
418         ac.ar = t->ar;
419         ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
420         ac.spacetype = (t->sa) ? t->sa->spacetype : 0;
421         ac.regiontype = (t->ar) ? t->ar->regiontype : 0;
422
423         ANIM_animdata_context_getdata(&ac);
424
425         /* do the flush first */
426         flushTransGraphData(t);
427
428         /* get curves to check if a re-sort is needed */
429         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
430         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
431
432         /* now test if there is a need to re-sort */
433         for (ale = anim_data.first; ale; ale = ale->next) {
434                 FCurve *fcu = (FCurve *)ale->key_data;
435
436                 /* ignore FC-Curves without any selected verts */
437                 if (!fcu_test_selected(fcu))
438                         continue;
439
440                 /* watch it: if the time is wrong: do not correct handles yet */
441                 if (test_time_fcurve(fcu))
442                         dosort++;
443                 else
444                         calchandles_fcurve(fcu);
445
446                 /* set refresh tags for objects using this animation,
447                  * BUT only if realtime updates are enabled
448                  */
449                 if ((sipo->flag & SIPO_NOREALTIMEUPDATES) == 0)
450                         ANIM_list_elem_update(CTX_data_main(t->context), t->scene, ale);
451         }
452
453         /* do resort and other updates? */
454         if (dosort) remake_graph_transdata(t, &anim_data);
455
456         /* now free temp channels */
457         ANIM_animdata_freelist(&anim_data);
458 }
459
460 /* helper for recalcData() - for NLA Editor transforms */
461 static void recalcData_nla(TransInfo *t)
462 {
463         SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first;
464         Scene *scene = t->scene;
465         double secf = FPS;
466         int i;
467
468         TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
469         TransDataNla *tdn = tc->custom.type.data;
470
471         /* for each strip we've got, perform some additional validation of the values that got set before
472          * using RNA to set the value (which does some special operations when setting these values to make
473          * sure that everything works ok)
474          */
475         for (i = 0; i < tc->data_len; i++, tdn++) {
476                 NlaStrip *strip = tdn->strip;
477                 PointerRNA strip_ptr;
478                 short pExceeded, nExceeded, iter;
479                 int delta_y1, delta_y2;
480
481                 /* if this tdn has no handles, that means it is just a dummy that should be skipped */
482                 if (tdn->handle == 0)
483                         continue;
484
485                 /* set refresh tags for objects using this animation,
486                  * BUT only if realtime updates are enabled
487                  */
488                 if ((snla->flag & SNLA_NOREALTIMEUPDATES) == 0)
489                         ANIM_id_update(CTX_data_main(t->context), tdn->id);
490
491                 /* if canceling transform, just write the values without validating, then move on */
492                 if (t->state == TRANS_CANCEL) {
493                         /* clear the values by directly overwriting the originals, but also need to restore
494                          * endpoints of neighboring transition-strips
495                          */
496
497                         /* start */
498                         strip->start = tdn->h1[0];
499
500                         if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION))
501                                 strip->prev->end = tdn->h1[0];
502
503                         /* end */
504                         strip->end = tdn->h2[0];
505
506                         if ((strip->next) && (strip->next->type == NLASTRIP_TYPE_TRANSITION))
507                                 strip->next->start = tdn->h2[0];
508
509                         /* flush transforms to child strips (since this should be a meta) */
510                         BKE_nlameta_flush_transforms(strip);
511
512                         /* restore to original track (if needed) */
513                         if (tdn->oldTrack != tdn->nlt) {
514                                 /* just append to end of list for now, since strips get sorted in special_aftertrans_update() */
515                                 BLI_remlink(&tdn->nlt->strips, strip);
516                                 BLI_addtail(&tdn->oldTrack->strips, strip);
517                         }
518
519                         continue;
520                 }
521
522                 /* firstly, check if the proposed transform locations would overlap with any neighboring strips
523                  * (barring transitions) which are absolute barriers since they are not being moved
524                  *
525                  * this is done as a iterative procedure (done 5 times max for now)
526                  */
527                 for (iter = 0; iter < 5; iter++) {
528                         pExceeded = ((strip->prev) && (strip->prev->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h1[0] < strip->prev->end));
529                         nExceeded = ((strip->next) && (strip->next->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h2[0] > strip->next->start));
530
531                         if ((pExceeded && nExceeded) || (iter == 4)) {
532                                 /* both endpoints exceeded (or iteration ping-pong'd meaning that we need a compromise)
533                                  * - simply crop strip to fit within the bounds of the strips bounding it
534                                  * - if there were no neighbors, clear the transforms (make it default to the strip's current values)
535                                  */
536                                 if (strip->prev && strip->next) {
537                                         tdn->h1[0] = strip->prev->end;
538                                         tdn->h2[0] = strip->next->start;
539                                 }
540                                 else {
541                                         tdn->h1[0] = strip->start;
542                                         tdn->h2[0] = strip->end;
543                                 }
544                         }
545                         else if (nExceeded) {
546                                 /* move backwards */
547                                 float offset = tdn->h2[0] - strip->next->start;
548
549                                 tdn->h1[0] -= offset;
550                                 tdn->h2[0] -= offset;
551                         }
552                         else if (pExceeded) {
553                                 /* more forwards */
554                                 float offset = strip->prev->end - tdn->h1[0];
555
556                                 tdn->h1[0] += offset;
557                                 tdn->h2[0] += offset;
558                         }
559                         else /* all is fine and well */
560                                 break;
561                 }
562
563                 /* handle auto-snapping
564                  * NOTE: only do this when transform is still running, or we can't restore
565                  */
566                 if (t->state != TRANS_CANCEL) {
567                         switch (snla->autosnap) {
568                                 case SACTSNAP_FRAME: /* snap to nearest frame */
569                                 case SACTSNAP_STEP: /* frame step - this is basically the same,
570                                                      * since we don't have any remapping going on */
571                                 {
572                                         tdn->h1[0] = floorf(tdn->h1[0] + 0.5f);
573                                         tdn->h2[0] = floorf(tdn->h2[0] + 0.5f);
574                                         break;
575                                 }
576
577                                 case SACTSNAP_SECOND: /* snap to nearest second */
578                                 case SACTSNAP_TSTEP: /* second step - this is basically the same,
579                                                       * since we don't have any remapping going on */
580                                 {
581                                         /* This case behaves differently from the rest, since lengths of strips
582                                          * may not be multiples of a second. If we just naively resize adjust
583                                          * the handles, things may not work correctly. Instead, we only snap
584                                          * the first handle, and move the other to fit.
585                                          *
586                                          * FIXME: we do run into problems here when user attempts to negatively
587                                          *        scale the strip, as it then just compresses down and refuses
588                                          *        to expand out the other end.
589                                          */
590                                         float h1_new = (float)(floor(((double)tdn->h1[0] / secf) + 0.5) * secf);
591                                         float delta  = h1_new - tdn->h1[0];
592
593                                         tdn->h1[0] = h1_new;
594                                         tdn->h2[0] += delta;
595                                         break;
596                                 }
597
598                                 case SACTSNAP_MARKER: /* snap to nearest marker */
599                                 {
600                                         tdn->h1[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h1[0]);
601                                         tdn->h2[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h2[0]);
602                                         break;
603                                 }
604                         }
605                 }
606
607                 /* Use RNA to write the values to ensure that constraints on these are obeyed
608                  * (e.g. for transition strips, the values are taken from the neighbors)
609                  *
610                  * NOTE: we write these twice to avoid truncation errors which can arise when
611                  * moving the strips a large distance using numeric input [#33852]
612                  */
613                 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
614
615                 RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
616                 RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
617
618                 RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
619                 RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
620
621                 /* flush transforms to child strips (since this should be a meta) */
622                 BKE_nlameta_flush_transforms(strip);
623
624
625                 /* now, check if we need to try and move track
626                  * - we need to calculate both, as only one may have been altered by transform if only 1 handle moved
627                  */
628                 delta_y1 = ((int)tdn->h1[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
629                 delta_y2 = ((int)tdn->h2[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
630
631                 if (delta_y1 || delta_y2) {
632                         NlaTrack *track;
633                         int delta = (delta_y2) ? delta_y2 : delta_y1;
634                         int n;
635
636                         /* move in the requested direction, checking at each layer if there's space for strip to pass through,
637                          * stopping on the last track available or that we're able to fit in
638                          */
639                         if (delta > 0) {
640                                 for (track = tdn->nlt->next, n = 0; (track) && (n < delta); track = track->next, n++) {
641                                         /* check if space in this track for the strip */
642                                         if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
643                                                 /* move strip to this track */
644                                                 BLI_remlink(&tdn->nlt->strips, strip);
645                                                 BKE_nlatrack_add_strip(track, strip);
646
647                                                 tdn->nlt = track;
648                                                 tdn->trackIndex++;
649                                         }
650                                         else /* can't move any further */
651                                                 break;
652                                 }
653                         }
654                         else {
655                                 /* make delta 'positive' before using it, since we now know to go backwards */
656                                 delta = -delta;
657
658                                 for (track = tdn->nlt->prev, n = 0; (track) && (n < delta); track = track->prev, n++) {
659                                         /* check if space in this track for the strip */
660                                         if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
661                                                 /* move strip to this track */
662                                                 BLI_remlink(&tdn->nlt->strips, strip);
663                                                 BKE_nlatrack_add_strip(track, strip);
664
665                                                 tdn->nlt = track;
666                                                 tdn->trackIndex--;
667                                         }
668                                         else /* can't move any further */
669                                                 break;
670                                 }
671                         }
672                 }
673         }
674 }
675
676 static void recalcData_mask_common(TransInfo *t)
677 {
678         Mask *mask = CTX_data_edit_mask(t->context);
679
680         flushTransMasking(t);
681
682         DEG_id_tag_update(&mask->id, 0);
683 }
684
685 /* helper for recalcData() - for Image Editor transforms */
686 static void recalcData_image(TransInfo *t)
687 {
688         if (t->options & CTX_MASK) {
689                 recalcData_mask_common(t);
690         }
691         else if (t->options & CTX_PAINT_CURVE) {
692                 flushTransPaintCurve(t);
693         }
694         else if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
695                 SpaceImage *sima = t->sa->spacedata.first;
696
697                 flushTransUVs(t);
698                 if (sima->flag & SI_LIVE_UNWRAP)
699                         ED_uvedit_live_unwrap_re_solve();
700
701                 FOREACH_TRANS_DATA_CONTAINER (t, tc) {
702                         if (tc->data_len) {
703                                 DEG_id_tag_update(tc->obedit->data, 0);
704                         }
705                 }
706         }
707 }
708
709 /* helper for recalcData() - for Movie Clip transforms */
710 static void recalcData_spaceclip(TransInfo *t)
711 {
712         SpaceClip *sc = t->sa->spacedata.first;
713
714         if (ED_space_clip_check_show_trackedit(sc)) {
715                 MovieClip *clip = ED_space_clip_get_clip(sc);
716                 ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
717                 MovieTrackingTrack *track;
718                 int framenr = ED_space_clip_get_clip_frame_number(sc);
719
720                 flushTransTracking(t);
721
722                 track = tracksbase->first;
723                 while (track) {
724                         if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
725                                 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
726
727                                 if (t->mode == TFM_TRANSLATION) {
728                                         if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT))
729                                                 BKE_tracking_marker_clamp(marker, CLAMP_PAT_POS);
730                                         if (TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH))
731                                                 BKE_tracking_marker_clamp(marker, CLAMP_SEARCH_POS);
732                                 }
733                                 else if (t->mode == TFM_RESIZE) {
734                                         if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT))
735                                                 BKE_tracking_marker_clamp(marker, CLAMP_PAT_DIM);
736                                         if (TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH))
737                                                 BKE_tracking_marker_clamp(marker, CLAMP_SEARCH_DIM);
738                                 }
739                                 else if (t->mode == TFM_ROTATION) {
740                                         if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT))
741                                                 BKE_tracking_marker_clamp(marker, CLAMP_PAT_POS);
742                                 }
743                         }
744
745                         track = track->next;
746                 }
747
748                 DEG_id_tag_update(&clip->id, 0);
749         }
750         else if (t->options & CTX_MASK) {
751                 recalcData_mask_common(t);
752         }
753 }
754
755 /* helper for recalcData() - for object transforms, typically in the 3D view */
756 static void recalcData_objects(TransInfo *t)
757 {
758         Base *base = t->view_layer->basact;
759
760         if (t->obedit_type != -1) {
761                 if (ELEM(t->obedit_type, OB_CURVE, OB_SURF)) {
762
763                         if (t->state != TRANS_CANCEL) {
764                                 clipMirrorModifier(t);
765                                 applyProject(t);
766                         }
767
768                         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
769                                 Curve *cu = tc->obedit->data;
770                                 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
771                                 Nurb *nu = nurbs->first;
772
773                                 DEG_id_tag_update(tc->obedit->data, 0);  /* sets recalc flags */
774
775                                 if (t->state == TRANS_CANCEL) {
776                                         while (nu) {
777                                                 /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
778                                                 BKE_nurb_handles_calc(nu);
779                                                 nu = nu->next;
780                                         }
781                                 }
782                                 else {
783                                         /* Normal updating */
784                                         while (nu) {
785                                                 BKE_nurb_test_2d(nu);
786                                                 BKE_nurb_handles_calc(nu);
787                                                 nu = nu->next;
788                                         }
789                                 }
790                         }
791                 }
792                 else if (t->obedit_type == OB_LATTICE) {
793
794                         if (t->state != TRANS_CANCEL) {
795                                 applyProject(t);
796                         }
797
798                         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
799                                 Lattice *la = tc->obedit->data;
800                                 DEG_id_tag_update(tc->obedit->data, 0);  /* sets recalc flags */
801                                 if (la->editlatt->latt->flag & LT_OUTSIDE) {
802                                         outside_lattice(la->editlatt->latt);
803                                 }
804                         }
805                 }
806                 else if (t->obedit_type == OB_MESH) {
807                         /* mirror modifier clipping? */
808                         if (t->state != TRANS_CANCEL) {
809                                 /* apply clipping after so we never project past the clip plane [#25423] */
810                                 applyProject(t);
811                                 clipMirrorModifier(t);
812                         }
813                         if ((t->flag & T_NO_MIRROR) == 0 &&
814                             (t->options & CTX_NO_MIRROR) == 0)
815                         {
816                                 editbmesh_apply_to_mirror(t);
817                         }
818
819                         if (t->mode == TFM_EDGE_SLIDE) {
820                                 projectEdgeSlideData(t, false);
821                         }
822                         else if (t->mode == TFM_VERT_SLIDE) {
823                                 projectVertSlideData(t, false);
824                         }
825
826                         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
827                                 DEG_id_tag_update(tc->obedit->data, 0);  /* sets recalc flags */
828                                 BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
829                                 EDBM_mesh_normals_update(em);
830                                 BKE_editmesh_tessface_calc(em);
831                         }
832                 }
833                 else if (t->obedit_type == OB_ARMATURE) { /* no recalc flag, does pose */
834
835                         if (t->state != TRANS_CANCEL) {
836                                 applyProject(t);
837                         }
838
839                         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
840                                 bArmature *arm = tc->obedit->data;
841                                 ListBase *edbo = arm->edbo;
842                                 EditBone *ebo, *ebo_parent;
843                                 TransData *td = tc->data;
844                                 int i;
845
846                                 /* Ensure all bones are correctly adjusted */
847                                 for (ebo = edbo->first; ebo; ebo = ebo->next) {
848                                         ebo_parent = (ebo->flag & BONE_CONNECTED) ? ebo->parent : NULL;
849
850                                         if (ebo_parent) {
851                                                 /* If this bone has a parent tip that has been moved */
852                                                 if (ebo_parent->flag & BONE_TIPSEL) {
853                                                         copy_v3_v3(ebo->head, ebo_parent->tail);
854                                                         if (t->mode == TFM_BONE_ENVELOPE) ebo->rad_head = ebo_parent->rad_tail;
855                                                 }
856                                                 /* If this bone has a parent tip that has NOT been moved */
857                                                 else {
858                                                         copy_v3_v3(ebo_parent->tail, ebo->head);
859                                                         if (t->mode == TFM_BONE_ENVELOPE) ebo_parent->rad_tail = ebo->rad_head;
860                                                 }
861                                         }
862
863                                         /* on extrude bones, oldlength==0.0f, so we scale radius of points */
864                                         ebo->length = len_v3v3(ebo->head, ebo->tail);
865                                         if (ebo->oldlength == 0.0f) {
866                                                 ebo->rad_head = 0.25f * ebo->length;
867                                                 ebo->rad_tail = 0.10f * ebo->length;
868                                                 ebo->dist = 0.25f * ebo->length;
869                                                 if (ebo->parent) {
870                                                         if (ebo->rad_head > ebo->parent->rad_tail)
871                                                                 ebo->rad_head = ebo->parent->rad_tail;
872                                                 }
873                                         }
874                                         else if (t->mode != TFM_BONE_ENVELOPE) {
875                                                 /* if bones change length, lets do that for the deform distance as well */
876                                                 ebo->dist *= ebo->length / ebo->oldlength;
877                                                 ebo->rad_head *= ebo->length / ebo->oldlength;
878                                                 ebo->rad_tail *= ebo->length / ebo->oldlength;
879                                                 ebo->oldlength = ebo->length;
880
881                                                 if (ebo_parent) {
882                                                         ebo_parent->rad_tail = ebo->rad_head;
883                                                 }
884                                         }
885                                 }
886
887                                 if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONE_ENVELOPE_DIST, TFM_BONESIZE)) {
888                                         /* fix roll */
889                                         for (i = 0; i < tc->data_len; i++, td++) {
890                                                 if (td->extra) {
891                                                         float vec[3], up_axis[3];
892                                                         float qrot[4];
893                                                         float roll;
894
895                                                         ebo = td->extra;
896
897                                                         if (t->state == TRANS_CANCEL) {
898                                                                 /* restore roll */
899                                                                 ebo->roll = td->ival;
900                                                         }
901                                                         else {
902                                                                 copy_v3_v3(up_axis, td->axismtx[2]);
903
904                                                                 sub_v3_v3v3(vec, ebo->tail, ebo->head);
905                                                                 normalize_v3(vec);
906                                                                 rotation_between_vecs_to_quat(qrot, td->axismtx[1], vec);
907                                                                 mul_qt_v3(qrot, up_axis);
908
909                                                                 /* roll has a tendency to flip in certain orientations - [#34283], [#33974] */
910                                                                 roll = ED_armature_ebone_roll_to_vector(ebo, up_axis, false);
911                                                                 ebo->roll = angle_compat_rad(roll, td->ival);
912                                                         }
913                                                 }
914                                         }
915                                 }
916
917                                 if (arm->flag & ARM_MIRROR_EDIT) {
918                                         if (t->state != TRANS_CANCEL) {
919                                                 ED_armature_edit_transform_mirror_update(tc->obedit);
920                                         }
921                                         else {
922                                                 restoreBones(tc);
923                                         }
924                                 }
925                         }
926                 }
927                 else {
928                         if (t->state != TRANS_CANCEL) {
929                                 applyProject(t);
930                         }
931                         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
932                                 if (tc->data_len) {
933                                         DEG_id_tag_update(tc->obedit->data, 0);  /* sets recalc flags */
934                                 }
935                         }
936                 }
937
938         }
939         else if (t->flag & T_POSE) {
940                 GSet *motionpath_updates = BLI_gset_ptr_new("motionpath updates");
941
942                 FOREACH_TRANS_DATA_CONTAINER (t, tc) {
943                         Object *ob = tc->poseobj;
944                         bArmature *arm = ob->data;
945
946                         /* if animtimer is running, and the object already has animation data,
947                          * check if the auto-record feature means that we should record 'samples'
948                          * (i.e. uneditable animation values)
949                          *
950                          * context is needed for keying set poll() functions.
951                          */
952                         // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
953                         if ((t->animtimer) && (t->context) && IS_AUTOKEY_ON(t->scene)) {
954                                 int targetless_ik = (t->flag & T_AUTOIK); // XXX this currently doesn't work, since flags aren't set yet!
955
956                                 animrecord_check_state(t->scene, &ob->id, t->animtimer);
957                                 autokeyframe_pose(t->context, t->scene, ob, t->mode, targetless_ik);
958                         }
959
960                         if (motionpath_need_update_pose(t->scene, ob)) {
961                                 BLI_gset_insert(motionpath_updates, ob);
962                         }
963
964                         /* old optimize trick... this enforces to bypass the depgraph */
965                         if (!(arm->flag & ARM_DELAYDEFORM)) {
966                                 DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);  /* sets recalc flags */
967                                 /* transformation of pose may affect IK tree, make sure it is rebuilt */
968                                 BIK_clear_data(ob->pose);
969                         }
970                         else {
971                                 BKE_pose_where_is(t->depsgraph, t->scene, ob);
972                         }
973                 }
974
975                 /* Update motion paths once for all transformed bones in an object. */
976                 GSetIterator gs_iter;
977                 GSET_ITER (gs_iter, motionpath_updates) {
978                         Object *ob = BLI_gsetIterator_getKey(&gs_iter);
979                         ED_pose_recalculate_paths(t->context, t->scene, ob, true);
980                 }
981                 BLI_gset_free(motionpath_updates, NULL);
982         }
983         else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) &&
984                  PE_get_current(t->scene, base->object))
985         {
986                 if (t->state != TRANS_CANCEL) {
987                         applyProject(t);
988                 }
989                 flushTransParticles(t);
990         }
991         else {
992                 bool motionpath_update = false;
993
994                 if (t->state != TRANS_CANCEL) {
995                         applyProject(t);
996                 }
997
998                 FOREACH_TRANS_DATA_CONTAINER (t, tc) {
999                         TransData *td = tc->data;
1000
1001                         for (int i = 0; i < tc->data_len; i++, td++) {
1002                                 Object *ob = td->ob;
1003
1004                                 if (td->flag & TD_NOACTION)
1005                                         break;
1006
1007                                 if (td->flag & TD_SKIP)
1008                                         continue;
1009
1010                                 /* if animtimer is running, and the object already has animation data,
1011                                  * check if the auto-record feature means that we should record 'samples'
1012                                  * (i.e. uneditable animation values)
1013                                  */
1014                                 // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
1015                                 if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
1016                                         animrecord_check_state(t->scene, &ob->id, t->animtimer);
1017                                         autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
1018                                 }
1019
1020                                 motionpath_update |= motionpath_need_update_object(t->scene, ob);
1021
1022                                 /* sets recalc flags fully, instead of flushing existing ones
1023                                  * otherwise proxies don't function correctly
1024                                  */
1025                                 DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
1026
1027                                 if (t->flag & T_TEXTURE)
1028                                         DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
1029                         }
1030                 }
1031
1032                 if (motionpath_update) {
1033                         /* Update motion paths once for all transformed objects. */
1034                         ED_objects_recalculate_paths(t->context, t->scene, true);
1035                 }
1036         }
1037 }
1038
1039 static void recalcData_cursor(TransInfo *t)
1040 {
1041         DEG_id_tag_update(&t->scene->id, ID_RECALC_COPY_ON_WRITE);
1042 }
1043
1044 /* helper for recalcData() - for sequencer transforms */
1045 static void recalcData_sequencer(TransInfo *t)
1046 {
1047         TransData *td;
1048         int a;
1049         Sequence *seq_prev = NULL;
1050
1051         TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
1052
1053         for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
1054                 TransDataSeq *tdsq = (TransDataSeq *) td->extra;
1055                 Sequence *seq = tdsq->seq;
1056
1057                 if (seq != seq_prev) {
1058                         if (BKE_sequence_tx_fullupdate_test(seq)) {
1059                                 /* A few effect strip types need a complete recache on transform. */
1060                                 BKE_sequence_invalidate_cache(t->scene, seq);
1061                         }
1062                         else {
1063                                 BKE_sequence_invalidate_dependent(t->scene, seq);
1064                         }
1065                 }
1066
1067                 seq_prev = seq;
1068         }
1069
1070         BKE_sequencer_preprocessed_cache_cleanup();
1071
1072         flushTransSeq(t);
1073 }
1074
1075 /* force recalculation of triangles during transformation */
1076 static void recalcData_gpencil_strokes(TransInfo *t)
1077 {
1078         TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
1079
1080         TransData *td = tc->data;
1081         for (int i = 0; i < tc->data_len; i++, td++) {
1082                 bGPDstroke *gps = td->extra;
1083                 if (gps != NULL) {
1084                         gps->flag |= GP_STROKE_RECALC_GEOMETRY;
1085                 }
1086         }
1087 }
1088
1089 /* called for updating while transform acts, once per redraw */
1090 void recalcData(TransInfo *t)
1091 {
1092         /* if tests must match createTransData for correct updates */
1093         if (t->options & CTX_CURSOR) {
1094                 recalcData_cursor(t);
1095         }
1096         else if (t->options & CTX_TEXTURE) {
1097                 recalcData_objects(t);
1098         }
1099         else if (t->options & CTX_EDGE) {
1100                 recalcData_objects(t);
1101         }
1102         else if (t->options & CTX_PAINT_CURVE) {
1103                 flushTransPaintCurve(t);
1104         }
1105         else if (t->options & CTX_GPENCIL_STROKES) {
1106                 /* set recalc triangle cache flag */
1107                 recalcData_gpencil_strokes(t);
1108         }
1109         else if (t->spacetype == SPACE_IMAGE) {
1110                 recalcData_image(t);
1111         }
1112         else if (t->spacetype == SPACE_ACTION) {
1113                 recalcData_actedit(t);
1114         }
1115         else if (t->spacetype == SPACE_NLA) {
1116                 recalcData_nla(t);
1117         }
1118         else if (t->spacetype == SPACE_SEQ) {
1119                 recalcData_sequencer(t);
1120         }
1121         else if (t->spacetype == SPACE_GRAPH) {
1122                 recalcData_graphedit(t);
1123         }
1124         else if (t->spacetype == SPACE_NODE) {
1125                 flushTransNodes(t);
1126         }
1127         else if (t->spacetype == SPACE_CLIP) {
1128                 recalcData_spaceclip(t);
1129         }
1130         else {
1131                 recalcData_objects(t);
1132         }
1133 }
1134
1135 void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis, short options)
1136 {
1137         float v1[3], v2[3], v3[3];
1138         unsigned char col[3], col2[3];
1139
1140         if (t->spacetype == SPACE_VIEW3D) {
1141                 View3D *v3d = t->view;
1142
1143                 GPU_matrix_push();
1144
1145                 copy_v3_v3(v3, dir);
1146                 mul_v3_fl(v3, v3d->clip_end);
1147
1148                 sub_v3_v3v3(v2, center, v3);
1149                 add_v3_v3v3(v1, center, v3);
1150
1151                 if (options & DRAWLIGHT) {
1152                         col[0] = col[1] = col[2] = 220;
1153                 }
1154                 else {
1155                         UI_GetThemeColor3ubv(TH_GRID, col);
1156                 }
1157                 UI_make_axis_color(col, col2, axis);
1158
1159                 uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1160
1161                 immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
1162                 immUniformColor3ubv(col2);
1163
1164                 immBegin(GPU_PRIM_LINES, 2);
1165                 immVertex3fv(pos, v1);
1166                 immVertex3fv(pos, v2);
1167                 immEnd();
1168
1169                 immUnbindProgram();
1170
1171                 GPU_matrix_pop();
1172         }
1173 }
1174
1175 /**
1176  * Free data before switching to another mode.
1177  */
1178 void resetTransModal(TransInfo *t)
1179 {
1180         freeTransCustomDataForMode(t);
1181 }
1182
1183 void resetTransRestrictions(TransInfo *t)
1184 {
1185         t->flag &= ~T_ALL_RESTRICTIONS;
1186 }
1187
1188 static int initTransInfo_edit_pet_to_flag(const int proportional)
1189 {
1190         switch (proportional) {
1191                 case PROP_EDIT_ON:
1192                         return T_PROP_EDIT;
1193                 case PROP_EDIT_CONNECTED:
1194                         return T_PROP_EDIT | T_PROP_CONNECTED;
1195                 case PROP_EDIT_PROJECTED:
1196                         return T_PROP_EDIT | T_PROP_PROJECTED;
1197                 default:
1198                         return 0;
1199         }
1200 }
1201
1202 void initTransDataContainers_FromObjectData(TransInfo *t, Object *obact, Object **objects, uint objects_len)
1203 {
1204         const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
1205         const short object_type = obact ? obact->type : -1;
1206
1207         if ((object_mode & OB_MODE_EDIT) || (t->options & CTX_GPENCIL_STROKES) ||
1208             ((object_mode & OB_MODE_POSE) && (object_type == OB_ARMATURE)))
1209         {
1210                 if (t->data_container) {
1211                         MEM_freeN(t->data_container);
1212                 }
1213
1214                 bool free_objects = false;
1215                 if (objects == NULL) {
1216                         objects = BKE_view_layer_array_from_objects_in_mode(
1217                                 t->view_layer,
1218                                 (t->spacetype == SPACE_VIEW3D) ? t->view : NULL,
1219                                 &objects_len, {
1220                                     .object_mode = object_mode,
1221                                     .no_dup_data = true,
1222                                 });
1223                         free_objects = true;
1224                 }
1225
1226                 t->data_container = MEM_callocN(sizeof(*t->data_container) * objects_len, __func__);
1227                 t->data_container_len = objects_len;
1228
1229                 for (int i = 0; i < objects_len; i++) {
1230                         TransDataContainer *tc = &t->data_container[i];
1231                         /* TODO, multiple axes. */
1232                         tc->mirror.axis_flag = (
1233                                 ((t->flag & T_NO_MIRROR) == 0) &&
1234                                 ((t->options & CTX_NO_MIRROR) == 0) &&
1235                                 (objects[i]->type == OB_MESH) &&
1236                                 (((Mesh *)objects[i]->data)->editflag & ME_EDIT_MIRROR_X) != 0);
1237
1238                         if (object_mode & OB_MODE_EDIT) {
1239                                 tc->obedit = objects[i];
1240                                 /* Check needed for UV's */
1241                                 if ((t->flag & T_2D_EDIT) == 0) {
1242                                         tc->use_local_mat = true;
1243                                 }
1244                         }
1245                         else if (object_mode & OB_MODE_POSE) {
1246                                 tc->poseobj = objects[i];
1247                                 tc->use_local_mat = true;
1248                         }
1249                         else if (t->options & CTX_GPENCIL_STROKES) {
1250                                 tc->use_local_mat = true;
1251                         }
1252
1253                         if (tc->use_local_mat) {
1254                                 BLI_assert((t->flag & T_2D_EDIT) == 0);
1255                                 copy_m4_m4(tc->mat, objects[i]->obmat);
1256                                 copy_m3_m4(tc->mat3, tc->mat);
1257                                 invert_m4_m4(tc->imat, tc->mat);
1258                                 invert_m3_m3(tc->imat3, tc->mat3);
1259                                 normalize_m3_m3(tc->mat3_unit, tc->mat3);
1260                         }
1261                         /* Otherwise leave as zero. */
1262                 }
1263
1264                 if (free_objects) {
1265                         MEM_freeN(objects);
1266                 }
1267         }
1268 }
1269
1270 /**
1271  * Setup internal data, mouse, vectors
1272  *
1273  * \note \a op and \a event can be NULL
1274  *
1275  * \see #saveTransform does the reverse.
1276  */
1277 void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
1278 {
1279         Depsgraph *depsgraph = CTX_data_depsgraph(C);
1280         Scene *sce = CTX_data_scene(C);
1281         ViewLayer *view_layer = CTX_data_view_layer(C);
1282         const eObjectMode object_mode = OBACT(view_layer) ? OBACT(view_layer)->mode : OB_MODE_OBJECT;
1283         const short object_type = OBACT(view_layer) ? OBACT(view_layer)->type : -1;
1284         ToolSettings *ts = CTX_data_tool_settings(C);
1285         ARegion *ar = CTX_wm_region(C);
1286         ScrArea *sa = CTX_wm_area(C);
1287
1288         bGPdata *gpd = CTX_data_gpencil_data(C);
1289         PropertyRNA *prop;
1290
1291         t->depsgraph = depsgraph;
1292         t->scene = sce;
1293         t->view_layer = view_layer;
1294         t->sa = sa;
1295         t->ar = ar;
1296         t->settings = ts;
1297         t->reports = op ? op->reports : NULL;
1298
1299         t->helpline = HLP_NONE;
1300
1301         t->flag = 0;
1302
1303         t->obedit_type = ((object_mode == OB_MODE_EDIT) || (object_mode == OB_MODE_EDIT_GPENCIL)) ? object_type : -1;
1304
1305         /* Many kinds of transform only use a single handle. */
1306         if (t->data_container == NULL) {
1307                 t->data_container = MEM_callocN(sizeof(*t->data_container), __func__);
1308                 t->data_container_len = 1;
1309         }
1310
1311         t->redraw = TREDRAW_HARD;  /* redraw first time */
1312
1313         if (event) {
1314                 t->mouse.imval[0] = event->mval[0];
1315                 t->mouse.imval[1] = event->mval[1];
1316         }
1317         else {
1318                 t->mouse.imval[0] = 0;
1319                 t->mouse.imval[1] = 0;
1320         }
1321
1322         t->con.imval[0] = t->mouse.imval[0];
1323         t->con.imval[1] = t->mouse.imval[1];
1324
1325         t->mval[0] = t->mouse.imval[0];
1326         t->mval[1] = t->mouse.imval[1];
1327
1328         t->transform        = NULL;
1329         t->handleEvent      = NULL;
1330
1331         t->data_len_all = 0;
1332
1333         t->val = 0.0f;
1334
1335         zero_v3(t->vec);
1336         zero_v3(t->center_global);
1337
1338         unit_m3(t->mat);
1339
1340         unit_m3(t->orient_matrix);
1341         negate_m3(t->orient_matrix);
1342         /* Leave 't->orient_matrix_is_set' to false,
1343          * so we overwrite it when we have a useful value. */
1344
1345         /* if there's an event, we're modal */
1346         if (event) {
1347                 t->flag |= T_MODAL;
1348         }
1349
1350         /* Crease needs edge flag */
1351         if (ELEM(t->mode, TFM_CREASE, TFM_BWEIGHT)) {
1352                 t->options |= CTX_EDGE;
1353         }
1354
1355         t->remove_on_cancel = false;
1356
1357         if (op && (prop = RNA_struct_find_property(op->ptr, "remove_on_cancel")) && RNA_property_is_set(op->ptr, prop)) {
1358                 if (RNA_property_boolean_get(op->ptr, prop)) {
1359                         t->remove_on_cancel = true;
1360                 }
1361         }
1362
1363         /* GPencil editing context */
1364         if (GPENCIL_EDIT_MODE(gpd)) {
1365                 t->options |= CTX_GPENCIL_STROKES;
1366         }
1367
1368         /* Assign the space type, some exceptions for running in different mode */
1369         if (sa == NULL) {
1370                 /* background mode */
1371                 t->spacetype = SPACE_EMPTY;
1372         }
1373         else if ((ar == NULL) && (sa->spacetype == SPACE_VIEW3D)) {
1374                 /* running in the text editor */
1375                 t->spacetype = SPACE_EMPTY;
1376         }
1377         else {
1378                 /* normal operation */
1379                 t->spacetype = sa->spacetype;
1380         }
1381
1382         /* handle T_ALT_TRANSFORM initialization, we may use for different operators */
1383         if (op) {
1384                 const char *prop_id = NULL;
1385                 if (t->mode == TFM_SHRINKFATTEN) {
1386                         prop_id = "use_even_offset";
1387                 }
1388
1389                 if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id))) {
1390                         SET_FLAG_FROM_TEST(t->flag, RNA_property_boolean_get(op->ptr, prop), T_ALT_TRANSFORM);
1391                 }
1392         }
1393
1394         if (t->spacetype == SPACE_VIEW3D) {
1395                 View3D *v3d = sa->spacedata.first;
1396                 bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
1397
1398                 t->view = v3d;
1399                 t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
1400
1401                 /* turn gizmo off during transform */
1402                 if (t->flag & T_MODAL) {
1403                         t->gizmo_flag = v3d->gizmo_flag;
1404                         v3d->gizmo_flag = V3D_GIZMO_HIDE;
1405                 }
1406
1407                 if (t->scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) {
1408                         t->flag |= T_V3D_ALIGN;
1409                 }
1410                 t->around = t->scene->toolsettings->transform_pivot_point;
1411
1412                 /* bend always uses the cursor */
1413                 if (t->mode == TFM_BEND) {
1414                         t->around = V3D_AROUND_CURSOR;
1415                 }
1416
1417                 TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
1418                 t->orientation.unset = V3D_ORIENT_GLOBAL;
1419                 t->orientation.user = orient_slot->type;
1420                 t->orientation.custom = BKE_scene_transform_orientation_find(t->scene, orient_slot->index_custom);
1421
1422                 t->orientation.index = 0;
1423                 ARRAY_SET_ITEMS(
1424                         t->orientation.types,
1425                         &t->orientation.user,
1426                         NULL);
1427
1428                 /* Make second orientation local if both are global. */
1429                 if (t->orientation.user == V3D_ORIENT_GLOBAL) {
1430                         t->orientation.user_alt = V3D_ORIENT_LOCAL;
1431                         t->orientation.types[0] = &t->orientation.user_alt;
1432                         SWAP(short *, t->orientation.types[0], t->orientation.types[1]);
1433                 }
1434
1435                 /* exceptional case */
1436                 if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
1437                         if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
1438                                 const bool use_island = transdata_check_local_islands(t, t->around);
1439
1440                                 if ((t->obedit_type != -1) && !use_island) {
1441                                         t->options |= CTX_NO_PET;
1442                                 }
1443                         }
1444                 }
1445
1446                 if (object_mode & OB_MODE_ALL_PAINT) {
1447                         Paint *p = BKE_paint_get_active_from_context(C);
1448                         if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
1449                                 t->options |= CTX_PAINT_CURVE;
1450                         }
1451                 }
1452
1453                 /* initialize UV transform from */
1454                 if (op && ((prop = RNA_struct_find_property(op->ptr, "correct_uv")))) {
1455                         if (RNA_property_is_set(op->ptr, prop)) {
1456                                 if (RNA_property_boolean_get(op->ptr, prop)) {
1457                                         t->settings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT;
1458                                 }
1459                                 else {
1460                                         t->settings->uvcalc_flag &= ~UVCALC_TRANSFORM_CORRECT;
1461                                 }
1462                         }
1463                         else {
1464                                 RNA_property_boolean_set(op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) != 0);
1465                         }
1466                 }
1467
1468         }
1469         else if (t->spacetype == SPACE_IMAGE) {
1470                 SpaceImage *sima = sa->spacedata.first;
1471                 // XXX for now, get View2D from the active region
1472                 t->view = &ar->v2d;
1473                 t->around = sima->around;
1474
1475                 if (ED_space_image_show_uvedit(sima, OBACT(t->view_layer))) {
1476                         /* UV transform */
1477                 }
1478                 else if (sima->mode == SI_MODE_MASK) {
1479                         t->options |= CTX_MASK;
1480                 }
1481                 else if (sima->mode == SI_MODE_PAINT) {
1482                         Paint *p = &sce->toolsettings->imapaint.paint;
1483                         if (p->brush && (p->brush->flag & BRUSH_CURVE)) {
1484                                 t->options |= CTX_PAINT_CURVE;
1485                         }
1486                 }
1487                 /* image not in uv edit, nor in mask mode, can happen for some tools */
1488         }
1489         else if (t->spacetype == SPACE_NODE) {
1490                 // XXX for now, get View2D from the active region
1491                 t->view = &ar->v2d;
1492                 t->around = V3D_AROUND_CENTER_BOUNDS;
1493         }
1494         else if (t->spacetype == SPACE_GRAPH) {
1495                 SpaceGraph *sipo = sa->spacedata.first;
1496                 t->view = &ar->v2d;
1497                 t->around = sipo->around;
1498         }
1499         else if (t->spacetype == SPACE_CLIP) {
1500                 SpaceClip *sclip = sa->spacedata.first;
1501                 t->view = &ar->v2d;
1502                 t->around = sclip->around;
1503
1504                 if (ED_space_clip_check_show_trackedit(sclip))
1505                         t->options |= CTX_MOVIECLIP;
1506                 else if (ED_space_clip_check_show_maskedit(sclip))
1507                         t->options |= CTX_MASK;
1508         }
1509         else {
1510                 if (ar) {
1511                         // XXX for now, get View2D  from the active region
1512                         t->view = &ar->v2d;
1513                         // XXX for now, the center point is the midpoint of the data
1514                 }
1515                 else {
1516                         t->view = NULL;
1517                 }
1518                 t->around = V3D_AROUND_CENTER_BOUNDS;
1519         }
1520
1521         if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_matrix")) &&
1522                    RNA_property_is_set(op->ptr, prop)) &&
1523             ((t->flag & T_MODAL) ||
1524              /* When using redo, don't use the the custom constraint matrix
1525               * if the user selects a different orientation. */
1526              (RNA_enum_get(op->ptr, "constraint_orientation") ==
1527               RNA_enum_get(op->ptr, "constraint_matrix_orientation"))))
1528         {
1529                 RNA_property_float_get_array(op->ptr, prop, &t->spacemtx[0][0]);
1530                 /* Some transform modes use this to operate on an axis. */
1531                 copy_m3_m3(t->orient_matrix, t->spacemtx);
1532                 t->orient_matrix_is_set = true;
1533                 t->orientation.user = V3D_ORIENT_CUSTOM_MATRIX;
1534                 t->orientation.custom = 0;
1535                 if (t->flag & T_MODAL) {
1536                         RNA_enum_set(op->ptr, "constraint_matrix_orientation", RNA_enum_get(op->ptr, "constraint_orientation"));
1537                 }
1538         }
1539         else if (op && ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
1540                         RNA_property_is_set(op->ptr, prop)))
1541         {
1542                 short orientation = RNA_property_enum_get(op->ptr, prop);
1543                 TransformOrientation *custom_orientation = NULL;
1544
1545                 if (orientation >= V3D_ORIENT_CUSTOM) {
1546                         if (orientation >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
1547                                 orientation = V3D_ORIENT_GLOBAL;
1548                         }
1549                         else {
1550                                 custom_orientation = BKE_scene_transform_orientation_find(
1551                                         t->scene, orientation - V3D_ORIENT_CUSTOM);
1552                                 orientation = V3D_ORIENT_CUSTOM;
1553                         }
1554                 }
1555
1556                 t->orientation.user = orientation;
1557                 t->orientation.custom = custom_orientation;
1558         }
1559
1560         if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
1561                    RNA_property_is_set(op->ptr, prop)))
1562         {
1563                 if (RNA_property_boolean_get(op->ptr, prop)) {
1564                         t->flag |= T_RELEASE_CONFIRM;
1565                 }
1566         }
1567         else {
1568                 if (U.flag & USER_RELEASECONFIRM) {
1569                         t->flag |= T_RELEASE_CONFIRM;
1570                 }
1571         }
1572
1573         if (op && ((prop = RNA_struct_find_property(op->ptr, "mirror")) &&
1574                    RNA_property_is_set(op->ptr, prop)))
1575         {
1576                 if (!RNA_property_boolean_get(op->ptr, prop)) {
1577                         t->flag |= T_NO_MIRROR;
1578                 }
1579         }
1580         else if ((t->spacetype == SPACE_VIEW3D) && (t->obedit_type == OB_MESH)) {
1581                 /* pass */
1582         }
1583         else {
1584                 /* Avoid mirroring for unsupported contexts. */
1585                 t->options |= CTX_NO_MIRROR;
1586         }
1587
1588         /* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */
1589         if (op && (prop = RNA_struct_find_property(op->ptr, "proportional"))) {
1590                 if (RNA_property_is_set(op->ptr, prop)) {
1591                         t->flag |= initTransInfo_edit_pet_to_flag(RNA_property_enum_get(op->ptr, prop));
1592                 }
1593                 else {
1594                         /* use settings from scene only if modal */
1595                         if (t->flag & T_MODAL) {
1596                                 if ((t->options & CTX_NO_PET) == 0) {
1597                                         if (t->spacetype == SPACE_GRAPH) {
1598                                                 t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_fcurve);
1599                                         }
1600                                         else if (t->spacetype == SPACE_ACTION) {
1601                                                 t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional_action);
1602                                         }
1603                                         else if (t->obedit_type != -1) {
1604                                                 t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional);
1605                                         }
1606                                         else if (t->options & CTX_GPENCIL_STROKES) {
1607                                                 t->flag |= initTransInfo_edit_pet_to_flag(ts->proportional);
1608                                         }
1609                                         else if (t->options & CTX_MASK) {
1610                                                 if (ts->proportional_mask) {
1611                                                         t->flag |= T_PROP_EDIT;
1612
1613                                                         if (ts->proportional == PROP_EDIT_CONNECTED) {
1614                                                                 t->flag |= T_PROP_CONNECTED;
1615                                                         }
1616                                                 }
1617                                         }
1618                                         else if ((t->obedit_type == -1) && ts->proportional_objects) {
1619                                                 t->flag |= T_PROP_EDIT;
1620                                         }
1621                                 }
1622                         }
1623                 }
1624
1625                 if (op && ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) &&
1626                            RNA_property_is_set(op->ptr, prop)))
1627                 {
1628                         t->prop_size = RNA_property_float_get(op->ptr, prop);
1629                 }
1630                 else {
1631                         t->prop_size = ts->proportional_size;
1632                 }
1633
1634
1635                 /* TRANSFORM_FIX_ME rna restrictions */
1636                 if (t->prop_size <= 0.00001f) {
1637                         printf("Proportional size (%f) under 0.00001, resetting to 1!\n", t->prop_size);
1638                         t->prop_size = 1.0f;
1639                 }
1640
1641                 if (op && ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) &&
1642                            RNA_property_is_set(op->ptr, prop)))
1643                 {
1644                         t->prop_mode = RNA_property_enum_get(op->ptr, prop);
1645                 }
1646                 else {
1647                         t->prop_mode = ts->prop_mode;
1648                 }
1649         }
1650         else { /* add not pet option to context when not available */
1651                 t->options |= CTX_NO_PET;
1652         }
1653
1654         // Mirror is not supported with PET, turn it off.
1655 #if 0
1656         if (t->flag & T_PROP_EDIT) {
1657                 t->flag &= ~T_MIRROR;
1658         }
1659 #endif
1660
1661         setTransformViewAspect(t, t->aspect);
1662
1663         if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) && RNA_property_is_set(op->ptr, prop)) {
1664                 RNA_property_float_get_array(op->ptr, prop, t->center_global);
1665                 mul_v3_v3(t->center_global, t->aspect);
1666                 t->flag |= T_OVERRIDE_CENTER;
1667         }
1668
1669         setTransformViewMatrices(t);
1670         initNumInput(&t->num);
1671 }
1672
1673
1674 static void freeTransCustomData(
1675         TransInfo *t, TransDataContainer *tc,
1676         TransCustomData *custom_data)
1677 {
1678         if (custom_data->free_cb) {
1679                 /* Can take over freeing t->data and data_2d etc... */
1680                 custom_data->free_cb(t, tc, custom_data);
1681                 BLI_assert(custom_data->data == NULL);
1682         }
1683         else if ((custom_data->data != NULL) && custom_data->use_free) {
1684                 MEM_freeN(custom_data->data);
1685                 custom_data->data = NULL;
1686         }
1687         /* In case modes are switched in the same transform session. */
1688         custom_data->free_cb = false;
1689         custom_data->use_free = false;
1690 }
1691
1692 static void freeTransCustomDataContainer(TransInfo *t, TransDataContainer *tc, TransCustomDataContainer *tcdc)
1693 {
1694         TransCustomData *custom_data = &tcdc->first_elem;
1695         for (int i = 0; i < TRANS_CUSTOM_DATA_ELEM_MAX; i++, custom_data++) {
1696                 freeTransCustomData(t, tc, custom_data);
1697         }
1698 }
1699
1700 /**
1701  * Needed for mode switching.
1702  */
1703 void freeTransCustomDataForMode(TransInfo *t)
1704 {
1705         freeTransCustomData(t, NULL, &t->custom.mode);
1706         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
1707                 freeTransCustomData(t, tc, &tc->custom.mode);
1708         }
1709 }
1710
1711 /* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
1712 void postTrans(bContext *C, TransInfo *t)
1713 {
1714         if (t->draw_handle_view)
1715                 ED_region_draw_cb_exit(t->ar->type, t->draw_handle_view);
1716         if (t->draw_handle_apply)
1717                 ED_region_draw_cb_exit(t->ar->type, t->draw_handle_apply);
1718         if (t->draw_handle_pixel)
1719                 ED_region_draw_cb_exit(t->ar->type, t->draw_handle_pixel);
1720         if (t->draw_handle_cursor)
1721                 WM_paint_cursor_end(CTX_wm_manager(C), t->draw_handle_cursor);
1722
1723         if (t->flag & T_MODAL_CURSOR_SET) {
1724                 WM_cursor_modal_restore(CTX_wm_window(C));
1725         }
1726
1727         /* Free all custom-data */
1728         freeTransCustomDataContainer(t, NULL, &t->custom);
1729         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
1730                 freeTransCustomDataContainer(t, tc, &tc->custom);
1731         }
1732
1733         /* postTrans can be called when nothing is selected, so data is NULL already */
1734         if (t->data_len_all != 0) {
1735                 FOREACH_TRANS_DATA_CONTAINER (t, tc) {
1736                         /* free data malloced per trans-data */
1737                         if (ELEM(t->obedit_type, OB_CURVE, OB_SURF) ||
1738                             (t->spacetype == SPACE_GRAPH))
1739                         {
1740                                 TransData *td = tc->data;
1741                                 for (int a = 0; a < tc->data_len; a++, td++) {
1742                                         if (td->flag & TD_BEZTRIPLE) {
1743                                                 MEM_freeN(td->hdata);
1744                                         }
1745                                 }
1746                         }
1747                         MEM_freeN(tc->data);
1748
1749                         MEM_SAFE_FREE(tc->data_ext);
1750                         MEM_SAFE_FREE(tc->data_2d);
1751                 }
1752         }
1753
1754         MEM_SAFE_FREE(t->data_container);
1755         t->data_container = NULL;
1756
1757         BLI_freelistN(&t->tsnap.points);
1758
1759         if (t->spacetype == SPACE_IMAGE) {
1760                 if (t->options & (CTX_MASK | CTX_PAINT_CURVE)) {
1761                         /* pass */
1762                 }
1763                 else {
1764                         SpaceImage *sima = t->sa->spacedata.first;
1765                         if (sima->flag & SI_LIVE_UNWRAP)
1766                                 ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL);
1767                 }
1768         }
1769         else if (t->spacetype == SPACE_VIEW3D) {
1770                 View3D *v3d = t->sa->spacedata.first;
1771                 /* restore gizmo */
1772                 if (t->flag & T_MODAL) {
1773                         v3d->gizmo_flag = t->gizmo_flag;
1774                 }
1775         }
1776
1777         if (t->mouse.data) {
1778                 MEM_freeN(t->mouse.data);
1779         }
1780
1781         if (t->rng != NULL) {
1782                 BLI_rng_free(t->rng);
1783         }
1784
1785         freeSnapping(t);
1786 }
1787
1788 void applyTransObjects(TransInfo *t)
1789 {
1790         TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
1791
1792         TransData *td;
1793
1794         for (td = tc->data; td < tc->data + tc->data_len; td++) {
1795                 copy_v3_v3(td->iloc, td->loc);
1796                 if (td->ext->rot) {
1797                         copy_v3_v3(td->ext->irot, td->ext->rot);
1798                 }
1799                 if (td->ext->size) {
1800                         copy_v3_v3(td->ext->isize, td->ext->size);
1801                 }
1802         }
1803         recalcData(t);
1804 }
1805
1806 static void restoreElement(TransData *td)
1807 {
1808         /* TransData for crease has no loc */
1809         if (td->loc) {
1810                 copy_v3_v3(td->loc, td->iloc);
1811         }
1812         if (td->val) {
1813                 *td->val = td->ival;
1814         }
1815
1816         if (td->ext && (td->flag & TD_NO_EXT) == 0) {
1817                 if (td->ext->rot) {
1818                         copy_v3_v3(td->ext->rot, td->ext->irot);
1819                 }
1820                 if (td->ext->rotAngle) {
1821                         *td->ext->rotAngle = td->ext->irotAngle;
1822                 }
1823                 if (td->ext->rotAxis) {
1824                         copy_v3_v3(td->ext->rotAxis, td->ext->irotAxis);
1825                 }
1826                 /* XXX, drotAngle & drotAxis not used yet */
1827                 if (td->ext->size) {
1828                         copy_v3_v3(td->ext->size, td->ext->isize);
1829                 }
1830                 if (td->ext->quat) {
1831                         copy_qt_qt(td->ext->quat, td->ext->iquat);
1832                 }
1833         }
1834
1835         if (td->flag & TD_BEZTRIPLE) {
1836                 *(td->hdata->h1) = td->hdata->ih1;
1837                 *(td->hdata->h2) = td->hdata->ih2;
1838         }
1839 }
1840
1841 void restoreTransObjects(TransInfo *t)
1842 {
1843         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
1844
1845                 TransData *td;
1846                 TransData2D *td2d;
1847
1848                 for (td = tc->data; td < tc->data + tc->data_len; td++) {
1849                         restoreElement(td);
1850                 }
1851
1852                 for (td2d = tc->data_2d; tc->data_2d && td2d < tc->data_2d + tc->data_len; td2d++) {
1853                         if (td2d->h1) {
1854                                 td2d->h1[0] = td2d->ih1[0];
1855                                 td2d->h1[1] = td2d->ih1[1];
1856                         }
1857                         if (td2d->h2) {
1858                                 td2d->h2[0] = td2d->ih2[0];
1859                                 td2d->h2[1] = td2d->ih2[1];
1860                         }
1861                 }
1862
1863                 unit_m3(t->mat);
1864
1865         }
1866
1867         recalcData(t);
1868 }
1869
1870 void calculateCenter2D(TransInfo *t)
1871 {
1872         BLI_assert(!is_zero_v3(t->aspect));
1873         projectFloatView(t, t->center_global, t->center2d);
1874 }
1875
1876 void calculateCenterLocal(
1877         TransInfo *t, const float center_global[3])
1878 {
1879         /* setting constraint center */
1880         /* note, init functions may over-ride t->center */
1881         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
1882                 if (tc->use_local_mat) {
1883                         mul_v3_m4v3(tc->center_local, tc->imat, center_global);
1884                 }
1885                 else {
1886                         copy_v3_v3(tc->center_local, center_global);
1887                 }
1888         }
1889 }
1890
1891 void calculateCenterCursor(TransInfo *t, float r_center[3])
1892 {
1893         const float *cursor = t->scene->cursor.location;
1894         copy_v3_v3(r_center, cursor);
1895
1896         /* If edit or pose mode, move cursor in local space */
1897         if (t->options & CTX_PAINT_CURVE) {
1898                 if (ED_view3d_project_float_global(t->ar, cursor, r_center, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
1899                         r_center[0] = t->ar->winx / 2.0f;
1900                         r_center[1] = t->ar->winy / 2.0f;
1901                 }
1902                 r_center[2] = 0.0f;
1903         }
1904 }
1905
1906 void calculateCenterCursor2D(TransInfo *t, float r_center[2])
1907 {
1908         const float *cursor = NULL;
1909
1910         if (t->spacetype == SPACE_IMAGE) {
1911                 SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
1912                 cursor = sima->cursor;
1913         }
1914         else if (t->spacetype == SPACE_CLIP) {
1915                 SpaceClip *space_clip = (SpaceClip *) t->sa->spacedata.first;
1916                 cursor = space_clip->cursor;
1917         }
1918
1919         if (cursor) {
1920                 if (t->options & CTX_MASK) {
1921                         float co[2];
1922
1923                         if (t->spacetype == SPACE_IMAGE) {
1924                                 SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
1925                                 BKE_mask_coord_from_image(sima->image, &sima->iuser, co, cursor);
1926                         }
1927                         else if (t->spacetype == SPACE_CLIP) {
1928                                 SpaceClip *space_clip = (SpaceClip *) t->sa->spacedata.first;
1929                                 BKE_mask_coord_from_movieclip(space_clip->clip, &space_clip->user, co, cursor);
1930                         }
1931                         else {
1932                                 BLI_assert(!"Shall not happen");
1933                         }
1934
1935                         r_center[0] = co[0] * t->aspect[0];
1936                         r_center[1] = co[1] * t->aspect[1];
1937                 }
1938                 else if (t->options & CTX_PAINT_CURVE) {
1939                         if (t->spacetype == SPACE_IMAGE) {
1940                                 r_center[0] = UI_view2d_view_to_region_x(&t->ar->v2d, cursor[0]);
1941                                 r_center[1] = UI_view2d_view_to_region_y(&t->ar->v2d, cursor[1]);
1942                         }
1943                 }
1944                 else {
1945                         r_center[0] = cursor[0] * t->aspect[0];
1946                         r_center[1] = cursor[1] * t->aspect[1];
1947                 }
1948         }
1949 }
1950
1951 void calculateCenterCursorGraph2D(TransInfo *t, float r_center[2])
1952 {
1953         SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
1954         Scene *scene = t->scene;
1955
1956         /* cursor is combination of current frame, and graph-editor cursor value */
1957         if (sipo->mode == SIPO_MODE_DRIVERS) {
1958                 r_center[0] = sipo->cursorTime;
1959                 r_center[1] = sipo->cursorVal;
1960         }
1961         else {
1962                 r_center[0] = (float)(scene->r.cfra);
1963                 r_center[1] = sipo->cursorVal;
1964         }
1965 }
1966
1967 void calculateCenterMedian(TransInfo *t, float r_center[3])
1968 {
1969         float partial[3] = {0.0f, 0.0f, 0.0f};
1970         int total = 0;
1971
1972         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
1973                 for (int i = 0; i < tc->data_len; i++) {
1974                         if (tc->data[i].flag & TD_SELECTED) {
1975                                 if (!(tc->data[i].flag & TD_NOCENTER)) {
1976                                         if (tc->use_local_mat) {
1977                                                 float v[3];
1978                                                 mul_v3_m4v3(v, tc->mat, tc->data[i].center);
1979                                                 add_v3_v3(partial, v);
1980                                         }
1981                                         else {
1982                                                 add_v3_v3(partial, tc->data[i].center);
1983                                         }
1984                                         total++;
1985                                 }
1986                         }
1987                 }
1988         }
1989         if (total) {
1990                 mul_v3_fl(partial, 1.0f / (float)total);
1991         }
1992         copy_v3_v3(r_center, partial);
1993 }
1994
1995 void calculateCenterBound(TransInfo *t, float r_center[3])
1996 {
1997         float max[3], min[3];
1998         bool changed = false;
1999         INIT_MINMAX(min, max);
2000         FOREACH_TRANS_DATA_CONTAINER (t, tc) {
2001                 for (int i = 0; i < tc->data_len; i++) {
2002                         if (tc->data[i].flag & TD_SELECTED) {
2003                                 if (!(tc->data[i].flag & TD_NOCENTER)) {
2004                                         if (tc->use_local_mat) {
2005                                                 float v[3];
2006                                                 mul_v3_m4v3(v, tc->mat, tc->data[i].center);
2007                                                 minmax_v3v3_v3(min, max, v);
2008                                         }
2009                                         else {
2010                                                 minmax_v3v3_v3(min, max, tc->data[i].center);
2011                                         }
2012                                         changed = true;
2013                                 }
2014                         }
2015                 }
2016         }
2017         if (changed) {
2018                 mid_v3_v3v3(r_center, min, max);
2019         }
2020 }
2021
2022 /**
2023  * \param select_only: only get active center from data being transformed.
2024  */
2025 bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
2026 {
2027         TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
2028
2029         if (t->spacetype != SPACE_VIEW3D) {
2030                 return false;
2031         }
2032         else if (tc->obedit) {
2033                 if (ED_object_calc_active_center_for_editmode(tc->obedit, select_only, r_center)) {
2034                         mul_m4_v3(tc->obedit->obmat, r_center);
2035                         return true;
2036                 }
2037         }
2038         else if (t->flag & T_POSE) {
2039                 ViewLayer *view_layer = t->view_layer;
2040                 Object *ob = OBACT(view_layer) ;
2041                 if (ED_object_calc_active_center_for_posemode(ob, select_only, r_center)) {
2042                         mul_m4_v3(ob->obmat, r_center);
2043                         return true;
2044                 }
2045         }
2046         else if (t->options & CTX_PAINT_CURVE) {
2047                 Paint *p = BKE_paint_get_active(t->scene, t->view_layer);
2048                 Brush *br = p->brush;
2049                 PaintCurve *pc = br->paint_curve;
2050                 copy_v3_v3(r_center, pc->points[pc->add_index - 1].bez.vec[1]);
2051                 r_center[2] = 0.0f;
2052                 return true;
2053         }
2054         else {
2055                 /* object mode */
2056                 ViewLayer *view_layer = t->view_layer;
2057                 Object *ob = OBACT(view_layer);
2058                 Base *base = BASACT(view_layer);
2059                 if (ob && ((!select_only) || ((base->flag & BASE_SELECTED) != 0))) {
2060                         copy_v3_v3(r_center, ob->obmat[3]);
2061                         return true;
2062                 }
2063         }
2064
2065         return false;
2066 }
2067
2068 static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[3])
2069 {
2070         switch (around) {
2071                 case V3D_AROUND_CENTER_BOUNDS:
2072                         calculateCenterBound(t, r_center);
2073                         break;
2074                 case V3D_AROUND_CENTER_MEDIAN:
2075                         calculateCenterMedian(t, r_center);
2076                         break;
2077                 case V3D_AROUND_CURSOR:
2078                         if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP))
2079                                 calculateCenterCursor2D(t, r_center);
2080                         else if (t->spacetype == SPACE_GRAPH)
2081                                 calculateCenterCursorGraph2D(t, r_center);
2082                         else
2083                                 calculateCenterCursor(t, r_center);
2084                         break;
2085                 case V3D_AROUND_LOCAL_ORIGINS:
2086                         /* Individual element center uses median center for helpline and such */
2087                         calculateCenterMedian(t, r_center);
2088                         break;
2089                 case V3D_AROUND_ACTIVE:
2090                 {
2091                         if (calculateCenterActive(t, false, r_center)) {
2092                                 /* pass */
2093                         }
2094                         else {
2095                                 /* fallback */
2096                                 calculateCenterMedian(t, r_center);
2097                         }
2098                         break;
2099                 }
2100         }
2101 }
2102
2103 void calculateCenter(TransInfo *t)
2104 {
2105         if ((t->flag & T_OVERRIDE_CENTER) == 0) {
2106                 calculateCenter_FromAround(t, t->around, t->center_global);
2107         }
2108         calculateCenterLocal(t, t->center_global);
2109
2110         /* avoid calculating again */
2111         {
2112                 TransCenterData *cd = &t->center_cache[t->around];
2113                 copy_v3_v3(cd->global, t->center_global);
2114                 cd->is_set = true;
2115         }
2116
2117         calculateCenter2D(t);
2118
2119         /* for panning from cameraview */
2120         if ((t->flag & T_OBJECT) && (t->flag & T_OVERRIDE_CENTER) == 0) {
2121                 if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
2122
2123                         if (t->flag & T_CAMERA) {
2124                                 float axis[3];
2125                                 /* persinv is nasty, use viewinv instead, always right */
2126                                 copy_v3_v3(axis, t->viewinv[2]);
2127                                 normalize_v3(axis);
2128
2129                                 /* 6.0 = 6 grid units */
2130                                 axis[0] = t->center_global[0] - 6.0f * axis[0];
2131                                 axis[1] = t->center_global[1] - 6.0f * axis[1];
2132                                 axis[2] = t->center_global[2] - 6.0f * axis[2];
2133
2134                                 projectFloatView(t, axis, t->center2d);
2135
2136                                 /* rotate only needs correct 2d center, grab needs ED_view3d_calc_zfac() value */
2137                                 if (t->mode == TFM_TRANSLATION) {
2138                                         copy_v3_v3(t->center_global, axis);
2139                                 }
2140                         }
2141                 }
2142         }
2143
2144         if (t->spacetype == SPACE_VIEW3D) {
2145                 /* ED_view3d_calc_zfac() defines a factor for perspective depth correction, used in ED_view3d_win_to_delta() */
2146
2147                 /* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW
2148                  * and never used in other cases.
2149                  *
2150                  * We need special case here as well, since ED_view3d_calc_zfac will crash when called
2151                  * for a region different from RGN_TYPE_WINDOW.
2152                  */
2153                 if (t->ar->regiontype == RGN_TYPE_WINDOW) {
2154                         t->zfac = ED_view3d_calc_zfac(t->ar->regiondata, t->center_global, NULL);
2155                 }
2156                 else {
2157                         t->zfac = 0.0f;
2158                 }
2159         }
2160 }
2161
2162 BLI_STATIC_ASSERT(ARRAY_SIZE(((TransInfo *)NULL)->center_cache) == (V3D_AROUND_ACTIVE + 1), "test size");
2163
2164 /**
2165  * Lazy initialize transform center data, when we need to access center values from other types.
2166  */
2167 const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
2168 {
2169         BLI_assert(around <= V3D_AROUND_ACTIVE);
2170         TransCenterData *cd = &t->center_cache[around];
2171         if (cd->is_set == false) {
2172                 calculateCenter_FromAround(t, around, cd->global);
2173                 cd->is_set = true;
2174         }
2175         return cd;
2176 }
2177
2178 void calculatePropRatio(TransInfo *t)
2179 {
2180         int i;
2181         float dist;
2182         const bool connected = (t->flag & T_PROP_CONNECTED) != 0;
2183
2184         t->proptext[0] = '\0';
2185
2186         if (t->flag & T_PROP_EDIT) {
2187                 const char *pet_id = NULL;
2188                 FOREACH_TRANS_DATA_CONTAINER (t, tc) {
2189                         TransData *td = tc->data;
2190                         for (i = 0; i < tc->data_len; i++, td++) {
2191                                 if (td->flag & TD_SELECTED) {
2192                                         td->factor = 1.0f;
2193                                 }
2194                                 else if (tc->mirror.axis_flag && (td->loc[0] * tc->mirror.sign) < -0.00001f) {
2195                                         td->flag |= TD_SKIP;
2196                                         td->factor = 0.0f;
2197                                         restoreElement(td);
2198                                 }
2199                                 else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) ||
2200                                          (connected == 0 && td->rdist > t->prop_size))
2201                                 {
2202                                         /*
2203                                          * The elements are sorted according to their dist member in the array,
2204                                          * that means we can stop when it finds one element outside of the propsize.
2205                                          * do not set 'td->flag |= TD_NOACTION', the prop circle is being changed.
2206                                          */
2207
2208                                         td->factor = 0.0f;
2209                                         restoreElement(td);
2210                                 }
2211                                 else {
2212                                         /* Use rdist for falloff calculations, it is the real distance */
2213                                         td->flag &= ~TD_NOACTION;
2214
2215                                         if (connected)
2216                                                 dist = (t->prop_size - td->dist) / t->prop_size;
2217                                         else
2218                                                 dist = (t->prop_size - td->rdist) / t->prop_size;
2219
2220                                         /*
2221                                          * Clamp to positive numbers.
2222                                          * Certain corner cases with connectivity and individual centers
2223                                          * can give values of rdist larger than propsize.
2224                                          */
2225                                         if (dist < 0.0f)
2226                                                 dist = 0.0f;
2227
2228                                         switch (t->prop_mode) {
2229                                                 case PROP_SHARP:
2230                                                         td->factor = dist * dist;
2231                                                         break;
2232                                                 case PROP_SMOOTH:
2233                                                         td->factor = 3.0f * dist * dist - 2.0f * dist * dist * dist;
2234                                                         break;
2235                                                 case PROP_ROOT:
2236                                                         td->factor = sqrtf(dist);
2237                                                         break;
2238                                                 case PROP_LIN:
2239                                                         td->factor = dist;
2240                                                         break;
2241                                                 case PROP_CONST:
2242                                                         td->factor = 1.0f;
2243                                                         break;
2244                                                 case PROP_SPHERE:
2245                                                         td->factor = sqrtf(2 * dist - dist * dist);
2246                                                         break;
2247                                                 case PROP_RANDOM:
2248                                                         if (t->rng == NULL) {
2249                                                                 /* Lazy initialization. */
2250                                                                 uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
2251                                                                 t->rng = BLI_rng_new(rng_seed);
2252                                                         }
2253                                                         td->factor = BLI_rng_get_float(t->rng) * dist;
2254                                                         break;
2255                                                 case PROP_INVSQUARE:
2256                                                         td->factor = dist * (2.0f - dist);
2257                                                         break;
2258                                                 default:
2259                                                         td->factor = 1;
2260                                                         break;
2261                                         }
2262                                 }
2263                         }
2264                 }
2265
2266                 switch (t->prop_mode) {
2267                         case PROP_SHARP:
2268                                 pet_id = N_("(Sharp)");
2269                                 break;
2270                         case PROP_SMOOTH:
2271                                 pet_id = N_("(Smooth)");
2272                                 break;
2273                         case PROP_ROOT:
2274                                 pet_id = N_("(Root)");
2275                                 break;
2276                         case PROP_LIN:
2277                                 pet_id = N_("(Linear)");
2278                                 break;
2279                         case PROP_CONST:
2280                                 pet_id = N_("(Constant)");
2281                                 break;
2282                         case PROP_SPHERE:
2283                                 pet_id = N_("(Sphere)");
2284                                 break;
2285                         case PROP_RANDOM:
2286                                 pet_id = N_("(Random)");
2287                                 break;
2288                         case PROP_INVSQUARE:
2289                                 pet_id = N_("(InvSquare)");
2290                                 break;
2291                         default:
2292                                 break;
2293                 }
2294
2295                 if (pet_id) {
2296                         BLI_strncpy(t->proptext, IFACE_(pet_id), sizeof(t->proptext));
2297                 }
2298         }
2299         else {
2300                 FOREACH_TRANS_DATA_CONTAINER (t, tc) {
2301                         TransData *td = tc->data;
2302                         for (i = 0; i < tc->data_len; i++, td++) {
2303                                 td->factor = 1.0;
2304                         }
2305                 }
2306         }
2307 }
2308
2309 /**
2310  * Rotate an element, low level code, ignore protected channels.
2311  * (use for objects or pose-bones)
2312  * Similar to #ElementRotation.
2313  */
2314 void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot)
2315 {
2316         float totmat[3][3];
2317         float smat[3][3];
2318         float fmat[3][3];
2319         float obmat[3][3];
2320
2321         float dmat[3][3];  /* delta rotation */
2322         float dmat_inv[3][3];
2323
2324         mul_m3_m3m3(totmat, mat, td->mtx);
2325         mul_m3_m3m3(smat, td->smtx, mat);
2326
2327         /* logic from BKE_object_rot_to_mat3 */
2328         if (use_drot) {
2329                 if (td->ext->rotOrder > 0) {
2330                         eulO_to_mat3(dmat, td->ext->drot, td->ext->rotOrder);
2331                 }
2332                 else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
2333 #if 0
2334                         axis_angle_to_mat3(dmat, td->ext->drotAxis, td->ext->drotAngle);
2335 #else
2336                         unit_m3(dmat);
2337 #endif
2338                 }
2339                 else {
2340                         float tquat[4];
2341                         normalize_qt_qt(tquat, td->ext->dquat);
2342                         quat_to_mat3(dmat, tquat);
2343                 }
2344
2345                 invert_m3_m3(dmat_inv, dmat);
2346         }
2347
2348
2349         if (td->ext->rotOrder == ROT_MODE_QUAT) {
2350                 float quat[4];
2351
2352                 /* calculate the total rotatation */
2353                 quat_to_mat3(obmat, td->ext->iquat);
2354                 if (use_drot) {
2355                         mul_m3_m3m3(obmat, dmat, obmat);
2356                 }
2357
2358                 /* mat = transform, obmat = object rotation */
2359                 mul_m3_m3m3(fmat, smat, obmat);
2360
2361                 if (use_drot) {
2362                         mul_m3_m3m3(fmat, dmat_inv, fmat);
2363                 }
2364
2365                 mat3_to_quat(quat, fmat);
2366
2367                 /* apply */
2368                 copy_qt_qt(td->ext->quat, quat);
2369         }
2370         else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
2371                 float axis[3], angle;
2372
2373                 /* calculate the total rotatation */
2374                 axis_angle_to_mat3(obmat, td->ext->irotAxis, td->ext->irotAngle);
2375                 if (use_drot) {
2376                         mul_m3_m3m3(obmat, dmat, obmat);
2377                 }
2378
2379                 /* mat = transform, obmat = object rotation */
2380                 mul_m3_m3m3(fmat, smat, obmat);
2381
2382                 if (use_drot) {
2383                         mul_m3_m3m3(fmat, dmat_inv, fmat);
2384                 }
2385
2386                 mat3_to_axis_angle(axis, &angle, fmat);
2387
2388                 /* apply */
2389                 copy_v3_v3(td->ext->rotAxis, axis);
2390                 *td->ext->rotAngle = angle;
2391         }
2392         else {
2393                 float eul[3];
2394
2395                 /* calculate the total rotatation */
2396                 eulO_to_mat3(obmat, td->ext->irot, td->ext->rotOrder);
2397                 if (use_drot) {
2398                         mul_m3_m3m3(obmat, dmat, obmat);
2399                 }
2400
2401                 /* mat = transform, obmat = object rotation */
2402                 mul_m3_m3m3(fmat, smat, obmat);
2403
2404                 if (use_drot) {
2405                         mul_m3_m3m3(fmat, dmat_inv, fmat);
2406                 }
2407
2408                 mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
2409
2410                 /* apply */
2411                 copy_v3_v3(td->ext->rot, eul);
2412         }
2413 }