Viewport: cannot select object by clicking on its instances
[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 <math.h>
25
26 #include "MEM_guardedalloc.h"
27
28 #include "DNA_gpencil_types.h"
29 #include "DNA_mesh_types.h"
30
31 #include "BLI_blenlib.h"
32 #include "BLI_math.h"
33 #include "BLI_rand.h"
34
35 #include "PIL_time.h"
36
37 #include "BLT_translation.h"
38
39 #include "RNA_access.h"
40
41 #include "GPU_immediate.h"
42 #include "GPU_matrix.h"
43
44 #include "BKE_context.h"
45 #include "BKE_layer.h"
46 #include "BKE_mask.h"
47 #include "BKE_paint.h"
48
49 #include "ED_clip.h"
50 #include "ED_image.h"
51 #include "ED_object.h"
52 #include "ED_screen.h"
53 #include "ED_space_api.h"
54 #include "ED_uvedit.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "UI_resources.h"
60 #include "UI_view2d.h"
61
62 #include "transform.h"
63 #include "transform_mode.h"
64 #include "transform_orientations.h"
65 #include "transform_snap.h"
66
67 /* ************************** Functions *************************** */
68
69 void getViewVector(const TransInfo *t, const float coord[3], float vec[3])
70 {
71   if (t->persp != RV3D_ORTHO) {
72     sub_v3_v3v3(vec, coord, t->viewinv[3]);
73   }
74   else {
75     copy_v3_v3(vec, t->viewinv[2]);
76   }
77   normalize_v3(vec);
78 }
79
80 /* ************************** GENERICS **************************** */
81
82 void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis, short options)
83 {
84   float v1[3], v2[3], v3[3];
85   uchar col[3], col2[3];
86
87   if (t->spacetype == SPACE_VIEW3D) {
88     View3D *v3d = t->view;
89
90     GPU_matrix_push();
91
92     copy_v3_v3(v3, dir);
93     mul_v3_fl(v3, v3d->clip_end);
94
95     sub_v3_v3v3(v2, center, v3);
96     add_v3_v3v3(v1, center, v3);
97
98     if (options & DRAWLIGHT) {
99       col[0] = col[1] = col[2] = 220;
100     }
101     else {
102       UI_GetThemeColor3ubv(TH_GRID, col);
103     }
104     UI_make_axis_color(col, col2, axis);
105
106     uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
107
108     immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
109     immUniformColor3ubv(col2);
110
111     immBegin(GPU_PRIM_LINES, 2);
112     immVertex3fv(pos, v1);
113     immVertex3fv(pos, v2);
114     immEnd();
115
116     immUnbindProgram();
117
118     GPU_matrix_pop();
119   }
120 }
121
122 /**
123  * Free data before switching to another mode.
124  */
125 void resetTransModal(TransInfo *t)
126 {
127   freeTransCustomDataForMode(t);
128 }
129
130 void resetTransRestrictions(TransInfo *t)
131 {
132   t->flag &= ~T_ALL_RESTRICTIONS;
133 }
134
135 void initTransDataContainers_FromObjectData(TransInfo *t,
136                                             Object *obact,
137                                             Object **objects,
138                                             uint objects_len)
139 {
140   const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
141   const short object_type = obact ? obact->type : -1;
142
143   if ((object_mode & OB_MODE_EDIT) || (t->options & CTX_GPENCIL_STROKES) ||
144       ((object_mode & OB_MODE_POSE) && (object_type == OB_ARMATURE))) {
145     if (t->data_container) {
146       MEM_freeN(t->data_container);
147     }
148
149     bool free_objects = false;
150     if (objects == NULL) {
151       objects = BKE_view_layer_array_from_objects_in_mode(
152           t->view_layer,
153           (t->spacetype == SPACE_VIEW3D) ? t->view : NULL,
154           &objects_len,
155           {
156               .object_mode = object_mode,
157               .no_dup_data = true,
158           });
159       free_objects = true;
160     }
161
162     t->data_container = MEM_callocN(sizeof(*t->data_container) * objects_len, __func__);
163     t->data_container_len = objects_len;
164
165     for (int i = 0; i < objects_len; i++) {
166       TransDataContainer *tc = &t->data_container[i];
167       if (((t->flag & T_NO_MIRROR) == 0) && ((t->options & CTX_NO_MIRROR) == 0) &&
168           (objects[i]->type == OB_MESH)) {
169         tc->use_mirror_axis_x = (((Mesh *)objects[i]->data)->symmetry & ME_SYMMETRY_X) != 0;
170         tc->use_mirror_axis_y = (((Mesh *)objects[i]->data)->symmetry & ME_SYMMETRY_Y) != 0;
171         tc->use_mirror_axis_z = (((Mesh *)objects[i]->data)->symmetry & ME_SYMMETRY_Z) != 0;
172       }
173
174       if (object_mode & OB_MODE_EDIT) {
175         tc->obedit = objects[i];
176         /* Check needed for UV's */
177         if ((t->flag & T_2D_EDIT) == 0) {
178           tc->use_local_mat = true;
179         }
180       }
181       else if (object_mode & OB_MODE_POSE) {
182         tc->poseobj = objects[i];
183         tc->use_local_mat = true;
184       }
185       else if (t->options & CTX_GPENCIL_STROKES) {
186         tc->use_local_mat = true;
187       }
188
189       if (tc->use_local_mat) {
190         BLI_assert((t->flag & T_2D_EDIT) == 0);
191         copy_m4_m4(tc->mat, objects[i]->obmat);
192         copy_m3_m4(tc->mat3, tc->mat);
193         /* for non-invertible scale matrices, invert_m4_m4_fallback()
194          * can still provide a valid pivot */
195         invert_m4_m4_fallback(tc->imat, tc->mat);
196         invert_m3_m3(tc->imat3, tc->mat3);
197         normalize_m3_m3(tc->mat3_unit, tc->mat3);
198       }
199       /* Otherwise leave as zero. */
200     }
201
202     if (free_objects) {
203       MEM_freeN(objects);
204     }
205   }
206 }
207
208 /**
209  * Setup internal data, mouse, vectors
210  *
211  * \note \a op and \a event can be NULL
212  *
213  * \see #saveTransform does the reverse.
214  */
215 void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *event)
216 {
217   Scene *sce = CTX_data_scene(C);
218   ViewLayer *view_layer = CTX_data_view_layer(C);
219   Object *obact = OBACT(view_layer);
220   const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
221   ToolSettings *ts = CTX_data_tool_settings(C);
222   ARegion *region = CTX_wm_region(C);
223   ScrArea *area = CTX_wm_area(C);
224
225   bGPdata *gpd = CTX_data_gpencil_data(C);
226   PropertyRNA *prop;
227
228   t->mbus = CTX_wm_message_bus(C);
229   t->depsgraph = CTX_data_depsgraph_pointer(C);
230   t->scene = sce;
231   t->view_layer = view_layer;
232   t->area = area;
233   t->region = region;
234   t->settings = ts;
235   t->reports = op ? op->reports : NULL;
236
237   t->helpline = HLP_NONE;
238
239   t->flag = 0;
240
241   if (obact && !(t->options & (CTX_CURSOR | CTX_TEXTURE)) &&
242       ELEM(object_mode, OB_MODE_EDIT, OB_MODE_EDIT_GPENCIL)) {
243     t->obedit_type = obact->type;
244   }
245   else {
246     t->obedit_type = -1;
247   }
248
249   /* Many kinds of transform only use a single handle. */
250   if (t->data_container == NULL) {
251     t->data_container = MEM_callocN(sizeof(*t->data_container), __func__);
252     t->data_container_len = 1;
253   }
254
255   t->redraw = TREDRAW_HARD; /* redraw first time */
256
257   int mval[2];
258   if (event) {
259     copy_v2_v2_int(mval, event->mval);
260   }
261   else {
262     zero_v2_int(mval);
263   }
264   copy_v2_v2_int(t->mval, mval);
265   copy_v2_v2_int(t->mouse.imval, mval);
266   copy_v2_v2_int(t->con.imval, mval);
267
268   t->transform = NULL;
269   t->handleEvent = NULL;
270
271   t->data_len_all = 0;
272
273   zero_v3(t->center_global);
274
275   unit_m3(t->mat);
276
277   /* Default to rotate on the Z axis. */
278   t->orient_axis = 2;
279   t->orient_axis_ortho = 1;
280
281   /* if there's an event, we're modal */
282   if (event) {
283     t->flag |= T_MODAL;
284   }
285
286   /* Crease needs edge flag */
287   if (ELEM(t->mode, TFM_CREASE, TFM_BWEIGHT)) {
288     t->options |= CTX_EDGE;
289   }
290
291   t->remove_on_cancel = false;
292
293   if (op && (prop = RNA_struct_find_property(op->ptr, "remove_on_cancel")) &&
294       RNA_property_is_set(op->ptr, prop)) {
295     if (RNA_property_boolean_get(op->ptr, prop)) {
296       t->remove_on_cancel = true;
297     }
298   }
299
300   /* GPencil editing context */
301   if (GPENCIL_EDIT_MODE(gpd)) {
302     t->options |= CTX_GPENCIL_STROKES;
303   }
304
305   /* Assign the space type, some exceptions for running in different mode */
306   if (area == NULL) {
307     /* background mode */
308     t->spacetype = SPACE_EMPTY;
309   }
310   else if ((region == NULL) && (area->spacetype == SPACE_VIEW3D)) {
311     /* running in the text editor */
312     t->spacetype = SPACE_EMPTY;
313   }
314   else {
315     /* normal operation */
316     t->spacetype = area->spacetype;
317   }
318
319   /* handle T_ALT_TRANSFORM initialization, we may use for different operators */
320   if (op) {
321     const char *prop_id = NULL;
322     if (t->mode == TFM_SHRINKFATTEN) {
323       prop_id = "use_even_offset";
324     }
325
326     if (prop_id && (prop = RNA_struct_find_property(op->ptr, prop_id))) {
327       SET_FLAG_FROM_TEST(t->flag, RNA_property_boolean_get(op->ptr, prop), T_ALT_TRANSFORM);
328     }
329   }
330
331   if (t->spacetype == SPACE_VIEW3D) {
332     View3D *v3d = area->spacedata.first;
333     bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
334
335     t->view = v3d;
336     t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
337
338     /* turn gizmo off during transform */
339     if (t->flag & T_MODAL) {
340       t->gizmo_flag = v3d->gizmo_flag;
341       v3d->gizmo_flag = V3D_GIZMO_HIDE;
342     }
343
344     if (t->scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) {
345       t->flag |= T_V3D_ALIGN;
346     }
347     t->around = t->scene->toolsettings->transform_pivot_point;
348
349     /* bend always uses the cursor */
350     if (t->mode == TFM_BEND) {
351       t->around = V3D_AROUND_CURSOR;
352     }
353
354     /* exceptional case */
355     if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
356       if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
357         const bool use_island = transdata_check_local_islands(t, t->around);
358
359         if ((t->obedit_type != -1) && !use_island) {
360           t->options |= CTX_NO_PET;
361         }
362       }
363     }
364
365     if (object_mode & OB_MODE_ALL_PAINT) {
366       Paint *p = BKE_paint_get_active_from_context(C);
367       if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
368         t->options |= CTX_PAINT_CURVE;
369       }
370     }
371
372     /* initialize UV transform from */
373     if (op && ((prop = RNA_struct_find_property(op->ptr, "correct_uv")))) {
374       if (RNA_property_is_set(op->ptr, prop)) {
375         if (RNA_property_boolean_get(op->ptr, prop)) {
376           t->settings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT_SLIDE;
377         }
378         else {
379           t->settings->uvcalc_flag &= ~UVCALC_TRANSFORM_CORRECT_SLIDE;
380         }
381       }
382       else {
383         RNA_property_boolean_set(
384             op->ptr, prop, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE) != 0);
385       }
386     }
387   }
388   else if (t->spacetype == SPACE_IMAGE) {
389     SpaceImage *sima = area->spacedata.first;
390     /* XXX for now, get View2D from the active region. */
391     t->view = &region->v2d;
392     t->around = sima->around;
393
394     if (ED_space_image_show_uvedit(sima, OBACT(t->view_layer))) {
395       /* UV transform */
396     }
397     else if (sima->mode == SI_MODE_MASK) {
398       t->options |= CTX_MASK;
399     }
400     else if (sima->mode == SI_MODE_PAINT) {
401       Paint *p = &sce->toolsettings->imapaint.paint;
402       if (p->brush && (p->brush->flag & BRUSH_CURVE)) {
403         t->options |= CTX_PAINT_CURVE;
404       }
405     }
406     /* image not in uv edit, nor in mask mode, can happen for some tools */
407   }
408   else if (t->spacetype == SPACE_NODE) {
409     /* XXX for now, get View2D from the active region. */
410     t->view = &region->v2d;
411     t->around = V3D_AROUND_CENTER_BOUNDS;
412   }
413   else if (t->spacetype == SPACE_GRAPH) {
414     SpaceGraph *sipo = area->spacedata.first;
415     t->view = &region->v2d;
416     t->around = sipo->around;
417   }
418   else if (t->spacetype == SPACE_CLIP) {
419     SpaceClip *sclip = area->spacedata.first;
420     t->view = &region->v2d;
421     t->around = sclip->around;
422
423     if (ED_space_clip_check_show_trackedit(sclip)) {
424       t->options |= CTX_MOVIECLIP;
425     }
426     else if (ED_space_clip_check_show_maskedit(sclip)) {
427       t->options |= CTX_MASK;
428     }
429   }
430   else {
431     if (region) {
432       /* XXX for now, get View2D  from the active region */
433       t->view = &region->v2d;
434       /* XXX for now, the center point is the midpoint of the data */
435     }
436     else {
437       t->view = NULL;
438     }
439     t->around = V3D_AROUND_CENTER_BOUNDS;
440   }
441
442   BLI_assert(is_zero_v4(t->values_modal_offset));
443
444   bool use_orient_axis = false;
445   bool t_values_set_is_array = false;
446
447   if (op && (prop = RNA_struct_find_property(op->ptr, "value")) &&
448       RNA_property_is_set(op->ptr, prop)) {
449     float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory  */
450     if (RNA_property_array_check(prop)) {
451       RNA_float_get_array(op->ptr, "value", values);
452       t_values_set_is_array = true;
453     }
454     else {
455       values[0] = RNA_float_get(op->ptr, "value");
456     }
457
458     copy_v4_v4(t->values, values);
459     if (t->flag & T_MODAL) {
460       /* Run before init functions so 'values_modal_offset' can be applied on mouse input. */
461       copy_v4_v4(t->values_modal_offset, values);
462     }
463     else {
464       copy_v4_v4(t->values, values);
465       t->flag |= T_INPUT_IS_VALUES_FINAL;
466     }
467   }
468
469   if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
470     t->orient_axis = RNA_property_enum_get(op->ptr, prop);
471     use_orient_axis = true;
472   }
473
474   if (op && (prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
475     bool constraint_axis[3] = {false, false, false};
476     if (t->flag & T_INPUT_IS_VALUES_FINAL) {
477       if (t_values_set_is_array) {
478         /* For operators whose `t->values` is array, set constraint so that the
479          * orientation is more intuitive in the Redo Panel. */
480         constraint_axis[0] = constraint_axis[1] = constraint_axis[2] = true;
481       }
482       else if (use_orient_axis) {
483         constraint_axis[t->orient_axis] = true;
484       }
485     }
486     else if (RNA_property_is_set(op->ptr, prop)) {
487       RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
488     }
489
490     if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
491       t->con.mode |= CON_APPLY;
492
493       if (constraint_axis[0]) {
494         t->con.mode |= CON_AXIS0;
495       }
496       if (constraint_axis[1]) {
497         t->con.mode |= CON_AXIS1;
498       }
499       if (constraint_axis[2]) {
500         t->con.mode |= CON_AXIS2;
501       }
502     }
503   }
504
505   {
506     short orient_types[3];
507     float custom_matrix[3][3];
508
509     short orient_type_scene = V3D_ORIENT_GLOBAL;
510     short orient_type_set = V3D_ORIENT_GLOBAL;
511     short orient_type_matrix_set = -1;
512
513     if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
514       TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
515       orient_type_scene = orient_slot->type;
516       if (orient_type_scene == V3D_ORIENT_CUSTOM) {
517         const int index_custom = orient_slot->index_custom;
518         orient_type_scene += index_custom;
519       }
520     }
521
522     short orient_type_default = orient_type_scene;
523
524     if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
525       t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
526     }
527
528     if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
529                RNA_property_is_set(op->ptr, prop))) {
530       orient_type_set = RNA_property_enum_get(op->ptr, prop);
531       if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
532         orient_type_set = V3D_ORIENT_GLOBAL;
533       }
534
535       /* Change the default orientation to be used when redoing. */
536       orient_type_default = orient_type_set;
537     }
538     else if (t->con.mode & CON_APPLY) {
539       orient_type_set = orient_type_scene;
540     }
541     else {
542       if (orient_type_set == orient_type_scene) {
543         BLI_assert(orient_type_set == V3D_ORIENT_GLOBAL);
544         orient_type_set = V3D_ORIENT_LOCAL;
545       }
546
547       if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode)) &&
548           (t->mode != TFM_ALIGN)) {
549         orient_type_default = V3D_ORIENT_VIEW;
550       }
551     }
552
553     if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
554                RNA_property_is_set(op->ptr, prop))) {
555       RNA_property_float_get_array(op->ptr, prop, &custom_matrix[0][0]);
556
557       if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
558           RNA_property_is_set(op->ptr, prop)) {
559         orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop);
560       }
561       else {
562         orient_type_matrix_set = orient_type_set;
563       }
564
565       if (orient_type_matrix_set == orient_type_set) {
566         /* Constraints are forced to use the custom matrix when redoing. */
567         orient_type_set = V3D_ORIENT_CUSTOM_MATRIX;
568       }
569     }
570
571     orient_types[0] = orient_type_default;
572     orient_types[1] = orient_type_scene;
573     orient_types[2] = orient_type_set;
574
575     for (int i = 0; i < 3; i++) {
576       /* For efficiency, avoid calculating the same orientation twice. */
577       int j;
578       for (j = 0; j < i; j++) {
579         if (orient_types[j] == orient_types[i]) {
580           memcpy(&t->orient[i], &t->orient[j], sizeof(*t->orient));
581           break;
582         }
583       }
584       if (j == i) {
585         t->orient[i].type = transform_orientation_matrix_get(
586             C, t, orient_types[i], custom_matrix, t->orient[i].matrix);
587       }
588     }
589
590     /* Set orient_curr to -1 in order to force the update in
591      * `transform_orientations_current_set`. */
592     t->orient_curr = -1;
593     transform_orientations_current_set(t, (t->con.mode & CON_APPLY) ? 2 : 0);
594   }
595
596   if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
597              RNA_property_is_set(op->ptr, prop))) {
598     if (RNA_property_boolean_get(op->ptr, prop)) {
599       t->flag |= T_RELEASE_CONFIRM;
600     }
601   }
602   else {
603     /* Release confirms preference should not affect node editor (T69288, T70504). */
604     if (ISMOUSE(t->launch_event) &&
605         ((U.flag & USER_RELEASECONFIRM) || (t->spacetype == SPACE_NODE))) {
606       /* Global "release confirm" on mouse bindings */
607       t->flag |= T_RELEASE_CONFIRM;
608     }
609   }
610
611   if (op && ((prop = RNA_struct_find_property(op->ptr, "mirror")) &&
612              RNA_property_is_set(op->ptr, prop))) {
613     if (!RNA_property_boolean_get(op->ptr, prop)) {
614       t->flag |= T_NO_MIRROR;
615     }
616   }
617   else if ((t->spacetype == SPACE_VIEW3D) && (t->obedit_type == OB_MESH)) {
618     /* pass */
619   }
620   else {
621     /* Avoid mirroring for unsupported contexts. */
622     t->options |= CTX_NO_MIRROR;
623   }
624
625   /* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */
626   if (op && (prop = RNA_struct_find_property(op->ptr, "use_proportional_edit"))) {
627     if (RNA_property_is_set(op->ptr, prop)) {
628       if (RNA_property_boolean_get(op->ptr, prop)) {
629         t->flag |= T_PROP_EDIT;
630         if (RNA_boolean_get(op->ptr, "use_proportional_connected")) {
631           t->flag |= T_PROP_CONNECTED;
632         }
633         if (RNA_boolean_get(op->ptr, "use_proportional_projected")) {
634           t->flag |= T_PROP_PROJECTED;
635         }
636       }
637     }
638     else {
639       /* use settings from scene only if modal */
640       if (t->flag & T_MODAL) {
641         if ((t->options & CTX_NO_PET) == 0) {
642           bool use_prop_edit = false;
643           if (t->spacetype == SPACE_GRAPH) {
644             use_prop_edit = ts->proportional_fcurve;
645           }
646           else if (t->spacetype == SPACE_ACTION) {
647             use_prop_edit = ts->proportional_action;
648           }
649           else if (t->options & CTX_MASK) {
650             use_prop_edit = ts->proportional_mask;
651           }
652           else if (obact && obact->mode == OB_MODE_OBJECT) {
653             use_prop_edit = ts->proportional_objects;
654           }
655           else {
656             use_prop_edit = (ts->proportional_edit & PROP_EDIT_USE) != 0;
657           }
658
659           if (use_prop_edit) {
660             t->flag |= T_PROP_EDIT;
661             if (ts->proportional_edit & PROP_EDIT_CONNECTED) {
662               t->flag |= T_PROP_CONNECTED;
663             }
664             if (ts->proportional_edit & PROP_EDIT_PROJECTED) {
665               t->flag |= T_PROP_PROJECTED;
666             }
667           }
668         }
669       }
670     }
671
672     if (op && ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) &&
673                RNA_property_is_set(op->ptr, prop))) {
674       t->prop_size = RNA_property_float_get(op->ptr, prop);
675     }
676     else {
677       t->prop_size = ts->proportional_size;
678     }
679
680     /* TRANSFORM_FIX_ME rna restrictions */
681     if (t->prop_size <= 0.00001f) {
682       printf("Proportional size (%f) under 0.00001, resetting to 1!\n", t->prop_size);
683       t->prop_size = 1.0f;
684     }
685
686     if (op && ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) &&
687                RNA_property_is_set(op->ptr, prop))) {
688       t->prop_mode = RNA_property_enum_get(op->ptr, prop);
689     }
690     else {
691       t->prop_mode = ts->prop_mode;
692     }
693   }
694   else { /* add not pet option to context when not available */
695     t->options |= CTX_NO_PET;
696   }
697
698   if (t->obedit_type == OB_MESH) {
699     if (op && (prop = RNA_struct_find_property(op->ptr, "use_automerge_and_split")) &&
700         RNA_property_is_set(op->ptr, prop)) {
701       if (RNA_property_boolean_get(op->ptr, prop)) {
702         t->flag |= T_AUTOMERGE | T_AUTOSPLIT;
703       }
704     }
705     else {
706       char automerge = t->scene->toolsettings->automerge;
707       if (automerge & AUTO_MERGE) {
708         t->flag |= T_AUTOMERGE;
709         if (automerge & AUTO_MERGE_AND_SPLIT) {
710           t->flag |= T_AUTOSPLIT;
711         }
712       }
713     }
714   }
715
716   /* Mirror is not supported with PET, turn it off. */
717 #if 0
718   if (t->flag & T_PROP_EDIT) {
719     t->flag &= ~T_MIRROR;
720   }
721 #endif
722
723   setTransformViewAspect(t, t->aspect);
724
725   if (op && (prop = RNA_struct_find_property(op->ptr, "center_override")) &&
726       RNA_property_is_set(op->ptr, prop)) {
727     RNA_property_float_get_array(op->ptr, prop, t->center_global);
728     mul_v3_v3(t->center_global, t->aspect);
729     t->flag |= T_OVERRIDE_CENTER;
730   }
731
732   setTransformViewMatrices(t);
733   initNumInput(&t->num);
734 }
735
736 static void freeTransCustomData(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
737 {
738   if (custom_data->free_cb) {
739     /* Can take over freeing t->data and data_2d etc... */
740     custom_data->free_cb(t, tc, custom_data);
741     BLI_assert(custom_data->data == NULL);
742   }
743   else if ((custom_data->data != NULL) && custom_data->use_free) {
744     MEM_freeN(custom_data->data);
745     custom_data->data = NULL;
746   }
747   /* In case modes are switched in the same transform session. */
748   custom_data->free_cb = NULL;
749   custom_data->use_free = false;
750 }
751
752 static void freeTransCustomDataContainer(TransInfo *t,
753                                          TransDataContainer *tc,
754                                          TransCustomDataContainer *tcdc)
755 {
756   TransCustomData *custom_data = &tcdc->first_elem;
757   for (int i = 0; i < TRANS_CUSTOM_DATA_ELEM_MAX; i++, custom_data++) {
758     freeTransCustomData(t, tc, custom_data);
759   }
760 }
761
762 /**
763  * Needed for mode switching.
764  */
765 void freeTransCustomDataForMode(TransInfo *t)
766 {
767   freeTransCustomData(t, NULL, &t->custom.mode);
768   FOREACH_TRANS_DATA_CONTAINER (t, tc) {
769     freeTransCustomData(t, tc, &tc->custom.mode);
770   }
771 }
772
773 /* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
774 void postTrans(bContext *C, TransInfo *t)
775 {
776   if (t->draw_handle_view) {
777     ED_region_draw_cb_exit(t->region->type, t->draw_handle_view);
778   }
779   if (t->draw_handle_apply) {
780     ED_region_draw_cb_exit(t->region->type, t->draw_handle_apply);
781   }
782   if (t->draw_handle_pixel) {
783     ED_region_draw_cb_exit(t->region->type, t->draw_handle_pixel);
784   }
785   if (t->draw_handle_cursor) {
786     WM_paint_cursor_end(t->draw_handle_cursor);
787   }
788
789   if (t->flag & T_MODAL_CURSOR_SET) {
790     WM_cursor_modal_restore(CTX_wm_window(C));
791   }
792
793   /* Free all custom-data */
794   freeTransCustomDataContainer(t, NULL, &t->custom);
795   FOREACH_TRANS_DATA_CONTAINER (t, tc) {
796     freeTransCustomDataContainer(t, tc, &tc->custom);
797   }
798
799   /* postTrans can be called when nothing is selected, so data is NULL already */
800   if (t->data_len_all != 0) {
801     FOREACH_TRANS_DATA_CONTAINER (t, tc) {
802       /* free data malloced per trans-data */
803       if (ELEM(t->obedit_type, OB_CURVE, OB_SURF, OB_GPENCIL) || (t->spacetype == SPACE_GRAPH)) {
804         TransData *td = tc->data;
805         for (int a = 0; a < tc->data_len; a++, td++) {
806           if (td->flag & TD_BEZTRIPLE) {
807             MEM_freeN(td->hdata);
808           }
809         }
810       }
811       MEM_freeN(tc->data);
812
813       MEM_SAFE_FREE(tc->data_mirror);
814       MEM_SAFE_FREE(tc->data_ext);
815       MEM_SAFE_FREE(tc->data_2d);
816     }
817   }
818
819   MEM_SAFE_FREE(t->data_container);
820   t->data_container = NULL;
821
822   BLI_freelistN(&t->tsnap.points);
823
824   if (t->spacetype == SPACE_IMAGE) {
825     if (t->options & (CTX_MASK | CTX_PAINT_CURVE)) {
826       /* pass */
827     }
828     else {
829       SpaceImage *sima = t->area->spacedata.first;
830       if (sima->flag & SI_LIVE_UNWRAP) {
831         ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL);
832       }
833     }
834   }
835   else if (t->spacetype == SPACE_VIEW3D) {
836     View3D *v3d = t->area->spacedata.first;
837     /* restore gizmo */
838     if (t->flag & T_MODAL) {
839       v3d->gizmo_flag = t->gizmo_flag;
840     }
841   }
842
843   if (t->mouse.data) {
844     MEM_freeN(t->mouse.data);
845   }
846
847   if (t->rng != NULL) {
848     BLI_rng_free(t->rng);
849   }
850
851   freeSnapping(t);
852 }
853
854 void applyTransObjects(TransInfo *t)
855 {
856   TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
857
858   TransData *td;
859
860   for (td = tc->data; td < tc->data + tc->data_len; td++) {
861     copy_v3_v3(td->iloc, td->loc);
862     if (td->ext->rot) {
863       copy_v3_v3(td->ext->irot, td->ext->rot);
864     }
865     if (td->ext->size) {
866       copy_v3_v3(td->ext->isize, td->ext->size);
867     }
868   }
869   recalcData(t);
870 }
871
872 static void transdata_restore_basic(TransDataBasic *td_basic)
873 {
874   /* TransData for crease has no loc */
875   if (td_basic->loc) {
876     copy_v3_v3(td_basic->loc, td_basic->iloc);
877   }
878 }
879
880 static void restoreElement(TransData *td)
881 {
882   transdata_restore_basic((TransDataBasic *)td);
883
884   if (td->val) {
885     *td->val = td->ival;
886   }
887
888   if (td->ext && (td->flag & TD_NO_EXT) == 0) {
889     if (td->ext->rot) {
890       copy_v3_v3(td->ext->rot, td->ext->irot);
891     }
892     if (td->ext->rotAngle) {
893       *td->ext->rotAngle = td->ext->irotAngle;
894     }
895     if (td->ext->rotAxis) {
896       copy_v3_v3(td->ext->rotAxis, td->ext->irotAxis);
897     }
898     /* XXX, drotAngle & drotAxis not used yet */
899     if (td->ext->size) {
900       copy_v3_v3(td->ext->size, td->ext->isize);
901     }
902     if (td->ext->quat) {
903       copy_qt_qt(td->ext->quat, td->ext->iquat);
904     }
905   }
906
907   if (td->flag & TD_BEZTRIPLE) {
908     *(td->hdata->h1) = td->hdata->ih1;
909     *(td->hdata->h2) = td->hdata->ih2;
910   }
911 }
912
913 void restoreTransObjects(TransInfo *t)
914 {
915   FOREACH_TRANS_DATA_CONTAINER (t, tc) {
916
917     TransData *td;
918     TransData2D *td2d;
919     TransDataMirror *tdm;
920
921     for (td = tc->data; td < tc->data + tc->data_len; td++) {
922       restoreElement(td);
923     }
924
925     for (tdm = tc->data_mirror; tdm < tc->data_mirror + tc->data_mirror_len; tdm++) {
926       transdata_restore_basic((TransDataBasic *)tdm);
927     }
928
929     for (td2d = tc->data_2d; tc->data_2d && td2d < tc->data_2d + tc->data_len; td2d++) {
930       if (td2d->h1) {
931         td2d->h1[0] = td2d->ih1[0];
932         td2d->h1[1] = td2d->ih1[1];
933       }
934       if (td2d->h2) {
935         td2d->h2[0] = td2d->ih2[0];
936         td2d->h2[1] = td2d->ih2[1];
937       }
938     }
939
940     unit_m3(t->mat);
941   }
942
943   recalcData(t);
944 }
945
946 void calculateCenter2D(TransInfo *t)
947 {
948   BLI_assert(!is_zero_v3(t->aspect));
949   projectFloatView(t, t->center_global, t->center2d);
950 }
951
952 void calculateCenterLocal(TransInfo *t, const float center_global[3])
953 {
954   /* setting constraint center */
955   /* note, init functions may over-ride t->center */
956   FOREACH_TRANS_DATA_CONTAINER (t, tc) {
957     if (tc->use_local_mat) {
958       mul_v3_m4v3(tc->center_local, tc->imat, center_global);
959     }
960     else {
961       copy_v3_v3(tc->center_local, center_global);
962     }
963   }
964 }
965
966 void calculateCenterCursor(TransInfo *t, float r_center[3])
967 {
968   const float *cursor = t->scene->cursor.location;
969   copy_v3_v3(r_center, cursor);
970
971   /* If edit or pose mode, move cursor in local space */
972   if (t->options & CTX_PAINT_CURVE) {
973     if (ED_view3d_project_float_global(t->region, cursor, r_center, V3D_PROJ_TEST_NOP) !=
974         V3D_PROJ_RET_OK) {
975       r_center[0] = t->region->winx / 2.0f;
976       r_center[1] = t->region->winy / 2.0f;
977     }
978     r_center[2] = 0.0f;
979   }
980 }
981
982 void calculateCenterCursor2D(TransInfo *t, float r_center[2])
983 {
984   const float *cursor = NULL;
985
986   if (t->spacetype == SPACE_IMAGE) {
987     SpaceImage *sima = (SpaceImage *)t->area->spacedata.first;
988     cursor = sima->cursor;
989   }
990   else if (t->spacetype == SPACE_CLIP) {
991     SpaceClip *space_clip = (SpaceClip *)t->area->spacedata.first;
992     cursor = space_clip->cursor;
993   }
994
995   if (cursor) {
996     if (t->options & CTX_MASK) {
997       float co[2];
998
999       if (t->spacetype == SPACE_IMAGE) {
1000         SpaceImage *sima = (SpaceImage *)t->area->spacedata.first;
1001         BKE_mask_coord_from_image(sima->image, &sima->iuser, co, cursor);
1002       }
1003       else if (t->spacetype == SPACE_CLIP) {
1004         SpaceClip *space_clip = (SpaceClip *)t->area->spacedata.first;
1005         BKE_mask_coord_from_movieclip(space_clip->clip, &space_clip->user, co, cursor);
1006       }
1007       else {
1008         BLI_assert(!"Shall not happen");
1009       }
1010
1011       r_center[0] = co[0] * t->aspect[0];
1012       r_center[1] = co[1] * t->aspect[1];
1013     }
1014     else if (t->options & CTX_PAINT_CURVE) {
1015       if (t->spacetype == SPACE_IMAGE) {
1016         r_center[0] = UI_view2d_view_to_region_x(&t->region->v2d, cursor[0]);
1017         r_center[1] = UI_view2d_view_to_region_y(&t->region->v2d, cursor[1]);
1018       }
1019     }
1020     else {
1021       r_center[0] = cursor[0] * t->aspect[0];
1022       r_center[1] = cursor[1] * t->aspect[1];
1023     }
1024   }
1025 }
1026
1027 void calculateCenterCursorGraph2D(TransInfo *t, float r_center[2])
1028 {
1029   SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
1030   Scene *scene = t->scene;
1031
1032   /* cursor is combination of current frame, and graph-editor cursor value */
1033   if (sipo->mode == SIPO_MODE_DRIVERS) {
1034     r_center[0] = sipo->cursorTime;
1035     r_center[1] = sipo->cursorVal;
1036   }
1037   else {
1038     r_center[0] = (float)(scene->r.cfra);
1039     r_center[1] = sipo->cursorVal;
1040   }
1041 }
1042
1043 static bool transdata_center_global_get(const TransDataContainer *tc,
1044                                         const TransDataBasic *td_basic,
1045                                         float r_vec[3])
1046 {
1047   if (td_basic->flag & TD_SELECTED) {
1048     if (!(td_basic->flag & TD_NOCENTER)) {
1049       if (tc->use_local_mat) {
1050         mul_v3_m4v3(r_vec, tc->mat, td_basic->center);
1051       }
1052       else {
1053         copy_v3_v3(r_vec, td_basic->center);
1054       }
1055       return true;
1056     }
1057   }
1058   return false;
1059 }
1060
1061 void calculateCenterMedian(TransInfo *t, float r_center[3])
1062 {
1063   float partial[3] = {0.0f, 0.0f, 0.0f};
1064   int total = 0;
1065
1066   FOREACH_TRANS_DATA_CONTAINER (t, tc) {
1067     float center[3];
1068     for (int i = 0; i < tc->data_len; i++) {
1069       if (transdata_center_global_get(tc, (TransDataBasic *)&tc->data[i], center)) {
1070         add_v3_v3(partial, center);
1071         total++;
1072       }
1073     }
1074     for (int i = 0; i < tc->data_mirror_len; i++) {
1075       if (transdata_center_global_get(tc, (TransDataBasic *)&tc->data_mirror[i], center)) {
1076         add_v3_v3(partial, center);
1077         total++;
1078       }
1079     }
1080   }
1081   if (total) {
1082     mul_v3_fl(partial, 1.0f / (float)total);
1083   }
1084   copy_v3_v3(r_center, partial);
1085 }
1086
1087 void calculateCenterBound(TransInfo *t, float r_center[3])
1088 {
1089   float max[3], min[3];
1090   bool changed = false;
1091   INIT_MINMAX(min, max);
1092   FOREACH_TRANS_DATA_CONTAINER (t, tc) {
1093     float center[3];
1094     for (int i = 0; i < tc->data_len; i++) {
1095       if (transdata_center_global_get(tc, (TransDataBasic *)&tc->data[i], center)) {
1096         minmax_v3v3_v3(min, max, center);
1097         changed = true;
1098       }
1099     }
1100     for (int i = 0; i < tc->data_mirror_len; i++) {
1101       if (transdata_center_global_get(tc, (TransDataBasic *)&tc->data_mirror[i], center)) {
1102         minmax_v3v3_v3(min, max, center);
1103         changed = true;
1104       }
1105     }
1106   }
1107   if (changed) {
1108     mid_v3_v3v3(r_center, min, max);
1109   }
1110 }
1111
1112 /**
1113  * \param select_only: only get active center from data being transformed.
1114  */
1115 bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
1116 {
1117   TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
1118
1119   if (t->spacetype != SPACE_VIEW3D) {
1120     return false;
1121   }
1122   if (tc->obedit) {
1123     if (ED_object_calc_active_center_for_editmode(tc->obedit, select_only, r_center)) {
1124       mul_m4_v3(tc->obedit->obmat, r_center);
1125       return true;
1126     }
1127   }
1128   else if (t->flag & T_POSE) {
1129     ViewLayer *view_layer = t->view_layer;
1130     Object *ob = OBACT(view_layer);
1131     if (ED_object_calc_active_center_for_posemode(ob, select_only, r_center)) {
1132       mul_m4_v3(ob->obmat, r_center);
1133       return true;
1134     }
1135   }
1136   else if (t->options & CTX_PAINT_CURVE) {
1137     Paint *p = BKE_paint_get_active(t->scene, t->view_layer);
1138     Brush *br = p->brush;
1139     PaintCurve *pc = br->paint_curve;
1140     copy_v3_v3(r_center, pc->points[pc->add_index - 1].bez.vec[1]);
1141     r_center[2] = 0.0f;
1142     return true;
1143   }
1144   else {
1145     /* object mode */
1146     ViewLayer *view_layer = t->view_layer;
1147     Object *ob = OBACT(view_layer);
1148     Base *base = BASACT(view_layer);
1149     if (ob && ((!select_only) || ((base->flag & BASE_SELECTED) != 0))) {
1150       copy_v3_v3(r_center, ob->obmat[3]);
1151       return true;
1152     }
1153   }
1154
1155   return false;
1156 }
1157
1158 static void calculateCenter_FromAround(TransInfo *t, int around, float r_center[3])
1159 {
1160   switch (around) {
1161     case V3D_AROUND_CENTER_BOUNDS:
1162       calculateCenterBound(t, r_center);
1163       break;
1164     case V3D_AROUND_CENTER_MEDIAN:
1165       calculateCenterMedian(t, r_center);
1166       break;
1167     case V3D_AROUND_CURSOR:
1168       if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
1169         calculateCenterCursor2D(t, r_center);
1170       }
1171       else if (t->spacetype == SPACE_GRAPH) {
1172         calculateCenterCursorGraph2D(t, r_center);
1173       }
1174       else {
1175         calculateCenterCursor(t, r_center);
1176       }
1177       break;
1178     case V3D_AROUND_LOCAL_ORIGINS:
1179       /* Individual element center uses median center for helpline and such */
1180       calculateCenterMedian(t, r_center);
1181       break;
1182     case V3D_AROUND_ACTIVE: {
1183       if (calculateCenterActive(t, false, r_center)) {
1184         /* pass */
1185       }
1186       else {
1187         /* fallback */
1188         calculateCenterMedian(t, r_center);
1189       }
1190       break;
1191     }
1192   }
1193 }
1194
1195 void calculateCenter(TransInfo *t)
1196 {
1197   if ((t->flag & T_OVERRIDE_CENTER) == 0) {
1198     calculateCenter_FromAround(t, t->around, t->center_global);
1199   }
1200   calculateCenterLocal(t, t->center_global);
1201
1202   /* avoid calculating again */
1203   {
1204     TransCenterData *cd = &t->center_cache[t->around];
1205     copy_v3_v3(cd->global, t->center_global);
1206     cd->is_set = true;
1207   }
1208
1209   calculateCenter2D(t);
1210
1211   /* for panning from cameraview */
1212   if ((t->flag & T_OBJECT) && (t->flag & T_OVERRIDE_CENTER) == 0) {
1213     if (t->spacetype == SPACE_VIEW3D && t->region && t->region->regiontype == RGN_TYPE_WINDOW) {
1214
1215       if (t->flag & T_CAMERA) {
1216         float axis[3];
1217         /* persinv is nasty, use viewinv instead, always right */
1218         copy_v3_v3(axis, t->viewinv[2]);
1219         normalize_v3(axis);
1220
1221         /* 6.0 = 6 grid units */
1222         axis[0] = t->center_global[0] - 6.0f * axis[0];
1223         axis[1] = t->center_global[1] - 6.0f * axis[1];
1224         axis[2] = t->center_global[2] - 6.0f * axis[2];
1225
1226         projectFloatView(t, axis, t->center2d);
1227
1228         /* rotate only needs correct 2d center, grab needs ED_view3d_calc_zfac() value */
1229         if (t->mode == TFM_TRANSLATION) {
1230           copy_v3_v3(t->center_global, axis);
1231         }
1232       }
1233     }
1234   }
1235
1236   if (t->spacetype == SPACE_VIEW3D) {
1237     /* ED_view3d_calc_zfac() defines a factor for perspective depth correction,
1238      * used in ED_view3d_win_to_delta() */
1239
1240     /* zfac is only used convertViewVec only in cases operator was invoked in RGN_TYPE_WINDOW
1241      * and never used in other cases.
1242      *
1243      * We need special case here as well, since ED_view3d_calc_zfac will crash when called
1244      * for a region different from RGN_TYPE_WINDOW.
1245      */
1246     if (t->region->regiontype == RGN_TYPE_WINDOW) {
1247       t->zfac = ED_view3d_calc_zfac(t->region->regiondata, t->center_global, NULL);
1248     }
1249     else {
1250       t->zfac = 0.0f;
1251     }
1252   }
1253 }
1254
1255 BLI_STATIC_ASSERT(ARRAY_SIZE(((TransInfo *)NULL)->center_cache) == (V3D_AROUND_ACTIVE + 1),
1256                   "test size");
1257
1258 /**
1259  * Lazy initialize transform center data, when we need to access center values from other types.
1260  */
1261 const TransCenterData *transformCenter_from_type(TransInfo *t, int around)
1262 {
1263   BLI_assert(around <= V3D_AROUND_ACTIVE);
1264   TransCenterData *cd = &t->center_cache[around];
1265   if (cd->is_set == false) {
1266     calculateCenter_FromAround(t, around, cd->global);
1267     cd->is_set = true;
1268   }
1269   return cd;
1270 }
1271
1272 void calculatePropRatio(TransInfo *t)
1273 {
1274   int i;
1275   float dist;
1276   const bool connected = (t->flag & T_PROP_CONNECTED) != 0;
1277
1278   t->proptext[0] = '\0';
1279
1280   if (t->flag & T_PROP_EDIT) {
1281     const char *pet_id = NULL;
1282     FOREACH_TRANS_DATA_CONTAINER (t, tc) {
1283       TransData *td = tc->data;
1284       for (i = 0; i < tc->data_len; i++, td++) {
1285         if (td->flag & TD_SELECTED) {
1286           td->factor = 1.0f;
1287         }
1288         else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) ||
1289                  (connected == 0 && td->rdist > t->prop_size)) {
1290           td->factor = 0.0f;
1291           restoreElement(td);
1292         }
1293         else {
1294           /* Use rdist for falloff calculations, it is the real distance */
1295           if (connected) {
1296             dist = (t->prop_size - td->dist) / t->prop_size;
1297           }
1298           else {
1299             dist = (t->prop_size - td->rdist) / t->prop_size;
1300           }
1301
1302           /*
1303            * Clamp to positive numbers.
1304            * Certain corner cases with connectivity and individual centers
1305            * can give values of rdist larger than propsize.
1306            */
1307           if (dist < 0.0f) {
1308             dist = 0.0f;
1309           }
1310
1311           switch (t->prop_mode) {
1312             case PROP_SHARP:
1313               td->factor = dist * dist;
1314               break;
1315             case PROP_SMOOTH:
1316               td->factor = 3.0f * dist * dist - 2.0f * dist * dist * dist;
1317               break;
1318             case PROP_ROOT:
1319               td->factor = sqrtf(dist);
1320               break;
1321             case PROP_LIN:
1322               td->factor = dist;
1323               break;
1324             case PROP_CONST:
1325               td->factor = 1.0f;
1326               break;
1327             case PROP_SPHERE:
1328               td->factor = sqrtf(2 * dist - dist * dist);
1329               break;
1330             case PROP_RANDOM:
1331               if (t->rng == NULL) {
1332                 /* Lazy initialization. */
1333                 uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
1334                 t->rng = BLI_rng_new(rng_seed);
1335               }
1336               td->factor = BLI_rng_get_float(t->rng) * dist;
1337               break;
1338             case PROP_INVSQUARE:
1339               td->factor = dist * (2.0f - dist);
1340               break;
1341             default:
1342               td->factor = 1;
1343               break;
1344           }
1345         }
1346       }
1347     }
1348
1349     switch (t->prop_mode) {
1350       case PROP_SHARP:
1351         pet_id = N_("(Sharp)");
1352         break;
1353       case PROP_SMOOTH:
1354         pet_id = N_("(Smooth)");
1355         break;
1356       case PROP_ROOT:
1357         pet_id = N_("(Root)");
1358         break;
1359       case PROP_LIN:
1360         pet_id = N_("(Linear)");
1361         break;
1362       case PROP_CONST:
1363         pet_id = N_("(Constant)");
1364         break;
1365       case PROP_SPHERE:
1366         pet_id = N_("(Sphere)");
1367         break;
1368       case PROP_RANDOM:
1369         pet_id = N_("(Random)");
1370         break;
1371       case PROP_INVSQUARE:
1372         pet_id = N_("(InvSquare)");
1373         break;
1374       default:
1375         break;
1376     }
1377
1378     if (pet_id) {
1379       BLI_strncpy(t->proptext, IFACE_(pet_id), sizeof(t->proptext));
1380     }
1381   }
1382   else {
1383     FOREACH_TRANS_DATA_CONTAINER (t, tc) {
1384       TransData *td = tc->data;
1385       for (i = 0; i < tc->data_len; i++, td++) {
1386         td->factor = 1.0;
1387       }
1388     }
1389   }
1390 }
1391
1392 /**
1393  * Rotate an element, low level code, ignore protected channels.
1394  * (use for objects or pose-bones)
1395  * Similar to #ElementRotation.
1396  */
1397 void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot)
1398 {
1399   float totmat[3][3];
1400   float smat[3][3];
1401   float fmat[3][3];
1402   float obmat[3][3];
1403
1404   float dmat[3][3]; /* delta rotation */
1405   float dmat_inv[3][3];
1406
1407   mul_m3_m3m3(totmat, mat, td->mtx);
1408   mul_m3_m3m3(smat, td->smtx, mat);
1409
1410   /* logic from BKE_object_rot_to_mat3 */
1411   if (use_drot) {
1412     if (td->ext->rotOrder > 0) {
1413       eulO_to_mat3(dmat, td->ext->drot, td->ext->rotOrder);
1414     }
1415     else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
1416 #if 0
1417       axis_angle_to_mat3(dmat, td->ext->drotAxis, td->ext->drotAngle);
1418 #else
1419       unit_m3(dmat);
1420 #endif
1421     }
1422     else {
1423       float tquat[4];
1424       normalize_qt_qt(tquat, td->ext->dquat);
1425       quat_to_mat3(dmat, tquat);
1426     }
1427
1428     invert_m3_m3(dmat_inv, dmat);
1429   }
1430
1431   if (td->ext->rotOrder == ROT_MODE_QUAT) {
1432     float quat[4];
1433
1434     /* calculate the total rotatation */
1435     quat_to_mat3(obmat, td->ext->iquat);
1436     if (use_drot) {
1437       mul_m3_m3m3(obmat, dmat, obmat);
1438     }
1439
1440     /* mat = transform, obmat = object rotation */
1441     mul_m3_m3m3(fmat, smat, obmat);
1442
1443     if (use_drot) {
1444       mul_m3_m3m3(fmat, dmat_inv, fmat);
1445     }
1446
1447     mat3_to_quat(quat, fmat);
1448
1449     /* apply */
1450     copy_qt_qt(td->ext->quat, quat);
1451   }
1452   else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
1453     float axis[3], angle;
1454
1455     /* calculate the total rotatation */
1456     axis_angle_to_mat3(obmat, td->ext->irotAxis, td->ext->irotAngle);
1457     if (use_drot) {
1458       mul_m3_m3m3(obmat, dmat, obmat);
1459     }
1460
1461     /* mat = transform, obmat = object rotation */
1462     mul_m3_m3m3(fmat, smat, obmat);
1463
1464     if (use_drot) {
1465       mul_m3_m3m3(fmat, dmat_inv, fmat);
1466     }
1467
1468     mat3_to_axis_angle(axis, &angle, fmat);
1469
1470     /* apply */
1471     copy_v3_v3(td->ext->rotAxis, axis);
1472     *td->ext->rotAngle = angle;
1473   }
1474   else {
1475     float eul[3];
1476
1477     /* calculate the total rotatation */
1478     eulO_to_mat3(obmat, td->ext->irot, td->ext->rotOrder);
1479     if (use_drot) {
1480       mul_m3_m3m3(obmat, dmat, obmat);
1481     }
1482
1483     /* mat = transform, obmat = object rotation */
1484     mul_m3_m3m3(fmat, smat, obmat);
1485
1486     if (use_drot) {
1487       mul_m3_m3m3(fmat, dmat_inv, fmat);
1488     }
1489
1490     mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
1491
1492     /* apply */
1493     copy_v3_v3(td->ext->rot, eul);
1494   }
1495 }