Manipulator: Use object bound-box for scale cage
[blender.git] / source / blender / editors / transform / transform_manipulator.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2005 Blender Foundation
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/transform/transform_manipulator.c
29  *  \ingroup edtransform
30  */
31
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36 #include <float.h>
37
38 #include "DNA_armature_types.h"
39 #include "DNA_curve_types.h"
40 #include "DNA_gpencil_types.h"
41 #include "DNA_lattice_types.h"
42 #include "DNA_meta_types.h"
43 #include "DNA_screen_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_view3d_types.h"
46
47 #include "BLI_listbase.h"
48 #include "BLI_math.h"
49 #include "BLI_utildefines.h"
50
51 #include "RNA_access.h"
52
53 #include "BKE_action.h"
54 #include "BKE_context.h"
55 #include "BKE_curve.h"
56 #include "BKE_global.h"
57 #include "BKE_particle.h"
58 #include "BKE_pointcache.h"
59 #include "BKE_editmesh.h"
60 #include "BKE_lattice.h"
61 #include "BKE_gpencil.h"
62 #include "BKE_workspace.h"
63
64 #include "BIF_gl.h"
65
66 #include "WM_api.h"
67 #include "WM_types.h"
68
69 #include "ED_armature.h"
70 #include "ED_curve.h"
71 #include "ED_object.h"
72 #include "ED_particle.h"
73 #include "ED_view3d.h"
74 #include "ED_gpencil.h"
75 #include "ED_screen.h"
76 #include "ED_manipulator_library.h"
77
78 #include "UI_resources.h"
79
80 /* local module include */
81 #include "transform.h"
82
83 #include "MEM_guardedalloc.h"
84
85 #include "GPU_select.h"
86 #include "GPU_immediate.h"
87 #include "GPU_matrix.h"
88
89 #define USE_AXIS_BOUNDS
90
91 /* return codes for select, and drawing flags */
92
93 #define MAN_TRANS_X             (1 << 0)
94 #define MAN_TRANS_Y             (1 << 1)
95 #define MAN_TRANS_Z             (1 << 2)
96 #define MAN_TRANS_C             (MAN_TRANS_X | MAN_TRANS_Y | MAN_TRANS_Z)
97
98 #define MAN_ROT_X               (1 << 3)
99 #define MAN_ROT_Y               (1 << 4)
100 #define MAN_ROT_Z               (1 << 5)
101 #define MAN_ROT_C               (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z)
102
103 #define MAN_SCALE_X             (1 << 8)
104 #define MAN_SCALE_Y             (1 << 9)
105 #define MAN_SCALE_Z             (1 << 10)
106 #define MAN_SCALE_C             (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z)
107
108 /* threshold for testing view aligned manipulator axis */
109 #define TW_AXIS_DOT_MIN 0.02f
110 #define TW_AXIS_DOT_MAX 0.1f
111
112 /* axes as index */
113 enum {
114         MAN_AXIS_TRANS_X = 0,
115         MAN_AXIS_TRANS_Y,
116         MAN_AXIS_TRANS_Z,
117         MAN_AXIS_TRANS_C,
118
119         MAN_AXIS_TRANS_XY,
120         MAN_AXIS_TRANS_YZ,
121         MAN_AXIS_TRANS_ZX,
122 #define MAN_AXIS_RANGE_TRANS_START MAN_AXIS_TRANS_X
123 #define MAN_AXIS_RANGE_TRANS_END (MAN_AXIS_TRANS_ZX + 1)
124
125         MAN_AXIS_ROT_X,
126         MAN_AXIS_ROT_Y,
127         MAN_AXIS_ROT_Z,
128         MAN_AXIS_ROT_C,
129         MAN_AXIS_ROT_T, /* trackball rotation */
130 #define MAN_AXIS_RANGE_ROT_START MAN_AXIS_ROT_X
131 #define MAN_AXIS_RANGE_ROT_END (MAN_AXIS_ROT_T + 1)
132
133         MAN_AXIS_SCALE_X,
134         MAN_AXIS_SCALE_Y,
135         MAN_AXIS_SCALE_Z,
136         MAN_AXIS_SCALE_C,
137         MAN_AXIS_SCALE_XY,
138         MAN_AXIS_SCALE_YZ,
139         MAN_AXIS_SCALE_ZX,
140 #define MAN_AXIS_RANGE_SCALE_START MAN_AXIS_SCALE_X
141 #define MAN_AXIS_RANGE_SCALE_END (MAN_AXIS_SCALE_ZX + 1)
142
143         MAN_AXIS_LAST = MAN_AXIS_RANGE_SCALE_END,
144 };
145
146 /* axis types */
147 enum {
148         MAN_AXES_ALL = 0,
149         MAN_AXES_TRANSLATE,
150         MAN_AXES_ROTATE,
151         MAN_AXES_SCALE,
152 };
153
154 typedef struct ManipulatorGroup {
155         bool all_hidden;
156
157         struct wmManipulator *manipulators[MAN_AXIS_LAST];
158 } ManipulatorGroup;
159
160 struct TransformBounds {
161         float center[3];                /* Center for transform widget. */
162         float min[3], max[3];   /* Boundbox of selection for transform widget. */
163
164 #ifdef USE_AXIS_BOUNDS
165         /* Normalized axis */
166         float axis[3][3];
167         float axis_min[3], axis_max[3];
168 #endif
169 };
170
171 /* -------------------------------------------------------------------- */
172 /** \name Utilities
173  * \{ */
174
175 /* loop over axes */
176 #define MAN_ITER_AXES_BEGIN(axis, axis_idx) \
177         { \
178                 wmManipulator *axis; \
179                 int axis_idx; \
180                 for (axis_idx = 0; axis_idx < MAN_AXIS_LAST; axis_idx++) { \
181                         axis = manipulator_get_axis_from_index(man, axis_idx);
182
183 #define MAN_ITER_AXES_END \
184                 } \
185         } ((void)0)
186
187 static wmManipulator *manipulator_get_axis_from_index(const ManipulatorGroup *man, const short axis_idx)
188 {
189         BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN_AXIS_TRANS_X, (float)MAN_AXIS_LAST));
190         return man->manipulators[axis_idx];
191 }
192
193 static short manipulator_get_axis_type(const int axis_idx)
194 {
195         if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
196                 return MAN_AXES_TRANSLATE;
197         }
198         if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) {
199                 return MAN_AXES_ROTATE;
200         }
201         if (axis_idx >= MAN_AXIS_RANGE_SCALE_START && axis_idx < MAN_AXIS_RANGE_SCALE_END) {
202                 return MAN_AXES_SCALE;
203         }
204         BLI_assert(0);
205         return -1;
206 }
207
208 static uint manipulator_orientation_axis(const int axis_idx, bool *r_is_plane)
209 {
210         switch (axis_idx) {
211                 case MAN_AXIS_TRANS_YZ:
212                 case MAN_AXIS_SCALE_YZ:
213                         if (r_is_plane) {
214                                 *r_is_plane = true;
215                         }
216                         ATTR_FALLTHROUGH;
217                 case MAN_AXIS_TRANS_X:
218                 case MAN_AXIS_ROT_X:
219                 case MAN_AXIS_SCALE_X:
220                         return 0;
221
222                 case MAN_AXIS_TRANS_ZX:
223                 case MAN_AXIS_SCALE_ZX:
224                         if (r_is_plane) {
225                                 *r_is_plane = true;
226                         }
227                         ATTR_FALLTHROUGH;
228                 case MAN_AXIS_TRANS_Y:
229                 case MAN_AXIS_ROT_Y:
230                 case MAN_AXIS_SCALE_Y:
231                         return 1;
232
233                 case MAN_AXIS_TRANS_XY:
234                 case MAN_AXIS_SCALE_XY:
235                         if (r_is_plane) {
236                                 *r_is_plane = true;
237                         }
238                         ATTR_FALLTHROUGH;
239                 case MAN_AXIS_TRANS_Z:
240                 case MAN_AXIS_ROT_Z:
241                 case MAN_AXIS_SCALE_Z:
242                         return 2;
243         }
244         return 3;
245 }
246
247 static bool manipulator_is_axis_visible(
248         const View3D *v3d, const RegionView3D *rv3d,
249         const float idot[3], const int axis_type, const int axis_idx)
250 {
251         bool is_plane = false;
252         const uint aidx_norm = manipulator_orientation_axis(axis_idx, &is_plane);
253         /* don't draw axis perpendicular to the view */
254         if (aidx_norm < 3) {
255                 float idot_axis = idot[aidx_norm];
256                 if (is_plane) {
257                         idot_axis = 1.0f - idot_axis;
258                 }
259                 if (idot_axis < TW_AXIS_DOT_MIN) {
260                         return false;
261                 }
262         }
263
264         if ((axis_type == MAN_AXES_TRANSLATE && !(v3d->twtype & V3D_MANIP_TRANSLATE)) ||
265             (axis_type == MAN_AXES_ROTATE && !(v3d->twtype & V3D_MANIP_ROTATE)) ||
266             (axis_type == MAN_AXES_SCALE && !(v3d->twtype & V3D_MANIP_SCALE)))
267         {
268                 return false;
269         }
270
271         switch (axis_idx) {
272                 case MAN_AXIS_TRANS_X:
273                         return (rv3d->twdrawflag & MAN_TRANS_X);
274                 case MAN_AXIS_TRANS_Y:
275                         return (rv3d->twdrawflag & MAN_TRANS_Y);
276                 case MAN_AXIS_TRANS_Z:
277                         return (rv3d->twdrawflag & MAN_TRANS_Z);
278                 case MAN_AXIS_TRANS_C:
279                         return (rv3d->twdrawflag & MAN_TRANS_C);
280                 case MAN_AXIS_ROT_X:
281                         return (rv3d->twdrawflag & MAN_ROT_X);
282                 case MAN_AXIS_ROT_Y:
283                         return (rv3d->twdrawflag & MAN_ROT_Y);
284                 case MAN_AXIS_ROT_Z:
285                         return (rv3d->twdrawflag & MAN_ROT_Z);
286                 case MAN_AXIS_ROT_C:
287                 case MAN_AXIS_ROT_T:
288                         return (rv3d->twdrawflag & MAN_ROT_C);
289                 case MAN_AXIS_SCALE_X:
290                         return (rv3d->twdrawflag & MAN_SCALE_X);
291                 case MAN_AXIS_SCALE_Y:
292                         return (rv3d->twdrawflag & MAN_SCALE_Y);
293                 case MAN_AXIS_SCALE_Z:
294                         return (rv3d->twdrawflag & MAN_SCALE_Z);
295                 case MAN_AXIS_SCALE_C:
296                         return (rv3d->twdrawflag & MAN_SCALE_C && (v3d->twtype & V3D_MANIP_TRANSLATE) == 0);
297                 case MAN_AXIS_TRANS_XY:
298                         return (rv3d->twdrawflag & MAN_TRANS_X &&
299                                 rv3d->twdrawflag & MAN_TRANS_Y &&
300                                 (v3d->twtype & V3D_MANIP_ROTATE) == 0);
301                 case MAN_AXIS_TRANS_YZ:
302                         return (rv3d->twdrawflag & MAN_TRANS_Y &&
303                                 rv3d->twdrawflag & MAN_TRANS_Z &&
304                                 (v3d->twtype & V3D_MANIP_ROTATE) == 0);
305                 case MAN_AXIS_TRANS_ZX:
306                         return (rv3d->twdrawflag & MAN_TRANS_Z &&
307                                 rv3d->twdrawflag & MAN_TRANS_X &&
308                                 (v3d->twtype & V3D_MANIP_ROTATE) == 0);
309                 case MAN_AXIS_SCALE_XY:
310                         return (rv3d->twdrawflag & MAN_SCALE_X &&
311                                 rv3d->twdrawflag & MAN_SCALE_Y &&
312                                 (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 &&
313                                 (v3d->twtype & V3D_MANIP_ROTATE) == 0);
314                 case MAN_AXIS_SCALE_YZ:
315                         return (rv3d->twdrawflag & MAN_SCALE_Y &&
316                                 rv3d->twdrawflag & MAN_SCALE_Z &&
317                                 (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 &&
318                                 (v3d->twtype & V3D_MANIP_ROTATE) == 0);
319                 case MAN_AXIS_SCALE_ZX:
320                         return (rv3d->twdrawflag & MAN_SCALE_Z &&
321                                 rv3d->twdrawflag & MAN_SCALE_X &&
322                                 (v3d->twtype & V3D_MANIP_TRANSLATE) == 0 &&
323                                 (v3d->twtype & V3D_MANIP_ROTATE) == 0);
324         }
325         return false;
326 }
327
328 static void manipulator_get_axis_color(
329         const int axis_idx, const float idot[3],
330         float r_col[4], float r_col_hi[4])
331 {
332         /* alpha values for normal/highlighted states */
333         const float alpha = 0.6f;
334         const float alpha_hi = 1.0f;
335         float alpha_fac;
336
337         bool is_plane = false;
338         const int axis_idx_norm = manipulator_orientation_axis(axis_idx, &is_plane);
339         /* get alpha fac based on axis angle, to fade axis out when hiding it because it points towards view */
340         if (axis_idx_norm < 3) {
341                 float idot_axis = idot[axis_idx_norm];
342                 if (is_plane) {
343                         idot_axis = 1.0f - idot_axis;
344                 }
345                 alpha_fac = (idot_axis > TW_AXIS_DOT_MAX) ?
346                         1.0f : (idot_axis < TW_AXIS_DOT_MIN) ?
347                         0.0f : ((idot_axis - TW_AXIS_DOT_MIN) / (TW_AXIS_DOT_MAX - TW_AXIS_DOT_MIN));
348         }
349         else {
350                 /* trackball rotation axis is a special case, we only draw a slight overlay */
351                 alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.1f : 1.0f;
352         }
353
354         switch (axis_idx) {
355                 case MAN_AXIS_TRANS_X:
356                 case MAN_AXIS_ROT_X:
357                 case MAN_AXIS_SCALE_X:
358                 case MAN_AXIS_TRANS_YZ:
359                 case MAN_AXIS_SCALE_YZ:
360                         UI_GetThemeColor4fv(TH_AXIS_X, r_col);
361                         break;
362                 case MAN_AXIS_TRANS_Y:
363                 case MAN_AXIS_ROT_Y:
364                 case MAN_AXIS_SCALE_Y:
365                 case MAN_AXIS_TRANS_ZX:
366                 case MAN_AXIS_SCALE_ZX:
367                         UI_GetThemeColor4fv(TH_AXIS_Y, r_col);
368                         break;
369                 case MAN_AXIS_TRANS_Z:
370                 case MAN_AXIS_ROT_Z:
371                 case MAN_AXIS_SCALE_Z:
372                 case MAN_AXIS_TRANS_XY:
373                 case MAN_AXIS_SCALE_XY:
374                         UI_GetThemeColor4fv(TH_AXIS_Z, r_col);
375                         break;
376                 case MAN_AXIS_TRANS_C:
377                 case MAN_AXIS_ROT_C:
378                 case MAN_AXIS_SCALE_C:
379                 case MAN_AXIS_ROT_T:
380                         copy_v4_fl(r_col, 1.0f);
381                         break;
382         }
383
384         copy_v4_v4(r_col_hi, r_col);
385
386         r_col[3] = alpha * alpha_fac;
387         r_col_hi[3] = alpha_hi * alpha_fac;
388 }
389
390 static void manipulator_get_axis_constraint(const int axis_idx, int r_axis[3])
391 {
392         zero_v3_int(r_axis);
393
394         switch (axis_idx) {
395                 case MAN_AXIS_TRANS_X:
396                 case MAN_AXIS_ROT_X:
397                 case MAN_AXIS_SCALE_X:
398                         r_axis[0] = 1;
399                         break;
400                 case MAN_AXIS_TRANS_Y:
401                 case MAN_AXIS_ROT_Y:
402                 case MAN_AXIS_SCALE_Y:
403                         r_axis[1] = 1;
404                         break;
405                 case MAN_AXIS_TRANS_Z:
406                 case MAN_AXIS_ROT_Z:
407                 case MAN_AXIS_SCALE_Z:
408                         r_axis[2] = 1;
409                         break;
410                 case MAN_AXIS_TRANS_XY:
411                 case MAN_AXIS_SCALE_XY:
412                         r_axis[0] = r_axis[1] = 1;
413                         break;
414                 case MAN_AXIS_TRANS_YZ:
415                 case MAN_AXIS_SCALE_YZ:
416                         r_axis[1] = r_axis[2] = 1;
417                         break;
418                 case MAN_AXIS_TRANS_ZX:
419                 case MAN_AXIS_SCALE_ZX:
420                         r_axis[2] = r_axis[0] = 1;
421                         break;
422                 default:
423                         break;
424         }
425 }
426
427
428 /* **************** Preparation Stuff **************** */
429
430 /* transform widget center calc helper for below */
431 static void calc_tw_center(struct TransformBounds *tbounds, const float co[3])
432 {
433         minmax_v3v3_v3(tbounds->min, tbounds->max, co);
434         add_v3_v3(tbounds->center, co);
435
436 #ifdef USE_AXIS_BOUNDS
437         for (int i = 0; i < 3; i++) {
438                 const float d = dot_v3v3(tbounds->axis[i], co);
439                 tbounds->axis_min[i] = min_ff(d, tbounds->axis_min[i]);
440                 tbounds->axis_max[i] = max_ff(d, tbounds->axis_max[i]);
441         }
442 #endif
443 }
444
445 static void protectflag_to_drawflags(short protectflag, short *drawflags)
446 {
447         if (protectflag & OB_LOCK_LOCX)
448                 *drawflags &= ~MAN_TRANS_X;
449         if (protectflag & OB_LOCK_LOCY)
450                 *drawflags &= ~MAN_TRANS_Y;
451         if (protectflag & OB_LOCK_LOCZ)
452                 *drawflags &= ~MAN_TRANS_Z;
453
454         if (protectflag & OB_LOCK_ROTX)
455                 *drawflags &= ~MAN_ROT_X;
456         if (protectflag & OB_LOCK_ROTY)
457                 *drawflags &= ~MAN_ROT_Y;
458         if (protectflag & OB_LOCK_ROTZ)
459                 *drawflags &= ~MAN_ROT_Z;
460
461         if (protectflag & OB_LOCK_SCALEX)
462                 *drawflags &= ~MAN_SCALE_X;
463         if (protectflag & OB_LOCK_SCALEY)
464                 *drawflags &= ~MAN_SCALE_Y;
465         if (protectflag & OB_LOCK_SCALEZ)
466                 *drawflags &= ~MAN_SCALE_Z;
467 }
468
469 /* for pose mode */
470 static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan)
471 {
472         protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
473 }
474
475 /* for editmode*/
476 static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *ebo)
477 {
478         if (ebo->flag & BONE_EDITMODE_LOCKED) {
479                 protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag);
480         }
481 }
482
483 /* could move into BLI_math however this is only useful for display/editing purposes */
484 static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], const float angle)
485 {
486         /* X/Y are arbitrary axies, most importantly Z is the axis of rotation */
487
488         float cross_vec[3];
489         float quat[4];
490
491         /* this is an un-scientific method to get a vector to cross with
492          * XYZ intentionally YZX */
493         cross_vec[0] = axis[1];
494         cross_vec[1] = axis[2];
495         cross_vec[2] = axis[0];
496
497         /* X-axis */
498         cross_v3_v3v3(gmat[0], cross_vec, axis);
499         normalize_v3(gmat[0]);
500         axis_angle_to_quat(quat, axis, angle);
501         mul_qt_v3(quat, gmat[0]);
502
503         /* Y-axis */
504         axis_angle_to_quat(quat, axis, M_PI_2);
505         copy_v3_v3(gmat[1], gmat[0]);
506         mul_qt_v3(quat, gmat[1]);
507
508         /* Z-axis */
509         copy_v3_v3(gmat[2], axis);
510
511         normalize_m3(gmat);
512 }
513
514
515 static bool test_rotmode_euler(short rotmode)
516 {
517         return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1;
518 }
519
520 bool gimbal_axis(Object *ob, float gmat[3][3])
521 {
522         if (ob->mode & OB_MODE_POSE) {
523                 bPoseChannel *pchan = BKE_pose_channel_active(ob);
524
525                 if (pchan) {
526                         float mat[3][3], tmat[3][3], obmat[3][3];
527                         if (test_rotmode_euler(pchan->rotmode)) {
528                                 eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
529                         }
530                         else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
531                                 axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
532                         }
533                         else { /* quat */
534                                 return 0;
535                         }
536
537
538                         /* apply bone transformation */
539                         mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
540
541                         if (pchan->parent) {
542                                 float parent_mat[3][3];
543
544                                 copy_m3_m4(parent_mat, pchan->parent->pose_mat);
545                                 mul_m3_m3m3(mat, parent_mat, tmat);
546
547                                 /* needed if object transformation isn't identity */
548                                 copy_m3_m4(obmat, ob->obmat);
549                                 mul_m3_m3m3(gmat, obmat, mat);
550                         }
551                         else {
552                                 /* needed if object transformation isn't identity */
553                                 copy_m3_m4(obmat, ob->obmat);
554                                 mul_m3_m3m3(gmat, obmat, tmat);
555                         }
556
557                         normalize_m3(gmat);
558                         return 1;
559                 }
560         }
561         else {
562                 if (test_rotmode_euler(ob->rotmode)) {
563                         eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
564                 }
565                 else if (ob->rotmode == ROT_MODE_AXISANGLE) {
566                         axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
567                 }
568                 else { /* quat */
569                         return 0;
570                 }
571
572                 if (ob->parent) {
573                         float parent_mat[3][3];
574                         copy_m3_m4(parent_mat, ob->parent->obmat);
575                         normalize_m3(parent_mat);
576                         mul_m3_m3m3(gmat, parent_mat, gmat);
577                 }
578                 return 1;
579         }
580
581         return 0;
582 }
583
584
585 /* centroid, boundbox, of selection */
586 /* returns total items selected */
587 static int calc_manipulator_stats(
588         const bContext *C, bool use_only_center,
589         struct TransformBounds *tbounds)
590 {
591         ScrArea *sa = CTX_wm_area(C);
592         ARegion *ar = CTX_wm_region(C);
593         Scene *scene = CTX_data_scene(C);
594         SceneLayer *sl = CTX_data_scene_layer(C);
595         Object *obedit = CTX_data_edit_object(C);
596         View3D *v3d = sa->spacedata.first;
597         RegionView3D *rv3d = ar->regiondata;
598         Base *base;
599         Object *ob = OBACT_NEW(sl);
600         bGPdata *gpd = CTX_data_gpencil_data(C);
601         const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
602         int a, totsel = 0;
603
604         /* transform widget matrix */
605         unit_m4(rv3d->twmat);
606
607 #ifdef USE_AXIS_BOUNDS
608         unit_m3(rv3d->tw_axis_matrix);
609         zero_v3(rv3d->tw_axis_min);
610         zero_v3(rv3d->tw_axis_max);
611 #endif
612
613         rv3d->twdrawflag = 0xFFFF;
614
615         /* global, local or normal orientation?
616          * if we could check 'totsel' now, this should be skipped with no selection. */
617         if (ob && !is_gp_edit) {
618
619                 switch (v3d->twmode) {
620
621                         case V3D_MANIP_GLOBAL:
622                         {
623                                 break; /* nothing to do */
624                         }
625                         case V3D_MANIP_GIMBAL:
626                         {
627                                 float mat[3][3];
628                                 if (gimbal_axis(ob, mat)) {
629                                         copy_m4_m3(rv3d->twmat, mat);
630                                         break;
631                                 }
632                                 /* if not gimbal, fall through to normal */
633                                 ATTR_FALLTHROUGH;
634                         }
635                         case V3D_MANIP_NORMAL:
636                         {
637                                 if (obedit || ob->mode & OB_MODE_POSE) {
638                                         float mat[3][3];
639                                         ED_getTransformOrientationMatrix(C, mat, v3d->around);
640                                         copy_m4_m3(rv3d->twmat, mat);
641                                         break;
642                                 }
643                                 /* no break we define 'normal' as 'local' in Object mode */
644                                 ATTR_FALLTHROUGH;
645                         }
646                         case V3D_MANIP_LOCAL:
647                         {
648                                 if (ob->mode & OB_MODE_POSE) {
649                                         /* each bone moves on its own local axis, but  to avoid confusion,
650                                          * use the active pones axis for display [#33575], this works as expected on a single bone
651                                          * and users who select many bones will understand whats going on and what local means
652                                          * when they start transforming */
653                                         float mat[3][3];
654                                         ED_getTransformOrientationMatrix(C, mat, v3d->around);
655                                         copy_m4_m3(rv3d->twmat, mat);
656                                         break;
657                                 }
658                                 copy_m4_m4(rv3d->twmat, ob->obmat);
659                                 normalize_m4(rv3d->twmat);
660                                 break;
661                         }
662                         case V3D_MANIP_VIEW:
663                         {
664                                 float mat[3][3];
665                                 copy_m3_m4(mat, rv3d->viewinv);
666                                 normalize_m3(mat);
667                                 copy_m4_m3(rv3d->twmat, mat);
668                                 break;
669                         }
670                         case V3D_MANIP_CUSTOM:
671                         {
672                                 TransformOrientation *custom_orientation = BKE_workspace_transform_orientation_find(
673                                         CTX_wm_workspace(C), v3d->custom_orientation_index);
674                                 float mat[3][3];
675
676                                 if (applyTransformOrientation(custom_orientation, mat, NULL)) {
677                                         copy_m4_m3(rv3d->twmat, mat);
678                                 }
679                                 break;
680                         }
681                 }
682         }
683
684         /* transform widget centroid/center */
685         INIT_MINMAX(tbounds->min, tbounds->max);
686         zero_v3(tbounds->center);
687
688 #ifdef USE_AXIS_BOUNDS
689         copy_m3_m4(tbounds->axis, rv3d->twmat);
690         if (ob && ob->mode & OB_MODE_EDIT) {
691                 float diff_mat[3][3];
692                 copy_m3_m4(diff_mat, ob->obmat);
693                 normalize_m3(diff_mat);
694                 invert_m3(diff_mat);
695                 mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat);
696                 normalize_m3(tbounds->axis);
697         }
698
699         for (int i = 0; i < 3; i++) {
700                 tbounds->axis_min[i] = +FLT_MAX;
701                 tbounds->axis_max[i] = -FLT_MAX;
702         }
703 #endif
704
705         if (is_gp_edit) {
706                 float diff_mat[4][4];
707                 float fpt[3];
708
709                 for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
710                         /* only editable and visible layers are considered */
711                         if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
712
713                                 /* calculate difference matrix if parent object */
714                                 if (gpl->parent != NULL) {
715                                         ED_gpencil_parent_location(gpl, diff_mat);
716                                 }
717
718                                 for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) {
719                                         /* skip strokes that are invalid for current view */
720                                         if (ED_gpencil_stroke_can_use(C, gps) == false) {
721                                                 continue;
722                                         }
723
724                                         /* we're only interested in selected points here... */
725                                         if (gps->flag & GP_STROKE_SELECT) {
726                                                 bGPDspoint *pt;
727                                                 int i;
728
729                                                 /* Change selection status of all points, then make the stroke match */
730                                                 for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
731                                                         if (pt->flag & GP_SPOINT_SELECT) {
732                                                                 if (gpl->parent == NULL) {
733                                                                         calc_tw_center(tbounds, &pt->x);
734                                                                         totsel++;
735                                                                 }
736                                                                 else {
737                                                                         mul_v3_m4v3(fpt, diff_mat, &pt->x);
738                                                                         calc_tw_center(tbounds, fpt);
739                                                                         totsel++;
740                                                                 }
741                                                         }
742                                                 }
743                                         }
744                                 }
745                         }
746                 }
747
748
749                 /* selection center */
750                 if (totsel) {
751                         mul_v3_fl(tbounds->center, 1.0f / (float)totsel);   /* centroid! */
752                 }
753         }
754         else if (obedit) {
755                 ob = obedit;
756                 if (obedit->type == OB_MESH) {
757                         BMEditMesh *em = BKE_editmesh_from_object(obedit);
758                         BMEditSelection ese;
759                         float vec[3] = {0, 0, 0};
760
761                         /* USE LAST SELECTE WITH ACTIVE */
762                         if ((v3d->around == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) {
763                                 BM_editselection_center(&ese, vec);
764                                 calc_tw_center(tbounds, vec);
765                                 totsel = 1;
766                         }
767                         else {
768                                 BMesh *bm = em->bm;
769                                 BMVert *eve;
770
771                                 BMIter iter;
772
773                                 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
774                                         if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
775                                                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
776                                                         totsel++;
777                                                         calc_tw_center(tbounds, eve->co);
778                                                 }
779                                         }
780                                 }
781                         }
782                 } /* end editmesh */
783                 else if (obedit->type == OB_ARMATURE) {
784                         bArmature *arm = obedit->data;
785                         EditBone *ebo;
786
787                         if ((v3d->around == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) {
788                                 /* doesn't check selection or visibility intentionally */
789                                 if (ebo->flag & BONE_TIPSEL) {
790                                         calc_tw_center(tbounds, ebo->tail);
791                                         totsel++;
792                                 }
793                                 if ((ebo->flag & BONE_ROOTSEL) ||
794                                     ((ebo->flag & BONE_TIPSEL) == false))  /* ensure we get at least one point */
795                                 {
796                                         calc_tw_center(tbounds, ebo->head);
797                                         totsel++;
798                                 }
799                                 protectflag_to_drawflags_ebone(rv3d, ebo);
800                         }
801                         else {
802                                 for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
803                                         if (EBONE_VISIBLE(arm, ebo)) {
804                                                 if (ebo->flag & BONE_TIPSEL) {
805                                                         calc_tw_center(tbounds, ebo->tail);
806                                                         totsel++;
807                                                 }
808                                                 if ((ebo->flag & BONE_ROOTSEL) &&
809                                                     /* don't include same point multiple times */
810                                                     ((ebo->flag & BONE_CONNECTED) &&
811                                                      (ebo->parent != NULL) &&
812                                                      (ebo->parent->flag & BONE_TIPSEL) &&
813                                                      EBONE_VISIBLE(arm, ebo->parent)) == 0)
814                                                 {
815                                                         calc_tw_center(tbounds, ebo->head);
816                                                         totsel++;
817                                                 }
818                                                 if (ebo->flag & BONE_SELECTED) {
819                                                         protectflag_to_drawflags_ebone(rv3d, ebo);
820                                                 }
821                                         }
822                                 }
823                         }
824                 }
825                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
826                         Curve *cu = obedit->data;
827                         float center[3];
828
829                         if (v3d->around == V3D_AROUND_ACTIVE && ED_curve_active_center(cu, center)) {
830                                 calc_tw_center(tbounds, center);
831                                 totsel++;
832                         }
833                         else {
834                                 Nurb *nu;
835                                 BezTriple *bezt;
836                                 BPoint *bp;
837                                 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
838
839                                 nu = nurbs->first;
840                                 while (nu) {
841                                         if (nu->type == CU_BEZIER) {
842                                                 bezt = nu->bezt;
843                                                 a = nu->pntsu;
844                                                 while (a--) {
845                                                         /* exceptions
846                                                          * if handles are hidden then only check the center points.
847                                                          * If the center knot is selected then only use this as the center point.
848                                                          */
849                                                         if (cu->drawflag & CU_HIDE_HANDLES) {
850                                                                 if (bezt->f2 & SELECT) {
851                                                                         calc_tw_center(tbounds, bezt->vec[1]);
852                                                                         totsel++;
853                                                                 }
854                                                         }
855                                                         else if (bezt->f2 & SELECT) {
856                                                                 calc_tw_center(tbounds, bezt->vec[1]);
857                                                                 totsel++;
858                                                         }
859                                                         else {
860                                                                 if (bezt->f1 & SELECT) {
861                                                                         calc_tw_center(tbounds, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]);
862                                                                         totsel++;
863                                                                 }
864                                                                 if (bezt->f3 & SELECT) {
865                                                                         calc_tw_center(tbounds, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]);
866                                                                         totsel++;
867                                                                 }
868                                                         }
869                                                         bezt++;
870                                                 }
871                                         }
872                                         else {
873                                                 bp = nu->bp;
874                                                 a = nu->pntsu * nu->pntsv;
875                                                 while (a--) {
876                                                         if (bp->f1 & SELECT) {
877                                                                 calc_tw_center(tbounds, bp->vec);
878                                                                 totsel++;
879                                                         }
880                                                         bp++;
881                                                 }
882                                         }
883                                         nu = nu->next;
884                                 }
885                         }
886                 }
887                 else if (obedit->type == OB_MBALL) {
888                         MetaBall *mb = (MetaBall *)obedit->data;
889                         MetaElem *ml;
890
891                         if ((v3d->around == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) {
892                                 calc_tw_center(tbounds, &ml->x);
893                                 totsel++;
894                         }
895                         else {
896                                 for (ml = mb->editelems->first; ml; ml = ml->next) {
897                                         if (ml->flag & SELECT) {
898                                                 calc_tw_center(tbounds, &ml->x);
899                                                 totsel++;
900                                         }
901                                 }
902                         }
903                 }
904                 else if (obedit->type == OB_LATTICE) {
905                         Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
906                         BPoint *bp;
907
908                         if ((v3d->around == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) {
909                                 calc_tw_center(tbounds, bp->vec);
910                                 totsel++;
911                         }
912                         else {
913                                 bp = lt->def;
914                                 a = lt->pntsu * lt->pntsv * lt->pntsw;
915                                 while (a--) {
916                                         if (bp->f1 & SELECT) {
917                                                 calc_tw_center(tbounds, bp->vec);
918                                                 totsel++;
919                                         }
920                                         bp++;
921                                 }
922                         }
923                 }
924
925                 /* selection center */
926                 if (totsel) {
927                         mul_v3_fl(tbounds->center, 1.0f / (float)totsel);   // centroid!
928                         mul_m4_v3(obedit->obmat, tbounds->center);
929                         mul_m4_v3(obedit->obmat, tbounds->min);
930                         mul_m4_v3(obedit->obmat, tbounds->max);
931                 }
932         }
933         else if (ob && (ob->mode & OB_MODE_POSE)) {
934                 bPoseChannel *pchan;
935                 int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed
936                 bool ok = false;
937
938                 if ((v3d->around == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) {
939                         /* doesn't check selection or visibility intentionally */
940                         Bone *bone = pchan->bone;
941                         if (bone) {
942                                 calc_tw_center(tbounds, pchan->pose_head);
943                                 protectflag_to_drawflags_pchan(rv3d, pchan);
944                                 totsel = 1;
945                                 ok = true;
946                         }
947                 }
948                 else {
949                         totsel = count_set_pose_transflags(&mode, 0, ob);
950
951                         if (totsel) {
952                                 /* use channels to get stats */
953                                 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
954                                         Bone *bone = pchan->bone;
955                                         if (bone && (bone->flag & BONE_TRANSFORM)) {
956                                                 calc_tw_center(tbounds, pchan->pose_head);
957                                                 protectflag_to_drawflags_pchan(rv3d, pchan);
958                                         }
959                                 }
960                                 ok = true;
961                         }
962                 }
963
964                 if (ok) {
965                         mul_v3_fl(tbounds->center, 1.0f / (float)totsel);   // centroid!
966                         mul_m4_v3(ob->obmat, tbounds->center);
967                         mul_m4_v3(ob->obmat, tbounds->min);
968                         mul_m4_v3(ob->obmat, tbounds->max);
969                 }
970         }
971         else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
972                 /* pass */
973         }
974         else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
975                 PTCacheEdit *edit = PE_get_current(scene, sl, ob);
976                 PTCacheEditPoint *point;
977                 PTCacheEditKey *ek;
978                 int k;
979
980                 if (edit) {
981                         point = edit->points;
982                         for (a = 0; a < edit->totpoint; a++, point++) {
983                                 if (point->flag & PEP_HIDE) continue;
984
985                                 for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) {
986                                         if (ek->flag & PEK_SELECT) {
987                                                 calc_tw_center(tbounds, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
988                                                 totsel++;
989                                         }
990                                 }
991                         }
992
993                         /* selection center */
994                         if (totsel)
995                                 mul_v3_fl(tbounds->center, 1.0f / (float)totsel);  // centroid!
996                 }
997         }
998         else {
999
1000                 /* we need the one selected object, if its not active */
1001                 base = BASACT_NEW(sl);
1002                 ob = OBACT_NEW(sl);
1003                 if (base && ((base->flag & BASE_SELECTED) == 0)) ob = NULL;
1004
1005                 for (base = sl->object_bases.first; base; base = base->next) {
1006                         if (TESTBASELIB_NEW(base)) {
1007                                 if (ob == NULL)
1008                                         ob = base->object;
1009                                 if (use_only_center || base->object->bb == NULL) {
1010                                         calc_tw_center(tbounds, base->object->obmat[3]);
1011                                 }
1012                                 else {
1013                                         for (uint j = 0; j < 8; j++) {
1014                                                 float co[3];
1015                                                 mul_v3_m4v3(co, base->object->obmat, base->object->bb->vec[j]);
1016                                                 calc_tw_center(tbounds, co);
1017                                         }
1018                                 }
1019                                 protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
1020                                 totsel++;
1021                         }
1022                 }
1023
1024                 /* selection center */
1025                 if (totsel) {
1026                         mul_v3_fl(tbounds->center, 1.0f / (float)totsel);   // centroid!
1027                 }
1028         }
1029
1030         if (totsel == 0) {
1031                 unit_m4(rv3d->twmat);
1032         }
1033         else {
1034 #ifdef USE_AXIS_BOUNDS
1035                 copy_v3_v3(rv3d->tw_axis_min, tbounds->axis_min);
1036                 copy_v3_v3(rv3d->tw_axis_max, tbounds->axis_max);
1037                 copy_m3_m3(rv3d->tw_axis_matrix, tbounds->axis);
1038 #endif
1039         }
1040
1041         return totsel;
1042 }
1043
1044 static void manipulator_get_idot(RegionView3D *rv3d, float r_idot[3])
1045 {
1046         float view_vec[3], axis_vec[3];
1047         ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec);
1048         for (int i = 0; i < 3; i++) {
1049                 normalize_v3_v3(axis_vec, rv3d->twmat[i]);
1050                 r_idot[i] = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec));
1051         }
1052 }
1053
1054 static void manipulator_prepare_mat(
1055         const bContext *C, View3D *v3d, RegionView3D *rv3d, const struct TransformBounds *tbounds)
1056 {
1057         Scene *scene = CTX_data_scene(C);
1058         SceneLayer *sl = CTX_data_scene_layer(C);
1059
1060         switch (v3d->around) {
1061                 case V3D_AROUND_CENTER_BOUNDS:
1062                 case V3D_AROUND_ACTIVE:
1063                 {
1064                         bGPdata *gpd = CTX_data_gpencil_data(C);
1065                         Object *ob = OBACT_NEW(sl);
1066
1067                         if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) &&
1068                             ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
1069                             (!(ob->mode & OB_MODE_POSE)))
1070                         {
1071                                 copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
1072                         }
1073                         else {
1074                                 mid_v3_v3v3(rv3d->twmat[3], tbounds->min, tbounds->max);
1075                         }
1076                         break;
1077                 }
1078                 case V3D_AROUND_LOCAL_ORIGINS:
1079                 case V3D_AROUND_CENTER_MEAN:
1080                         copy_v3_v3(rv3d->twmat[3], tbounds->center);
1081                         break;
1082                 case V3D_AROUND_CURSOR:
1083                         copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d));
1084                         break;
1085         }
1086 }
1087
1088 /**
1089  * Sets up \a r_start and \a r_len to define arrow line range.
1090  * Needed to adjust line drawing for combined manipulator axis types.
1091  */
1092 static void manipulator_line_range(const View3D *v3d, const short axis_type, float *r_start, float *r_len)
1093 {
1094         const float ofs = 0.2f;
1095
1096         *r_start = 0.2f;
1097         *r_len = 1.0f;
1098
1099         switch (axis_type) {
1100                 case MAN_AXES_TRANSLATE:
1101                         if (v3d->twtype & V3D_MANIP_SCALE) {
1102                                 *r_start = *r_len - ofs + 0.075f;
1103                         }
1104                         if (v3d->twtype & V3D_MANIP_ROTATE) {
1105                                 *r_len += ofs;
1106                         }
1107                         break;
1108                 case MAN_AXES_SCALE:
1109                         if (v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) {
1110                                 *r_len -= ofs + 0.025f;
1111                         }
1112                         break;
1113         }
1114
1115         *r_len -= *r_start;
1116 }
1117
1118 /** \} */
1119
1120
1121 /* -------------------------------------------------------------------- */
1122 /** \name Transform Manipulator
1123  * \{ */
1124
1125 static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup)
1126 {
1127         ManipulatorGroup *man;
1128
1129         man = MEM_callocN(sizeof(ManipulatorGroup), "manipulator_data");
1130
1131         const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true);
1132         const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true);
1133         const wmManipulatorType *wt_prim = WM_manipulatortype_find("MANIPULATOR_WT_primitive_3d", true);
1134
1135 #define MANIPULATOR_NEW_ARROW(v, draw_style) { \
1136         man->manipulators[v] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); \
1137         RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \
1138 } ((void)0)
1139 #define MANIPULATOR_NEW_DIAL(v, draw_options) { \
1140         man->manipulators[v] = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); \
1141         RNA_enum_set(man->manipulators[v]->ptr, "draw_options", draw_options); \
1142 } ((void)0)
1143 #define MANIPULATOR_NEW_PRIM(v, draw_style) { \
1144         man->manipulators[v] = WM_manipulator_new_ptr(wt_prim, mgroup, NULL); \
1145         RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \
1146 } ((void)0)
1147
1148         /* add/init widgets - order matters! */
1149         MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_T, ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL);
1150
1151         MANIPULATOR_NEW_DIAL(MAN_AXIS_SCALE_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
1152
1153         MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_X, ED_MANIPULATOR_ARROW_STYLE_BOX);
1154         MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Y, ED_MANIPULATOR_ARROW_STYLE_BOX);
1155         MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Z, ED_MANIPULATOR_ARROW_STYLE_BOX);
1156
1157         MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
1158         MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
1159         MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
1160
1161         MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_X, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
1162         MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Y, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
1163         MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Z, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
1164
1165         /* init screen aligned widget last here, looks better, behaves better */
1166         MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
1167
1168         MANIPULATOR_NEW_DIAL(MAN_AXIS_TRANS_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
1169
1170         MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_X, ED_MANIPULATOR_ARROW_STYLE_NORMAL);
1171         MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Y, ED_MANIPULATOR_ARROW_STYLE_NORMAL);
1172         MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Z, ED_MANIPULATOR_ARROW_STYLE_NORMAL);
1173
1174         MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
1175         MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
1176         MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
1177
1178         return man;
1179 }
1180
1181 /**
1182  * Custom handler for manipulator widgets
1183  */
1184 static int manipulator_modal(
1185         bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event),
1186         eWM_ManipulatorTweak UNUSED(tweak_flag))
1187 {
1188         const ScrArea *sa = CTX_wm_area(C);
1189         ARegion *ar = CTX_wm_region(C);
1190         View3D *v3d = sa->spacedata.first;
1191         RegionView3D *rv3d = ar->regiondata;
1192         struct TransformBounds tbounds;
1193
1194
1195         if (calc_manipulator_stats(C, true, &tbounds)) {
1196                 manipulator_prepare_mat(C, v3d, rv3d, &tbounds);
1197                 WM_manipulator_set_matrix_location(widget, rv3d->twmat[3]);
1198         }
1199
1200         ED_region_tag_redraw(ar);
1201
1202         return OPERATOR_RUNNING_MODAL;
1203 }
1204
1205 static void WIDGETGROUP_manipulator_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
1206 {
1207         ManipulatorGroup *man = manipulatorgroup_init(mgroup);
1208         struct {
1209                 wmOperatorType *translate, *rotate, *trackball, *resize;
1210         } ot_store = {NULL};
1211
1212         mgroup->customdata = man;
1213
1214         /* *** set properties for axes *** */
1215
1216         MAN_ITER_AXES_BEGIN(axis, axis_idx)
1217         {
1218                 const short axis_type = manipulator_get_axis_type(axis_idx);
1219                 int constraint_axis[3] = {1, 0, 0};
1220                 PointerRNA *ptr;
1221
1222                 manipulator_get_axis_constraint(axis_idx, constraint_axis);
1223
1224                 /* custom handler! */
1225                 WM_manipulator_set_fn_custom_modal(axis, manipulator_modal);
1226
1227                 switch (axis_idx) {
1228                         case MAN_AXIS_TRANS_X:
1229                         case MAN_AXIS_TRANS_Y:
1230                         case MAN_AXIS_TRANS_Z:
1231                         case MAN_AXIS_SCALE_X:
1232                         case MAN_AXIS_SCALE_Y:
1233                         case MAN_AXIS_SCALE_Z:
1234                                 WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH);
1235                                 break;
1236                         case MAN_AXIS_ROT_X:
1237                         case MAN_AXIS_ROT_Y:
1238                         case MAN_AXIS_ROT_Z:
1239                                 /* increased line width for better display */
1240                                 WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH + 1.0f);
1241                                 WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true);
1242                                 break;
1243                         case MAN_AXIS_TRANS_XY:
1244                         case MAN_AXIS_TRANS_YZ:
1245                         case MAN_AXIS_TRANS_ZX:
1246                         case MAN_AXIS_SCALE_XY:
1247                         case MAN_AXIS_SCALE_YZ:
1248                         case MAN_AXIS_SCALE_ZX:
1249                         {
1250                                 const float ofs_ax = 11.0f;
1251                                 const float ofs[3] = {ofs_ax, ofs_ax, 0.0f};
1252                                 WM_manipulator_set_scale(axis, 0.07f);
1253                                 WM_manipulator_set_matrix_offset_location(axis, ofs);
1254                                 WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true);
1255                                 break;
1256                         }
1257                         case MAN_AXIS_TRANS_C:
1258                         case MAN_AXIS_ROT_C:
1259                         case MAN_AXIS_SCALE_C:
1260                         case MAN_AXIS_ROT_T:
1261                                 WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH);
1262                                 if (axis_idx == MAN_AXIS_ROT_T) {
1263                                         WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_HOVER, true);
1264                                 }
1265                                 else if (axis_idx == MAN_AXIS_ROT_C) {
1266                                         WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true);
1267                                 }
1268                                 else {
1269                                         WM_manipulator_set_scale(axis, 0.2f);
1270                                 }
1271                                 break;
1272                 }
1273
1274                 switch (axis_type) {
1275                         case MAN_AXES_TRANSLATE:
1276                                 if (ot_store.translate == NULL) {
1277                                         ot_store.translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
1278                                 }
1279                                 ptr = WM_manipulator_operator_set(axis, 0, ot_store.translate, NULL);
1280                                 break;
1281                         case MAN_AXES_ROTATE:
1282                         {
1283                                 wmOperatorType *ot_rotate;
1284                                 if (axis_idx == MAN_AXIS_ROT_T) {
1285                                         if (ot_store.trackball == NULL) {
1286                                                 ot_store.trackball = WM_operatortype_find("TRANSFORM_OT_trackball", true);
1287                                         }
1288                                         ot_rotate = ot_store.trackball;
1289                                 }
1290                                 else {
1291                                         if (ot_store.rotate == NULL) {
1292                                                 ot_store.rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true);
1293                                         }
1294                                         ot_rotate = ot_store.rotate;
1295                                 }
1296                                 ptr = WM_manipulator_operator_set(axis, 0, ot_rotate, NULL);
1297                                 break;
1298                         }
1299                         case MAN_AXES_SCALE:
1300                         {
1301                                 if (ot_store.resize == NULL) {
1302                                         ot_store.resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
1303                                 }
1304                                 ptr = WM_manipulator_operator_set(axis, 0, ot_store.resize, NULL);
1305                                 break;
1306                         }
1307                 }
1308
1309                 {
1310                         PropertyRNA *prop;
1311                         if ((prop = RNA_struct_find_property(ptr, "constraint_axis"))) {
1312                                 RNA_property_boolean_set_array(ptr, prop, constraint_axis);
1313                         }
1314                 }
1315
1316                 RNA_boolean_set(ptr, "release_confirm", 1);
1317         }
1318         MAN_ITER_AXES_END;
1319 }
1320
1321 static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGroup *mgroup)
1322 {
1323         ManipulatorGroup *man = mgroup->customdata;
1324         ScrArea *sa = CTX_wm_area(C);
1325         ARegion *ar = CTX_wm_region(C);
1326         View3D *v3d = sa->spacedata.first;
1327         RegionView3D *rv3d = ar->regiondata;
1328         struct TransformBounds tbounds;
1329
1330         /* skip, we don't draw anything anyway */
1331         if ((man->all_hidden = (calc_manipulator_stats(C, true, &tbounds) == 0)))
1332                 return;
1333
1334         manipulator_prepare_mat(C, v3d, rv3d, &tbounds);
1335
1336         /* *** set properties for axes *** */
1337
1338         MAN_ITER_AXES_BEGIN(axis, axis_idx)
1339         {
1340                 const short axis_type = manipulator_get_axis_type(axis_idx);
1341                 const int aidx_norm = manipulator_orientation_axis(axis_idx, NULL);
1342
1343                 WM_manipulator_set_matrix_location(axis, rv3d->twmat[3]);
1344
1345                 switch (axis_idx) {
1346                         case MAN_AXIS_TRANS_X:
1347                         case MAN_AXIS_TRANS_Y:
1348                         case MAN_AXIS_TRANS_Z:
1349                         case MAN_AXIS_SCALE_X:
1350                         case MAN_AXIS_SCALE_Y:
1351                         case MAN_AXIS_SCALE_Z:
1352                         {
1353                                 float start_co[3] = {0.0f, 0.0f, 0.0f};
1354                                 float len;
1355
1356                                 manipulator_line_range(v3d, axis_type, &start_co[2], &len);
1357
1358                                 WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
1359                                 RNA_float_set(axis->ptr, "length", len);
1360                                 WM_manipulator_set_matrix_offset_location(axis, start_co);
1361                                 WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true);
1362                                 break;
1363                         }
1364                         case MAN_AXIS_ROT_X:
1365                         case MAN_AXIS_ROT_Y:
1366                         case MAN_AXIS_ROT_Z:
1367                                 WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
1368                                 break;
1369                         case MAN_AXIS_TRANS_XY:
1370                         case MAN_AXIS_TRANS_YZ:
1371                         case MAN_AXIS_TRANS_ZX:
1372                         case MAN_AXIS_SCALE_XY:
1373                         case MAN_AXIS_SCALE_YZ:
1374                         case MAN_AXIS_SCALE_ZX:
1375                         {
1376                                 const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1];
1377                                 const float *z_axis = rv3d->twmat[aidx_norm];
1378                                 WM_manipulator_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
1379                                 break;
1380                         }
1381                 }
1382         }
1383         MAN_ITER_AXES_END;
1384 }
1385
1386 static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
1387 {
1388         ManipulatorGroup *man = mgroup->customdata;
1389         ScrArea *sa = CTX_wm_area(C);
1390         ARegion *ar = CTX_wm_region(C);
1391         View3D *v3d = sa->spacedata.first;
1392         RegionView3D *rv3d = ar->regiondata;
1393         float idot[3];
1394
1395         /* when looking through a selected camera, the manipulator can be at the
1396          * exact same position as the view, skip so we don't break selection */
1397         if (man->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 1e-6f) {
1398                 MAN_ITER_AXES_BEGIN(axis, axis_idx)
1399                 {
1400                         WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true);
1401                 }
1402                 MAN_ITER_AXES_END;
1403                 return;
1404         }
1405         manipulator_get_idot(rv3d, idot);
1406
1407         /* *** set properties for axes *** */
1408
1409         MAN_ITER_AXES_BEGIN(axis, axis_idx)
1410         {
1411                 const short axis_type = manipulator_get_axis_type(axis_idx);
1412                 /* XXX maybe unset _HIDDEN flag on redraw? */
1413                 if (manipulator_is_axis_visible(v3d, rv3d, idot, axis_type, axis_idx)) {
1414                         WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, false);
1415                 }
1416                 else {
1417                         WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true);
1418                         continue;
1419                 }
1420
1421                 float color[4], color_hi[4];
1422                 manipulator_get_axis_color(axis_idx, idot, color, color_hi);
1423                 WM_manipulator_set_color(axis, color);
1424                 WM_manipulator_set_color_highlight(axis, color_hi);
1425
1426                 switch (axis_idx) {
1427                         case MAN_AXIS_TRANS_C:
1428                         case MAN_AXIS_ROT_C:
1429                         case MAN_AXIS_SCALE_C:
1430                         case MAN_AXIS_ROT_T:
1431                                 WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]);
1432                                 break;
1433                 }
1434         }
1435         MAN_ITER_AXES_END;
1436 }
1437
1438 static bool WIDGETGROUP_manipulator_poll(const struct bContext *C, struct wmManipulatorGroupType *UNUSED(wgt))
1439 {
1440         /* it's a given we only use this in 3D view */
1441         const ScrArea *sa = CTX_wm_area(C);
1442         const View3D *v3d = sa->spacedata.first;
1443
1444         return (((v3d->twflag & V3D_MANIPULATOR_DRAW) != 0) &&
1445                 ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) != 0));
1446 }
1447
1448 void TRANSFORM_WGT_manipulator(wmManipulatorGroupType *wgt)
1449 {
1450         wgt->name = "Transform Manipulator";
1451         wgt->idname = "TRANSFORM_WGT_manipulator";
1452
1453         wgt->flag |= (WM_MANIPULATORGROUPTYPE_PERSISTENT |
1454                       WM_MANIPULATORGROUPTYPE_3D);
1455
1456         wgt->poll = WIDGETGROUP_manipulator_poll;
1457         wgt->setup = WIDGETGROUP_manipulator_setup;
1458         wgt->refresh = WIDGETGROUP_manipulator_refresh;
1459         wgt->draw_prepare = WIDGETGROUP_manipulator_draw_prepare;
1460 }
1461
1462 /** \} */
1463
1464
1465 /* -------------------------------------------------------------------- */
1466 /** \name Scale Cage Manipulator
1467  * \{ */
1468
1469 struct XFormCageWidgetGroup {
1470         wmManipulator *manipulator;
1471 };
1472
1473 static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmManipulatorGroupType *wgt)
1474 {
1475         WorkSpace *workspace = CTX_wm_workspace(C);
1476         if (!STREQ(wgt->idname, workspace->tool.manipulator_group)) {
1477                 WM_manipulator_group_type_unlink_delayed_ptr(wgt);
1478                 return false;
1479         }
1480         return true;
1481 }
1482
1483 static void WIDGETGROUP_xform_cage_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
1484 {
1485         struct XFormCageWidgetGroup *xmgroup = MEM_mallocN(sizeof(struct XFormCageWidgetGroup), __func__);
1486         const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_3d", true);
1487         xmgroup->manipulator = WM_manipulator_new_ptr(wt_cage, mgroup, NULL);
1488         wmManipulator *mpr = xmgroup->manipulator;
1489
1490         RNA_enum_set(mpr->ptr, "transform",
1491                      ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE |
1492                      ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE);
1493
1494         mpr->color[0] = 1;
1495         mpr->color_hi[0]=1;
1496
1497         mgroup->customdata = xmgroup;
1498
1499         {
1500                 wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
1501                 PointerRNA *ptr;
1502
1503                 /* assign operator */
1504                 PropertyRNA *prop_release_confirm = NULL;
1505                 PropertyRNA *prop_constraint_axis = NULL;
1506
1507                 int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
1508                 for (int x = 0; x < 3; x++) {
1509                         for (int y = 0; y < 3; y++) {
1510                                 for (int z = 0; z < 3; z++) {
1511                                         int constraint[3] = {x != 1, y != 1, z != 1};
1512                                         ptr = WM_manipulator_operator_set(mpr, i, ot_resize, NULL);
1513                                         if (prop_release_confirm == NULL) {
1514                                                 prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
1515                                                 prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
1516                                         }
1517                                         RNA_property_boolean_set(ptr, prop_release_confirm, true);
1518                                         RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint);
1519                                         i++;
1520                                 }
1521                         }
1522                 }
1523         }
1524 }
1525
1526 static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmManipulatorGroup *mgroup)
1527 {
1528         ScrArea *sa = CTX_wm_area(C);
1529         View3D *v3d = sa->spacedata.first;
1530         ARegion *ar = CTX_wm_region(C);
1531         RegionView3D *rv3d = ar->regiondata;
1532
1533         struct XFormCageWidgetGroup *xmgroup = mgroup->customdata;
1534         wmManipulator *mpr = xmgroup->manipulator;
1535
1536         struct TransformBounds tbounds;
1537
1538         if ((calc_manipulator_stats(C, false, &tbounds) == 0) ||
1539             equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max))
1540         {
1541                 WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true);
1542         }
1543         else {
1544                 manipulator_prepare_mat(C, v3d, rv3d, &tbounds);
1545
1546                 WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false);
1547
1548                 float dims[3];
1549                 sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min);
1550                 RNA_float_set_array(mpr->ptr, "dimensions", dims);
1551                 mul_v3_fl(dims, 0.5f);
1552
1553                 copy_m4_m3(mpr->matrix_offset, rv3d->tw_axis_matrix);
1554                 mid_v3_v3v3(mpr->matrix_offset[3], rv3d->tw_axis_max, rv3d->tw_axis_min);
1555                 mul_m3_v3(rv3d->tw_axis_matrix, mpr->matrix_offset[3]);
1556
1557                 PropertyRNA *prop_center_override = NULL;
1558                 float center[3];
1559                 float center_global[3];
1560                 int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
1561                 for (int x = 0; x < 3; x++) {
1562                         center[0] = (float)(1 - x) * dims[0];
1563                         for (int y = 0; y < 3; y++) {
1564                                 center[1] = (float)(1 - y) * dims[1];
1565                                 for (int z = 0; z < 3; z++) {
1566                                         center[2] = (float)(1 - z) * dims[2];
1567                                         struct wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, i);
1568                                         if (prop_center_override == NULL) {
1569                                                 prop_center_override = RNA_struct_find_property(&mpop->ptr, "center_override");
1570                                         }
1571                                         mul_v3_m4v3(center_global, mpr->matrix_offset, center);
1572                                         RNA_property_float_set_array(&mpop->ptr, prop_center_override, center_global);
1573                                         i++;
1574                                 }
1575                         }
1576                 }
1577         }
1578 }
1579
1580 static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
1581 {
1582         struct XFormCageWidgetGroup *xmgroup = mgroup->customdata;
1583         wmManipulator *mpr = xmgroup->manipulator;
1584
1585         SceneLayer *sl = CTX_data_scene_layer(C);
1586         Object *ob = OBACT_NEW(sl);
1587         if (ob && ob->mode & OB_MODE_EDIT) {
1588                 copy_m4_m4(mpr->matrix_space, ob->obmat);
1589         }
1590         else {
1591                 unit_m4(mpr->matrix_space);
1592         }
1593 }
1594
1595 void VIEW3D_WGT_xform_cage(wmManipulatorGroupType *wgt)
1596 {
1597         wgt->name = "Transform Cage";
1598         wgt->idname = "VIEW3D_WGT_xform_cage";
1599
1600         wgt->flag |= (WM_MANIPULATORGROUPTYPE_3D |
1601                       WM_MANIPULATORGROUPTYPE_DEPTH_3D);
1602
1603         wgt->mmap_params.spaceid = SPACE_VIEW3D;
1604         wgt->mmap_params.regionid = RGN_TYPE_WINDOW;
1605
1606         wgt->poll = WIDGETGROUP_xform_cage_poll;
1607         wgt->setup = WIDGETGROUP_xform_cage_setup;
1608         wgt->refresh = WIDGETGROUP_xform_cage_refresh;
1609         wgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare;
1610 }
1611
1612 /** \} */