Merge branch 'master' into blender2.8
[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_object_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_view3d_types.h"
47
48 #include "BLI_listbase.h"
49 #include "BLI_math.h"
50 #include "BLI_utildefines.h"
51
52 #include "RNA_access.h"
53
54 #include "BKE_action.h"
55 #include "BKE_context.h"
56 #include "BKE_curve.h"
57 #include "BKE_global.h"
58 #include "BKE_editmesh.h"
59 #include "BKE_lattice.h"
60
61 #include "BIF_gl.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65
66 #include "ED_armature.h"
67 #include "ED_curve.h"
68 #include "ED_view3d.h"
69
70 #include "UI_resources.h"
71
72 /* local module include */
73 #include "transform.h"
74
75 #include "GPU_select.h"
76
77 /* return codes for select, and drawing flags */
78
79 #define MAN_TRANS_X             (1 << 0)
80 #define MAN_TRANS_Y             (1 << 1)
81 #define MAN_TRANS_Z             (1 << 2)
82 #define MAN_TRANS_C             (MAN_TRANS_X | MAN_TRANS_Y | MAN_TRANS_Z)
83
84 #define MAN_ROT_X               (1 << 3)
85 #define MAN_ROT_Y               (1 << 4)
86 #define MAN_ROT_Z               (1 << 5)
87 #define MAN_ROT_V               (1 << 6)
88 #define MAN_ROT_T               (1 << 7)
89 #define MAN_ROT_C               (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z | MAN_ROT_V | MAN_ROT_T)
90
91 #define MAN_SCALE_X             (1 << 8)
92 #define MAN_SCALE_Y             (1 << 9)
93 #define MAN_SCALE_Z             (1 << 10)
94 #define MAN_SCALE_C             (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z)
95
96 /* color codes */
97
98 #define MAN_RGB     0
99 #define MAN_GHOST   1
100 #define MAN_MOVECOL 2
101
102 /* threshold for testing view aligned manipulator axis */
103 #define TW_AXIS_DOT_MIN 0.02f
104 #define TW_AXIS_DOT_MAX 0.1f
105
106 /* transform widget center calc helper for below */
107 static void calc_tw_center(Scene *scene, const float co[3])
108 {
109         float *twcent = scene->twcent;
110         float *min = scene->twmin;
111         float *max = scene->twmax;
112
113         minmax_v3v3_v3(min, max, co);
114         add_v3_v3(twcent, co);
115 }
116
117 static void protectflag_to_drawflags(short protectflag, short *drawflags)
118 {
119         if (protectflag & OB_LOCK_LOCX)
120                 *drawflags &= ~MAN_TRANS_X;
121         if (protectflag & OB_LOCK_LOCY)
122                 *drawflags &= ~MAN_TRANS_Y;
123         if (protectflag & OB_LOCK_LOCZ)
124                 *drawflags &= ~MAN_TRANS_Z;
125
126         if (protectflag & OB_LOCK_ROTX)
127                 *drawflags &= ~MAN_ROT_X;
128         if (protectflag & OB_LOCK_ROTY)
129                 *drawflags &= ~MAN_ROT_Y;
130         if (protectflag & OB_LOCK_ROTZ)
131                 *drawflags &= ~MAN_ROT_Z;
132
133         if (protectflag & OB_LOCK_SCALEX)
134                 *drawflags &= ~MAN_SCALE_X;
135         if (protectflag & OB_LOCK_SCALEY)
136                 *drawflags &= ~MAN_SCALE_Y;
137         if (protectflag & OB_LOCK_SCALEZ)
138                 *drawflags &= ~MAN_SCALE_Z;
139 }
140
141 /* for pose mode */
142 static void stats_pose(Scene *scene, RegionView3D *rv3d, bPoseChannel *pchan)
143 {
144         Bone *bone = pchan->bone;
145
146         if (bone) {
147                 calc_tw_center(scene, pchan->pose_head);
148                 protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
149         }
150 }
151
152 /* for editmode*/
153 static void stats_editbone(RegionView3D *rv3d, EditBone *ebo)
154 {
155         if (ebo->flag & BONE_EDITMODE_LOCKED)
156                 protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag);
157 }
158
159 /* could move into BLI_math however this is only useful for display/editing purposes */
160 static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], const float angle)
161 {
162         /* X/Y are arbitrary axies, most importantly Z is the axis of rotation */
163
164         float cross_vec[3];
165         float quat[4];
166
167         /* this is an un-scientific method to get a vector to cross with
168          * XYZ intentionally YZX */
169         cross_vec[0] = axis[1];
170         cross_vec[1] = axis[2];
171         cross_vec[2] = axis[0];
172
173         /* X-axis */
174         cross_v3_v3v3(gmat[0], cross_vec, axis);
175         normalize_v3(gmat[0]);
176         axis_angle_to_quat(quat, axis, angle);
177         mul_qt_v3(quat, gmat[0]);
178
179         /* Y-axis */
180         axis_angle_to_quat(quat, axis, M_PI_2);
181         copy_v3_v3(gmat[1], gmat[0]);
182         mul_qt_v3(quat, gmat[1]);
183
184         /* Z-axis */
185         copy_v3_v3(gmat[2], axis);
186
187         normalize_m3(gmat);
188 }
189
190
191 static int test_rotmode_euler(short rotmode)
192 {
193         return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1;
194 }
195
196 bool gimbal_axis(Object *ob, float gmat[3][3])
197 {
198         if (ob) {
199                 if (ob->mode & OB_MODE_POSE) {
200                         bPoseChannel *pchan = BKE_pose_channel_active(ob);
201
202                         if (pchan) {
203                                 float mat[3][3], tmat[3][3], obmat[3][3];
204                                 if (test_rotmode_euler(pchan->rotmode)) {
205                                         eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
206                                 }
207                                 else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
208                                         axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
209                                 }
210                                 else { /* quat */
211                                         return 0;
212                                 }
213
214
215                                 /* apply bone transformation */
216                                 mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
217
218                                 if (pchan->parent) {
219                                         float parent_mat[3][3];
220
221                                         copy_m3_m4(parent_mat, pchan->parent->pose_mat);
222                                         mul_m3_m3m3(mat, parent_mat, tmat);
223
224                                         /* needed if object transformation isn't identity */
225                                         copy_m3_m4(obmat, ob->obmat);
226                                         mul_m3_m3m3(gmat, obmat, mat);
227                                 }
228                                 else {
229                                         /* needed if object transformation isn't identity */
230                                         copy_m3_m4(obmat, ob->obmat);
231                                         mul_m3_m3m3(gmat, obmat, tmat);
232                                 }
233
234                                 normalize_m3(gmat);
235                                 return 1;
236                         }
237                 }
238                 else {
239                         if (test_rotmode_euler(ob->rotmode)) {
240                                 eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
241                         }
242                         else if (ob->rotmode == ROT_MODE_AXISANGLE) {
243                                 axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
244                         }
245                         else { /* quat */
246                                 return 0;
247                         }
248
249                         if (ob->parent) {
250                                 float parent_mat[3][3];
251                                 copy_m3_m4(parent_mat, ob->parent->obmat);
252                                 normalize_m3(parent_mat);
253                                 mul_m3_m3m3(gmat, parent_mat, gmat);
254                         }
255                         return 1;
256                 }
257         }
258
259         return 0;
260 }
261
262
263 /* centroid, boundbox, of selection */
264 /* returns total items selected */
265 static int calc_manipulator_stats(const bContext *C)
266 {
267         ScrArea *sa = CTX_wm_area(C);
268         ARegion *ar = CTX_wm_region(C);
269         Scene *scene = CTX_data_scene(C);
270         Object *obedit = CTX_data_edit_object(C);
271         View3D *v3d = sa->spacedata.first;
272         RegionView3D *rv3d = ar->regiondata;
273         Base *base;
274         Object *ob = OBACT;
275         bGPdata *gpd = CTX_data_gpencil_data(C);
276         const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
277         int a, totsel = 0;
278
279         /* transform widget matrix */
280         unit_m4(rv3d->twmat);
281
282         rv3d->twdrawflag = 0xFFFF;
283
284         /* transform widget centroid/center */
285         INIT_MINMAX(scene->twmin, scene->twmax);
286         zero_v3(scene->twcent);
287         
288         if (is_gp_edit) {
289                 CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
290                 {
291                         /* we're only interested in selected points here... */
292                         if (gps->flag & GP_STROKE_SELECT) {
293                                 bGPDspoint *pt;
294                                 int i;
295                                 
296                                 /* Change selection status of all points, then make the stroke match */
297                                 for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
298                                         if (pt->flag & GP_SPOINT_SELECT) {
299                                                 calc_tw_center(scene, &pt->x);
300                                                 totsel++;
301                                         }
302                                 }
303                         }
304                 }
305                 CTX_DATA_END;
306                 
307                 /* selection center */
308                 if (totsel) {
309                         mul_v3_fl(scene->twcent, 1.0f / (float)totsel);   /* centroid! */
310                 }
311         }
312         else if (obedit) {
313                 ob = obedit;
314                 if ((ob->lay & v3d->lay) == 0) return 0;
315
316                 if (obedit->type == OB_MESH) {
317                         BMEditMesh *em = BKE_editmesh_from_object(obedit);
318                         BMEditSelection ese;
319                         float vec[3] = {0, 0, 0};
320
321                         /* USE LAST SELECTE WITH ACTIVE */
322                         if ((v3d->around == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) {
323                                 BM_editselection_center(&ese, vec);
324                                 calc_tw_center(scene, vec);
325                                 totsel = 1;
326                         }
327                         else {
328                                 BMesh *bm = em->bm;
329                                 BMVert *eve;
330
331                                 BMIter iter;
332
333                                 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
334                                         if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
335                                                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
336                                                         totsel++;
337                                                         calc_tw_center(scene, eve->co);
338                                                 }
339                                         }
340                                 }
341                         }
342                 } /* end editmesh */
343                 else if (obedit->type == OB_ARMATURE) {
344                         bArmature *arm = obedit->data;
345                         EditBone *ebo;
346
347                         if ((v3d->around == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) {
348                                 /* doesn't check selection or visibility intentionally */
349                                 if (ebo->flag & BONE_TIPSEL) {
350                                         calc_tw_center(scene, ebo->tail);
351                                         totsel++;
352                                 }
353                                 if ((ebo->flag & BONE_ROOTSEL) ||
354                                     ((ebo->flag & BONE_TIPSEL) == false))  /* ensure we get at least one point */
355                                 {
356                                         calc_tw_center(scene, ebo->head);
357                                         totsel++;
358                                 }
359                                 stats_editbone(rv3d, ebo);
360                         }
361                         else {
362                                 for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
363                                         if (EBONE_VISIBLE(arm, ebo)) {
364                                                 if (ebo->flag & BONE_TIPSEL) {
365                                                         calc_tw_center(scene, ebo->tail);
366                                                         totsel++;
367                                                 }
368                                                 if ((ebo->flag & BONE_ROOTSEL) &&
369                                                     /* don't include same point multiple times */
370                                                     ((ebo->flag & BONE_CONNECTED) &&
371                                                      (ebo->parent != NULL) &&
372                                                      (ebo->parent->flag & BONE_TIPSEL) &&
373                                                      EBONE_VISIBLE(arm, ebo->parent)) == 0)
374                                                 {
375                                                         calc_tw_center(scene, ebo->head);
376                                                         totsel++;
377                                                 }
378                                                 if (ebo->flag & BONE_SELECTED) {
379                                                         stats_editbone(rv3d, ebo);
380                                                 }
381                                         }
382                                 }
383                         }
384                 }
385                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
386                         Curve *cu = obedit->data;
387                         float center[3];
388
389                         if (v3d->around == V3D_AROUND_ACTIVE && ED_curve_active_center(cu, center)) {
390                                 calc_tw_center(scene, center);
391                                 totsel++;
392                         }
393                         else {
394                                 Nurb *nu;
395                                 BezTriple *bezt;
396                                 BPoint *bp;
397                                 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
398
399                                 nu = nurbs->first;
400                                 while (nu) {
401                                         if (nu->type == CU_BEZIER) {
402                                                 bezt = nu->bezt;
403                                                 a = nu->pntsu;
404                                                 while (a--) {
405                                                         /* exceptions
406                                                          * if handles are hidden then only check the center points.
407                                                          * If the center knot is selected then only use this as the center point.
408                                                          */
409                                                         if (cu->drawflag & CU_HIDE_HANDLES) {
410                                                                 if (bezt->f2 & SELECT) {
411                                                                         calc_tw_center(scene, bezt->vec[1]);
412                                                                         totsel++;
413                                                                 }
414                                                         }
415                                                         else if (bezt->f2 & SELECT) {
416                                                                 calc_tw_center(scene, bezt->vec[1]);
417                                                                 totsel++;
418                                                         }
419                                                         else {
420                                                                 if (bezt->f1 & SELECT) {
421                                                                         calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]);
422                                                                         totsel++;
423                                                                 }
424                                                                 if (bezt->f3 & SELECT) {
425                                                                         calc_tw_center(scene, bezt->vec[(v3d->around == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]);
426                                                                         totsel++;
427                                                                 }
428                                                         }
429                                                         bezt++;
430                                                 }
431                                         }
432                                         else {
433                                                 bp = nu->bp;
434                                                 a = nu->pntsu * nu->pntsv;
435                                                 while (a--) {
436                                                         if (bp->f1 & SELECT) {
437                                                                 calc_tw_center(scene, bp->vec);
438                                                                 totsel++;
439                                                         }
440                                                         bp++;
441                                                 }
442                                         }
443                                         nu = nu->next;
444                                 }
445                         }
446                 }
447                 else if (obedit->type == OB_MBALL) {
448                         MetaBall *mb = (MetaBall *)obedit->data;
449                         MetaElem *ml;
450
451                         if ((v3d->around == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) {
452                                 calc_tw_center(scene, &ml->x);
453                                 totsel++;
454                         }
455                         else {
456                                 for (ml = mb->editelems->first; ml; ml = ml->next) {
457                                         if (ml->flag & SELECT) {
458                                                 calc_tw_center(scene, &ml->x);
459                                                 totsel++;
460                                         }
461                                 }
462                         }
463                 }
464                 else if (obedit->type == OB_LATTICE) {
465                         Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
466                         BPoint *bp;
467
468                         if ((v3d->around == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) {
469                                 calc_tw_center(scene, bp->vec);
470                                 totsel++;
471                         }
472                         else {
473                                 bp = lt->def;
474                                 a = lt->pntsu * lt->pntsv * lt->pntsw;
475                                 while (a--) {
476                                         if (bp->f1 & SELECT) {
477                                                 calc_tw_center(scene, bp->vec);
478                                                 totsel++;
479                                         }
480                                         bp++;
481                                 }
482                         }
483                 }
484
485                 /* selection center */
486                 if (totsel) {
487                         mul_v3_fl(scene->twcent, 1.0f / (float)totsel);   // centroid!
488                         mul_m4_v3(obedit->obmat, scene->twcent);
489                         mul_m4_v3(obedit->obmat, scene->twmin);
490                         mul_m4_v3(obedit->obmat, scene->twmax);
491                 }
492         }
493         else if (ob && (ob->mode & OB_MODE_POSE)) {
494                 bPoseChannel *pchan;
495                 int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed
496                 bool ok = false;
497
498                 if ((ob->lay & v3d->lay) == 0) return 0;
499
500                 if ((v3d->around == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) {
501                         /* doesn't check selection or visibility intentionally */
502                         Bone *bone = pchan->bone;
503                         if (bone) {
504                                 stats_pose(scene, rv3d, pchan);
505                                 totsel = 1;
506                                 ok = true;
507                         }
508                 }
509                 else {
510                         totsel = count_set_pose_transflags(&mode, 0, ob);
511
512                         if (totsel) {
513                                 /* use channels to get stats */
514                                 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
515                                         Bone *bone = pchan->bone;
516                                         if (bone && (bone->flag & BONE_TRANSFORM)) {
517                                                 stats_pose(scene, rv3d, pchan);
518                                         }
519                                 }
520                                 ok = true;
521                         }
522                 }
523
524                 if (ok) {
525                         mul_v3_fl(scene->twcent, 1.0f / (float)totsel);   // centroid!
526                         mul_m4_v3(ob->obmat, scene->twcent);
527                         mul_m4_v3(ob->obmat, scene->twmin);
528                         mul_m4_v3(ob->obmat, scene->twmax);
529                 }
530         }
531         else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
532                 /* pass */
533         }
534         else {
535
536                 /* we need the one selected object, if its not active */
537                 ob = OBACT;
538                 if (ob && !(ob->flag & SELECT)) ob = NULL;
539
540                 for (base = scene->base.first; base; base = base->next) {
541                         if (TESTBASELIB(v3d, base)) {
542                                 if (ob == NULL)
543                                         ob = base->object;
544                                 calc_tw_center(scene, base->object->obmat[3]);
545                                 protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
546                                 totsel++;
547                         }
548                 }
549
550                 /* selection center */
551                 if (totsel) {
552                         mul_v3_fl(scene->twcent, 1.0f / (float)totsel);   // centroid!
553                 }
554         }
555
556         /* global, local or normal orientation? */
557         if (ob && totsel && !is_gp_edit) {
558
559                 switch (v3d->twmode) {
560                 
561                         case V3D_MANIP_GLOBAL:
562                         {
563                                 break; /* nothing to do */
564                         }
565                         case V3D_MANIP_GIMBAL:
566                         {
567                                 float mat[3][3];
568                                 if (gimbal_axis(ob, mat)) {
569                                         copy_m4_m3(rv3d->twmat, mat);
570                                         break;
571                                 }
572                                 /* if not gimbal, fall through to normal */
573                                 /* fall-through */
574                         }
575                         case V3D_MANIP_NORMAL:
576                         {
577                                 if (obedit || ob->mode & OB_MODE_POSE) {
578                                         float mat[3][3];
579                                         ED_getTransformOrientationMatrix(C, mat, v3d->around);
580                                         copy_m4_m3(rv3d->twmat, mat);
581                                         break;
582                                 }
583                                 /* no break we define 'normal' as 'local' in Object mode */
584                                 /* fall-through */
585                         }
586                         case V3D_MANIP_LOCAL:
587                         {
588                                 if (ob->mode & OB_MODE_POSE) {
589                                         /* each bone moves on its own local axis, but  to avoid confusion,
590                                          * use the active pones axis for display [#33575], this works as expected on a single bone
591                                          * and users who select many bones will understand whats going on and what local means
592                                          * when they start transforming */
593                                         float mat[3][3];
594                                         ED_getTransformOrientationMatrix(C, mat, v3d->around);
595                                         copy_m4_m3(rv3d->twmat, mat);
596                                         break;
597                                 }
598                                 copy_m4_m4(rv3d->twmat, ob->obmat);
599                                 normalize_m4(rv3d->twmat);
600                                 break;
601                         }
602                         case V3D_MANIP_VIEW:
603                         {
604                                 float mat[3][3];
605                                 copy_m3_m4(mat, rv3d->viewinv);
606                                 normalize_m3(mat);
607                                 copy_m4_m3(rv3d->twmat, mat);
608                                 break;
609                         }
610                         default: /* V3D_MANIP_CUSTOM */
611                         {
612                                 float mat[3][3];
613                                 if (applyTransformOrientation(C, mat, NULL, v3d->twmode - V3D_MANIP_CUSTOM)) {
614                                         copy_m4_m3(rv3d->twmat, mat);
615                                 }
616                                 break;
617                         }
618                 }
619
620         }
621
622         return totsel;
623 }
624
625 /* don't draw axis perpendicular to the view */
626 static void test_manipulator_axis(const bContext *C)
627 {
628         RegionView3D *rv3d = CTX_wm_region_view3d(C);
629         float view_vec[3], axis_vec[3];
630         float idot;
631         int i;
632
633         const int twdrawflag_axis[3] = {
634             (MAN_TRANS_X | MAN_SCALE_X),
635             (MAN_TRANS_Y | MAN_SCALE_Y),
636             (MAN_TRANS_Z | MAN_SCALE_Z)};
637
638         ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec);
639
640         for (i = 0; i < 3; i++) {
641                 normalize_v3_v3(axis_vec, rv3d->twmat[i]);
642                 rv3d->tw_idot[i] = idot = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec));
643                 if (idot < TW_AXIS_DOT_MIN) {
644                         rv3d->twdrawflag &= ~twdrawflag_axis[i];
645                 }
646         }
647 }
648
649
650 /* ******************** DRAWING STUFFIES *********** */
651
652 static float screen_aligned(RegionView3D *rv3d, float mat[4][4])
653 {
654         glTranslate3fv(mat[3]);
655
656         /* sets view screen aligned */
657         glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]);
658
659         return len_v3(mat[0]); /* draw scale */
660 }
661
662
663 /* radring = radius of doughnut rings
664  * radhole = radius hole
665  * start = starting segment (based on nrings)
666  * end   = end segment
667  * nsides = amount of points in ring
668  * nrigns = amount of rings
669  */
670 static void partial_doughnut(float radring, float radhole, int start, int end, int nsides, int nrings)
671 {
672         float theta, phi, theta1;
673         float cos_theta, sin_theta;
674         float cos_theta1, sin_theta1;
675         float ring_delta, side_delta;
676         int i, j, do_caps = true;
677
678         if (start == 0 && end == nrings) do_caps = false;
679
680         ring_delta = 2.0f * (float)M_PI / (float)nrings;
681         side_delta = 2.0f * (float)M_PI / (float)nsides;
682
683         theta = (float)M_PI + 0.5f * ring_delta;
684         cos_theta = cosf(theta);
685         sin_theta = sinf(theta);
686
687         for (i = nrings - 1; i >= 0; i--) {
688                 theta1 = theta + ring_delta;
689                 cos_theta1 = cosf(theta1);
690                 sin_theta1 = sinf(theta1);
691
692                 if (do_caps && i == start) {  // cap
693                         glBegin(GL_POLYGON);
694                         phi = 0.0;
695                         for (j = nsides; j >= 0; j--) {
696                                 float cos_phi, sin_phi, dist;
697
698                                 phi += side_delta;
699                                 cos_phi = cosf(phi);
700                                 sin_phi = sinf(phi);
701                                 dist = radhole + radring * cos_phi;
702
703                                 glVertex3f(cos_theta1 * dist, -sin_theta1 * dist,  radring * sin_phi);
704                         }
705                         glEnd();
706                 }
707                 if (i >= start && i <= end) {
708                         glBegin(GL_QUAD_STRIP);
709                         phi = 0.0;
710                         for (j = nsides; j >= 0; j--) {
711                                 float cos_phi, sin_phi, dist;
712
713                                 phi += side_delta;
714                                 cos_phi = cosf(phi);
715                                 sin_phi = sinf(phi);
716                                 dist = radhole + radring * cos_phi;
717
718                                 glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi);
719                                 glVertex3f(cos_theta * dist, -sin_theta * dist,  radring * sin_phi);
720                         }
721                         glEnd();
722                 }
723
724                 if (do_caps && i == end) {    // cap
725                         glBegin(GL_POLYGON);
726                         phi = 0.0;
727                         for (j = nsides; j >= 0; j--) {
728                                 float cos_phi, sin_phi, dist;
729
730                                 phi -= side_delta;
731                                 cos_phi = cosf(phi);
732                                 sin_phi = sinf(phi);
733                                 dist = radhole + radring * cos_phi;
734
735                                 glVertex3f(cos_theta * dist, -sin_theta * dist,  radring * sin_phi);
736                         }
737                         glEnd();
738                 }
739
740
741                 theta = theta1;
742                 cos_theta = cos_theta1;
743                 sin_theta = sin_theta1;
744         }
745 }
746
747 static char axisBlendAngle(float idot)
748 {
749         if (idot > TW_AXIS_DOT_MAX) {
750                 return 255;
751         }
752         else if (idot < TW_AXIS_DOT_MIN) {
753                 return 0;
754         }
755         else {
756                 return (char)(255.0f * (idot - TW_AXIS_DOT_MIN) / (TW_AXIS_DOT_MAX - TW_AXIS_DOT_MIN));
757         }
758 }
759
760 /* three colors can be set:
761  * gray for ghosting
762  * moving: in transform theme color
763  * else the red/green/blue
764  */
765 static void manipulator_setcolor(View3D *v3d, char axis, int colcode, unsigned char alpha)
766 {
767         unsigned char col[4] = {0};
768         col[3] = alpha;
769
770         if (colcode == MAN_GHOST) {
771                 col[3] = 70;
772         }
773         else if (colcode == MAN_MOVECOL) {
774                 UI_GetThemeColor3ubv(TH_TRANSFORM, col);
775         }
776         else {
777                 switch (axis) {
778                         case 'C':
779                                 UI_GetThemeColor3ubv(TH_TRANSFORM, col);
780                                 if (v3d->twmode == V3D_MANIP_LOCAL) {
781                                         col[0] = col[0] > 200 ? 255 : col[0] + 55;
782                                         col[1] = col[1] > 200 ? 255 : col[1] + 55;
783                                         col[2] = col[2] > 200 ? 255 : col[2] + 55;
784                                 }
785                                 else if (v3d->twmode == V3D_MANIP_NORMAL) {
786                                         col[0] = col[0] < 55 ? 0 : col[0] - 55;
787                                         col[1] = col[1] < 55 ? 0 : col[1] - 55;
788                                         col[2] = col[2] < 55 ? 0 : col[2] - 55;
789                                 }
790                                 break;
791                         case 'X':
792                                 UI_GetThemeColor3ubv(TH_AXIS_X, col);
793                                 break;
794                         case 'Y':
795                                 UI_GetThemeColor3ubv(TH_AXIS_Y, col);
796                                 break;
797                         case 'Z':
798                                 UI_GetThemeColor3ubv(TH_AXIS_Z, col);
799                                 break;
800                         default:
801                                 BLI_assert(0);
802                                 break;
803                 }
804         }
805
806         glColor4ubv(col);
807 }
808
809 static void manipulator_axis_order(RegionView3D *rv3d, int r_axis_order[3])
810 {
811         float axis_values[3];
812         float vec[3];
813
814         ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], vec);
815
816         axis_values[0] = -dot_v3v3(rv3d->twmat[0], vec);
817         axis_values[1] = -dot_v3v3(rv3d->twmat[1], vec);
818         axis_values[2] = -dot_v3v3(rv3d->twmat[2], vec);
819
820         axis_sort_v3(axis_values, r_axis_order);
821 }
822
823 /* viewmatrix should have been set OK, also no shademode! */
824 static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int colcode,
825                                          int flagx, int flagy, int flagz, int axis,
826                                          const bool is_picksel)
827 {
828         switch (axis) {
829                 case 0:
830                         /* axes */
831                         if (flagx) {
832                                 if (is_picksel) {
833                                         if      (flagx & MAN_SCALE_X) GPU_select_load_id(MAN_SCALE_X);
834                                         else if (flagx & MAN_TRANS_X) GPU_select_load_id(MAN_TRANS_X);
835                                 }
836                                 else {
837                                         manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]));
838                                 }
839                                 glBegin(GL_LINES);
840                                 glVertex3f(0.2f, 0.0f, 0.0f);
841                                 glVertex3f(1.0f, 0.0f, 0.0f);
842                                 glEnd();
843                         }
844                         break;
845                 case 1:
846                         if (flagy) {
847                                 if (is_picksel) {
848                                         if      (flagy & MAN_SCALE_Y) GPU_select_load_id(MAN_SCALE_Y);
849                                         else if (flagy & MAN_TRANS_Y) GPU_select_load_id(MAN_TRANS_Y);
850                                 }
851                                 else {
852                                         manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]));
853                                 }
854                                 glBegin(GL_LINES);
855                                 glVertex3f(0.0f, 0.2f, 0.0f);
856                                 glVertex3f(0.0f, 1.0f, 0.0f);
857                                 glEnd();
858                         }
859                         break;
860                 case 2:
861                         if (flagz) {
862                                 if (is_picksel) {
863                                         if      (flagz & MAN_SCALE_Z) GPU_select_load_id(MAN_SCALE_Z);
864                                         else if (flagz & MAN_TRANS_Z) GPU_select_load_id(MAN_TRANS_Z);
865                                 }
866                                 else {
867                                         manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]));
868                                 }
869                                 glBegin(GL_LINES);
870                                 glVertex3f(0.0f, 0.0f, 0.2f);
871                                 glVertex3f(0.0f, 0.0f, 1.0f);
872                                 glEnd();
873                         }
874                         break;
875         }
876 }
877 static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode,
878                                   int flagx, int flagy, int flagz,
879                                   const int axis_order[3], const bool is_picksel)
880 {
881         int i;
882         for (i = 0; i < 3; i++) {
883                 draw_manipulator_axes_single(v3d, rv3d, colcode, flagx, flagy, flagz, axis_order[i], is_picksel);
884         }
885 }
886
887 static void preOrthoFront(const bool ortho, float twmat[4][4], int axis)
888 {
889         if (ortho == false) {
890                 float omat[4][4];
891                 copy_m4_m4(omat, twmat);
892                 orthogonalize_m4(omat, axis);
893                 glPushMatrix();
894                 glMultMatrixf(omat);
895                 glFrontFace(is_negative_m4(omat) ? GL_CW : GL_CCW);
896         }
897 }
898
899 static void postOrtho(const bool ortho)
900 {
901         if (ortho == false) {
902                 glPopMatrix();
903         }
904 }
905
906 BLI_INLINE bool manipulator_rotate_is_visible(const int drawflags)
907 {
908         return (drawflags & (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z));
909 }
910
911 static void draw_manipulator_rotate(
912         View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo,
913         const bool is_moving, const bool is_picksel)
914 {
915         double plane[4];
916         float matt[4][4];
917         float size, unitmat[4][4];
918         float cywid = 0.33f * 0.01f * (float)U.tw_handlesize;
919         float cusize = cywid * 0.65f;
920         int arcs = (G.debug_value != 2);
921         const int colcode = (is_moving) ? MAN_MOVECOL : MAN_RGB;
922         bool ortho;
923
924         /* skip drawing if all axes are locked */
925         if (manipulator_rotate_is_visible(drawflags) == false) return;
926
927         /* Init stuff */
928         glDisable(GL_DEPTH_TEST);
929         unit_m4(unitmat);
930
931         /* prepare for screen aligned draw */
932         size = len_v3(rv3d->twmat[0]);
933         glPushMatrix();
934         glTranslate3fv(rv3d->twmat[3]);
935
936         if (arcs) {
937                 /* clipplane makes nice handles, calc here because of multmatrix but with translate! */
938                 copy_v3db_v3fl(plane, rv3d->viewinv[2]);
939                 plane[3] = -0.02f * size; // clip just a bit more
940                 glClipPlane(GL_CLIP_PLANE0, plane);
941         }
942         /* sets view screen aligned */
943         glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]);
944
945         /* Screen aligned help circle */
946         if (arcs) {
947                 if (is_picksel == false) {
948                         UI_ThemeColorShade(TH_BACK, -30);
949                         drawcircball(GL_LINE_LOOP, unitmat[3], size, unitmat);
950                 }
951         }
952
953         /* Screen aligned trackball rot circle */
954         if (drawflags & MAN_ROT_T) {
955                 if (is_picksel) GPU_select_load_id(MAN_ROT_T);
956                 else UI_ThemeColor(TH_TRANSFORM);
957
958                 drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
959         }
960
961         /* Screen aligned view rot circle */
962         if (drawflags & MAN_ROT_V) {
963                 if (is_picksel) GPU_select_load_id(MAN_ROT_V);
964                 else UI_ThemeColor(TH_TRANSFORM);
965                 drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat);
966
967                 if (is_moving) {
968                         float vec[3];
969                         vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]);
970                         vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]);
971                         vec[2] = 0.0f;
972                         normalize_v3_length(vec, 1.2f * size);
973                         glBegin(GL_LINES);
974                         glVertex3f(0.0f, 0.0f, 0.0f);
975                         glVertex3fv(vec);
976                         glEnd();
977                 }
978         }
979         glPopMatrix();
980
981
982         ortho = is_orthogonal_m4(rv3d->twmat);
983         
984         /* apply the transform delta */
985         if (is_moving) {
986                 copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
987                 // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
988                 if (ortho) {
989                         glMultMatrixf(matt);
990                         glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW);
991                 }
992         }
993         else {
994                 if (ortho) {
995                         glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW);
996                         glMultMatrixf(rv3d->twmat);
997                 }
998         }
999
1000         /* axes */
1001         if (arcs == 0) {
1002                 if (!is_picksel) {
1003                         if ((combo & V3D_MANIP_SCALE) == 0) {
1004                                 /* axis */
1005                                 if ((drawflags & MAN_ROT_X) || (is_moving && (drawflags & MAN_ROT_Z))) {
1006                                         preOrthoFront(ortho, rv3d->twmat, 2);
1007                                         manipulator_setcolor(v3d, 'X', colcode, 255);
1008                                         glBegin(GL_LINES);
1009                                         glVertex3f(0.2f, 0.0f, 0.0f);
1010                                         glVertex3f(1.0f, 0.0f, 0.0f);
1011                                         glEnd();
1012                                         postOrtho(ortho);
1013                                 }
1014                                 if ((drawflags & MAN_ROT_Y) || (is_moving && (drawflags & MAN_ROT_X))) {
1015                                         preOrthoFront(ortho, rv3d->twmat, 0);
1016                                         manipulator_setcolor(v3d, 'Y', colcode, 255);
1017                                         glBegin(GL_LINES);
1018                                         glVertex3f(0.0f, 0.2f, 0.0f);
1019                                         glVertex3f(0.0f, 1.0f, 0.0f);
1020                                         glEnd();
1021                                         postOrtho(ortho);
1022                                 }
1023                                 if ((drawflags & MAN_ROT_Z) || (is_moving && (drawflags & MAN_ROT_Y))) {
1024                                         preOrthoFront(ortho, rv3d->twmat, 1);
1025                                         manipulator_setcolor(v3d, 'Z', colcode, 255);
1026                                         glBegin(GL_LINES);
1027                                         glVertex3f(0.0f, 0.0f, 0.2f);
1028                                         glVertex3f(0.0f, 0.0f, 1.0f);
1029                                         glEnd();
1030                                         postOrtho(ortho);
1031                                 }
1032                         }
1033                 }
1034         }
1035
1036         if (arcs == 0 && is_moving) {
1037
1038                 /* Z circle */
1039                 if (drawflags & MAN_ROT_Z) {
1040                         preOrthoFront(ortho, matt, 2);
1041                         if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
1042                         else manipulator_setcolor(v3d, 'Z', colcode, 255);
1043                         drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
1044                         postOrtho(ortho);
1045                 }
1046                 /* X circle */
1047                 if (drawflags & MAN_ROT_X) {
1048                         preOrthoFront(ortho, matt, 0);
1049                         if (is_picksel) GPU_select_load_id(MAN_ROT_X);
1050                         else manipulator_setcolor(v3d, 'X', colcode, 255);
1051                         glRotatef(90.0, 0.0, 1.0, 0.0);
1052                         drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
1053                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1054                         postOrtho(ortho);
1055                 }
1056                 /* Y circle */
1057                 if (drawflags & MAN_ROT_Y) {
1058                         preOrthoFront(ortho, matt, 1);
1059                         if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
1060                         else manipulator_setcolor(v3d, 'Y', colcode, 255);
1061                         glRotatef(-90.0, 1.0, 0.0, 0.0);
1062                         drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
1063                         glRotatef(90.0, 1.0, 0.0, 0.0);
1064                         postOrtho(ortho);
1065                 }
1066         }
1067         // donut arcs
1068         if (arcs) {
1069                 glEnable(GL_CLIP_PLANE0);
1070
1071                 /* Z circle */
1072                 if (drawflags & MAN_ROT_Z) {
1073                         preOrthoFront(ortho, rv3d->twmat, 2);
1074                         if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
1075                         else manipulator_setcolor(v3d, 'Z', colcode, 255);
1076                         partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
1077                         postOrtho(ortho);
1078                 }
1079                 /* X circle */
1080                 if (drawflags & MAN_ROT_X) {
1081                         preOrthoFront(ortho, rv3d->twmat, 0);
1082                         if (is_picksel) GPU_select_load_id(MAN_ROT_X);
1083                         else manipulator_setcolor(v3d, 'X', colcode, 255);
1084                         glRotatef(90.0, 0.0, 1.0, 0.0);
1085                         partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
1086                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1087                         postOrtho(ortho);
1088                 }
1089                 /* Y circle */
1090                 if (drawflags & MAN_ROT_Y) {
1091                         preOrthoFront(ortho, rv3d->twmat, 1);
1092                         if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
1093                         else manipulator_setcolor(v3d, 'Y', colcode, 255);
1094                         glRotatef(-90.0, 1.0, 0.0, 0.0);
1095                         partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
1096                         glRotatef(90.0, 1.0, 0.0, 0.0);
1097                         postOrtho(ortho);
1098                 }
1099
1100                 glDisable(GL_CLIP_PLANE0);
1101         }
1102
1103         if (arcs == 0) {
1104
1105                 /* Z handle on X axis */
1106                 if (drawflags & MAN_ROT_Z) {
1107                         preOrthoFront(ortho, rv3d->twmat, 2);
1108                         glPushMatrix();
1109                         if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
1110                         else manipulator_setcolor(v3d, 'Z', colcode, 255);
1111
1112                         partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
1113
1114                         glPopMatrix();
1115                         postOrtho(ortho);
1116                 }
1117
1118                 /* Y handle on X axis */
1119                 if (drawflags & MAN_ROT_Y) {
1120                         preOrthoFront(ortho, rv3d->twmat, 1);
1121                         glPushMatrix();
1122                         if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
1123                         else manipulator_setcolor(v3d, 'Y', colcode, 255);
1124
1125                         glRotatef(90.0, 1.0, 0.0, 0.0);
1126                         glRotatef(90.0, 0.0, 0.0, 1.0);
1127                         partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
1128
1129                         glPopMatrix();
1130                         postOrtho(ortho);
1131                 }
1132
1133                 /* X handle on Z axis */
1134                 if (drawflags & MAN_ROT_X) {
1135                         preOrthoFront(ortho, rv3d->twmat, 0);
1136                         glPushMatrix();
1137                         if (is_picksel) GPU_select_load_id(MAN_ROT_X);
1138                         else manipulator_setcolor(v3d, 'X', colcode, 255);
1139
1140                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1141                         glRotatef(90.0, 0.0, 0.0, 1.0);
1142                         partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
1143
1144                         glPopMatrix();
1145                         postOrtho(ortho);
1146                 }
1147
1148         }
1149
1150         /* restore */
1151         glLoadMatrixf(rv3d->viewmat);
1152         if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1153
1154 }
1155
1156 static void drawsolidcube(float size)
1157 {
1158         const float cube[8][3] = {
1159                 {-1.0, -1.0, -1.0},
1160                 {-1.0, -1.0,  1.0},
1161                 {-1.0,  1.0,  1.0},
1162                 {-1.0,  1.0, -1.0},
1163                 { 1.0, -1.0, -1.0},
1164                 { 1.0, -1.0,  1.0},
1165                 { 1.0,  1.0,  1.0},
1166                 { 1.0,  1.0, -1.0},
1167         };
1168         float n[3] = {0.0f};
1169
1170         glPushMatrix();
1171         glScalef(size, size, size);
1172
1173         glBegin(GL_QUADS);
1174         n[0] = -1.0;
1175         glNormal3fv(n);
1176         glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
1177         n[0] = 0;
1178         glEnd();
1179
1180         glBegin(GL_QUADS);
1181         n[1] = -1.0;
1182         glNormal3fv(n);
1183         glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]);
1184         n[1] = 0;
1185         glEnd();
1186
1187         glBegin(GL_QUADS);
1188         n[0] = 1.0;
1189         glNormal3fv(n);
1190         glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]);
1191         n[0] = 0;
1192         glEnd();
1193
1194         glBegin(GL_QUADS);
1195         n[1] = 1.0;
1196         glNormal3fv(n);
1197         glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]);
1198         n[1] = 0;
1199         glEnd();
1200
1201         glBegin(GL_QUADS);
1202         n[2] = 1.0;
1203         glNormal3fv(n);
1204         glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]);
1205         n[2] = 0;
1206         glEnd();
1207
1208         glBegin(GL_QUADS);
1209         n[2] = -1.0;
1210         glNormal3fv(n);
1211         glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]);
1212         glEnd();
1213
1214         glPopMatrix();
1215 }
1216
1217
1218 static void draw_manipulator_scale(
1219         View3D *v3d, RegionView3D *rv3d, const int drawflags, const int combo, const int colcode,
1220         const bool is_moving, const bool is_picksel)
1221 {
1222         float cywid = 0.25f * 0.01f * (float)U.tw_handlesize;
1223         float cusize = cywid * 0.75f, dz;
1224         int axis_order[3] = {2, 0, 1};
1225         int i;
1226
1227         /* when called while moving in mixed mode, do not draw when... */
1228         if ((drawflags & MAN_SCALE_C) == 0) return;
1229
1230         manipulator_axis_order(rv3d, axis_order);
1231
1232         glDisable(GL_DEPTH_TEST);
1233
1234         /* not in combo mode */
1235         if ((combo & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) == 0) {
1236                 float size, unitmat[4][4];
1237                 int shift = 0; // XXX
1238
1239                 /* center circle, do not add to selection when shift is pressed (planar constraint)  */
1240                 if (is_picksel && shift == 0) GPU_select_load_id(MAN_SCALE_C);
1241                 else manipulator_setcolor(v3d, 'C', colcode, 255);
1242
1243                 glPushMatrix();
1244                 size = screen_aligned(rv3d, rv3d->twmat);
1245                 unit_m4(unitmat);
1246                 drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
1247                 glPopMatrix();
1248
1249                 dz = 1.0;
1250         }
1251         else {
1252                 dz = 1.0f - 4.0f * cusize;
1253         }
1254
1255         if (is_moving) {
1256                 float matt[4][4];
1257
1258                 copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
1259                 // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
1260                 glMultMatrixf(matt);
1261                 glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW);
1262         }
1263         else {
1264                 glMultMatrixf(rv3d->twmat);
1265                 glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW);
1266         }
1267
1268         /* axis */
1269
1270         /* in combo mode, this is always drawn as first type */
1271         draw_manipulator_axes(v3d, rv3d, colcode,
1272                               drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z,
1273                               axis_order, is_picksel);
1274
1275
1276         for (i = 0; i < 3; i++) {
1277                 switch (axis_order[i]) {
1278                         case 0: /* X cube */
1279                                 if (drawflags & MAN_SCALE_X) {
1280                                         glTranslatef(dz, 0.0, 0.0);
1281                                         if (is_picksel) GPU_select_load_id(MAN_SCALE_X);
1282                                         else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]));
1283                                         drawsolidcube(cusize);
1284                                         glTranslatef(-dz, 0.0, 0.0);
1285                                 }
1286                                 break;
1287                         case 1: /* Y cube */
1288                                 if (drawflags & MAN_SCALE_Y) {
1289                                         glTranslatef(0.0, dz, 0.0);
1290                                         if (is_picksel) GPU_select_load_id(MAN_SCALE_Y);
1291                                         else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]));
1292                                         drawsolidcube(cusize);
1293                                         glTranslatef(0.0, -dz, 0.0);
1294                                 }
1295                                 break;
1296                         case 2: /* Z cube */
1297                                 if (drawflags & MAN_SCALE_Z) {
1298                                         glTranslatef(0.0, 0.0, dz);
1299                                         if (is_picksel) GPU_select_load_id(MAN_SCALE_Z);
1300                                         else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]));
1301                                         drawsolidcube(cusize);
1302                                         glTranslatef(0.0, 0.0, -dz);
1303                                 }
1304                                 break;
1305                 }
1306         }
1307
1308 #if 0 // XXX
1309         /* if shiftkey, center point as last, for selectbuffer order */
1310         if (is_picksel) {
1311                 int shift = 0; // XXX
1312
1313                 if (shift) {
1314                         glTranslatef(0.0, -dz, 0.0);
1315                         GPU_select_load_id(MAN_SCALE_C);
1316                         /* TODO: set glPointSize before drawing center point */
1317                         glBegin(GL_POINTS);
1318                         glVertex3f(0.0, 0.0, 0.0);
1319                         glEnd();
1320                 }
1321         }
1322 #endif
1323
1324         /* restore */
1325         glLoadMatrixf(rv3d->viewmat);
1326
1327         if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1328         glFrontFace(GL_CCW);
1329 }
1330
1331
1332 static void draw_cone(GLUquadricObj *qobj, float len, float width)
1333 {
1334         glTranslatef(0.0, 0.0, -0.5f * len);
1335         gluCylinder(qobj, width, 0.0, len, 8, 1);
1336         gluQuadricOrientation(qobj, GLU_INSIDE);
1337         gluDisk(qobj, 0.0, width, 8, 1);
1338         gluQuadricOrientation(qobj, GLU_OUTSIDE);
1339         glTranslatef(0.0, 0.0, 0.5f * len);
1340 }
1341
1342 static void draw_cylinder(GLUquadricObj *qobj, float len, float width)
1343 {
1344
1345         width *= 0.8f;   // just for beauty
1346
1347         glTranslatef(0.0, 0.0, -0.5f * len);
1348         gluCylinder(qobj, width, width, len, 8, 1);
1349         gluQuadricOrientation(qobj, GLU_INSIDE);
1350         gluDisk(qobj, 0.0, width, 8, 1);
1351         gluQuadricOrientation(qobj, GLU_OUTSIDE);
1352         glTranslatef(0.0, 0.0, len);
1353         gluDisk(qobj, 0.0, width, 8, 1);
1354         glTranslatef(0.0, 0.0, -0.5f * len);
1355 }
1356
1357
1358 static void draw_manipulator_translate(
1359         View3D *v3d, RegionView3D *rv3d, int drawflags, int combo, int colcode,
1360         const bool UNUSED(is_moving), const bool is_picksel)
1361 {
1362         GLUquadricObj *qobj;
1363         float cylen = 0.01f * (float)U.tw_handlesize;
1364         float cywid = 0.25f * cylen, dz, size;
1365         float unitmat[4][4];
1366         int shift = 0; // XXX
1367         int axis_order[3] = {0, 1, 2};
1368         int i;
1369
1370         /* when called while moving in mixed mode, do not draw when... */
1371         if ((drawflags & MAN_TRANS_C) == 0) return;
1372
1373         manipulator_axis_order(rv3d, axis_order);
1374
1375         // XXX if (moving) glTranslate3fv(t->vec);
1376         glDisable(GL_DEPTH_TEST);
1377
1378         /* center circle, do not add to selection when shift is pressed (planar constraint) */
1379         if (is_picksel && shift == 0) GPU_select_load_id(MAN_TRANS_C);
1380         else manipulator_setcolor(v3d, 'C', colcode, 255);
1381
1382         glPushMatrix();
1383         size = screen_aligned(rv3d, rv3d->twmat);
1384         unit_m4(unitmat);
1385         drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
1386         glPopMatrix();
1387
1388         /* and now apply matrix, we move to local matrix drawing */
1389         glMultMatrixf(rv3d->twmat);
1390
1391         /* axis */
1392         GPU_select_load_id(-1);
1393
1394         // translate drawn as last, only axis when no combo with scale, or for ghosting
1395         if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) {
1396                 draw_manipulator_axes(v3d, rv3d, colcode,
1397                                       drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z,
1398                                       axis_order, is_picksel);
1399         }
1400
1401
1402         /* offset in combo mode, for rotate a bit more */
1403         if (combo & (V3D_MANIP_ROTATE)) dz = 1.0f + 2.0f * cylen;
1404         else if (combo & (V3D_MANIP_SCALE)) dz = 1.0f + 0.5f * cylen;
1405         else dz = 1.0f;
1406
1407         qobj = gluNewQuadric();
1408         gluQuadricDrawStyle(qobj, GLU_FILL);
1409
1410         for (i = 0; i < 3; i++) {
1411                 switch (axis_order[i]) {
1412                         case 0: /* Z Cone */
1413                                 if (drawflags & MAN_TRANS_Z) {
1414                                         glTranslatef(0.0, 0.0, dz);
1415                                         if (is_picksel) GPU_select_load_id(MAN_TRANS_Z);
1416                                         else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]));
1417                                         draw_cone(qobj, cylen, cywid);
1418                                         glTranslatef(0.0, 0.0, -dz);
1419                                 }
1420                                 break;
1421                         case 1: /* X Cone */
1422                                 if (drawflags & MAN_TRANS_X) {
1423                                         glTranslatef(dz, 0.0, 0.0);
1424                                         if (is_picksel) GPU_select_load_id(MAN_TRANS_X);
1425                                         else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]));
1426                                         glRotatef(90.0, 0.0, 1.0, 0.0);
1427                                         draw_cone(qobj, cylen, cywid);
1428                                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1429                                         glTranslatef(-dz, 0.0, 0.0);
1430                                 }
1431                                 break;
1432                         case 2: /* Y Cone */
1433                                 if (drawflags & MAN_TRANS_Y) {
1434                                         glTranslatef(0.0, dz, 0.0);
1435                                         if (is_picksel) GPU_select_load_id(MAN_TRANS_Y);
1436                                         else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]));
1437                                         glRotatef(-90.0, 1.0, 0.0, 0.0);
1438                                         draw_cone(qobj, cylen, cywid);
1439                                         glRotatef(90.0, 1.0, 0.0, 0.0);
1440                                         glTranslatef(0.0, -dz, 0.0);
1441                                 }
1442                                 break;
1443                 }
1444         }
1445
1446         gluDeleteQuadric(qobj);
1447         glLoadMatrixf(rv3d->viewmat);
1448
1449         if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1450
1451 }
1452
1453 static void draw_manipulator_rotate_cyl(
1454         View3D *v3d, RegionView3D *rv3d, int drawflags, const int combo, const int colcode,
1455         const bool is_moving, const bool is_picksel)
1456 {
1457         GLUquadricObj *qobj;
1458         float size;
1459         float cylen = 0.01f * (float)U.tw_handlesize;
1460         float cywid = 0.25f * cylen;
1461         int axis_order[3] = {2, 0, 1};
1462         int i;
1463
1464         /* skip drawing if all axes are locked */
1465         if (manipulator_rotate_is_visible(drawflags) == false) return;
1466
1467         manipulator_axis_order(rv3d, axis_order);
1468
1469         /* prepare for screen aligned draw */
1470         glPushMatrix();
1471         size = screen_aligned(rv3d, rv3d->twmat);
1472
1473         glDisable(GL_DEPTH_TEST);
1474
1475         qobj = gluNewQuadric();
1476
1477         /* Screen aligned view rot circle */
1478         if (drawflags & MAN_ROT_V) {
1479                 float unitmat[4][4];
1480
1481                 unit_m4(unitmat);
1482
1483                 if (is_picksel) GPU_select_load_id(MAN_ROT_V);
1484                 UI_ThemeColor(TH_TRANSFORM);
1485                 drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat);
1486
1487                 if (is_moving) {
1488                         float vec[3];
1489                         vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]);
1490                         vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]);
1491                         vec[2] = 0.0f;
1492                         normalize_v3_length(vec, 1.2f * size);
1493                         glBegin(GL_LINES);
1494                         glVertex3f(0.0, 0.0, 0.0);
1495                         glVertex3fv(vec);
1496                         glEnd();
1497                 }
1498         }
1499         glPopMatrix();
1500
1501         /* apply the transform delta */
1502         if (is_moving) {
1503                 float matt[4][4];
1504                 copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
1505                 // XXX      if (t->flag & T_USES_MANIPULATOR) {
1506                 // XXX          mul_m4_m3m4(matt, t->mat, rv3d->twmat);
1507                 // XXX }
1508                 glMultMatrixf(matt);
1509         }
1510         else {
1511                 glMultMatrixf(rv3d->twmat);
1512         }
1513
1514         glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW);
1515
1516         /* axis */
1517         if (is_picksel == false) {
1518
1519                 // only draw axis when combo didn't draw scale axes
1520                 if ((combo & V3D_MANIP_SCALE) == 0) {
1521                         draw_manipulator_axes(v3d, rv3d, colcode,
1522                                               drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z,
1523                                               axis_order, is_picksel);
1524                 }
1525
1526                 /* only has to be set when not in picking */
1527                 gluQuadricDrawStyle(qobj, GLU_FILL);
1528         }
1529
1530         for (i = 0; i < 3; i++) {
1531                 switch (axis_order[i]) {
1532                         case 0: /* X cylinder */
1533                                 if (drawflags & MAN_ROT_X) {
1534                                         glTranslatef(1.0, 0.0, 0.0);
1535                                         if (is_picksel) GPU_select_load_id(MAN_ROT_X);
1536                                         glRotatef(90.0, 0.0, 1.0, 0.0);
1537                                         manipulator_setcolor(v3d, 'X', colcode, 255);
1538                                         draw_cylinder(qobj, cylen, cywid);
1539                                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1540                                         glTranslatef(-1.0, 0.0, 0.0);
1541                                 }
1542                                 break;
1543                         case 1: /* Y cylinder */
1544                                 if (drawflags & MAN_ROT_Y) {
1545                                         glTranslatef(0.0, 1.0, 0.0);
1546                                         if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
1547                                         glRotatef(-90.0, 1.0, 0.0, 0.0);
1548                                         manipulator_setcolor(v3d, 'Y', colcode, 255);
1549                                         draw_cylinder(qobj, cylen, cywid);
1550                                         glRotatef(90.0, 1.0, 0.0, 0.0);
1551                                         glTranslatef(0.0, -1.0, 0.0);
1552                                 }
1553                                 break;
1554                         case 2: /* Z cylinder */
1555                                 if (drawflags & MAN_ROT_Z) {
1556                                         glTranslatef(0.0, 0.0, 1.0);
1557                                         if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
1558                                         manipulator_setcolor(v3d, 'Z', colcode, 255);
1559                                         draw_cylinder(qobj, cylen, cywid);
1560                                         glTranslatef(0.0, 0.0, -1.0);
1561                                 }
1562                                 break;
1563                 }
1564         }
1565
1566         /* restore */
1567
1568         gluDeleteQuadric(qobj);
1569         glLoadMatrixf(rv3d->viewmat);
1570
1571         if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1572
1573 }
1574
1575
1576 /* ********************************************* */
1577
1578 /* main call, does calc centers & orientation too */
1579 static int drawflags = 0xFFFF;       // only for the calls below, belongs in scene...?
1580
1581 void BIF_draw_manipulator(const bContext *C)
1582 {
1583         ScrArea *sa = CTX_wm_area(C);
1584         ARegion *ar = CTX_wm_region(C);
1585         Scene *scene = CTX_data_scene(C);
1586         View3D *v3d = sa->spacedata.first;
1587         RegionView3D *rv3d = ar->regiondata;
1588         int totsel;
1589
1590         const bool is_picksel = false;
1591
1592         if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return;
1593
1594         if ((v3d->twtype & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE | V3D_MANIP_SCALE)) == 0) return;
1595
1596         {
1597                 v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
1598
1599                 totsel = calc_manipulator_stats(C);
1600                 if (totsel == 0) return;
1601
1602                 v3d->twflag |= V3D_DRAW_MANIPULATOR;
1603
1604                 /* now we can define center */
1605                 switch (v3d->around) {
1606                         case V3D_AROUND_CENTER_BOUNDS:
1607                         case V3D_AROUND_ACTIVE:
1608                         {
1609                                 bGPdata *gpd = CTX_data_gpencil_data(C);
1610                                 Object *ob = OBACT;
1611
1612                                 if (((v3d->around == V3D_AROUND_ACTIVE) && (scene->obedit == NULL)) &&
1613                                     ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
1614                                     (ob && !(ob->mode & OB_MODE_POSE)))
1615                                 {
1616                                         copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
1617                                 }
1618                                 else {
1619                                         mid_v3_v3v3(rv3d->twmat[3], scene->twmin, scene->twmax);
1620                                 }
1621                                 break;
1622                         }
1623                         case V3D_AROUND_LOCAL_ORIGINS:
1624                         case V3D_AROUND_CENTER_MEAN:
1625                                 copy_v3_v3(rv3d->twmat[3], scene->twcent);
1626                                 break;
1627                         case V3D_AROUND_CURSOR:
1628                                 copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d));
1629                                 break;
1630                 }
1631
1632                 mul_mat3_m4_fl(rv3d->twmat, ED_view3d_pixel_size(rv3d, rv3d->twmat[3]) * U.tw_size);
1633         }
1634
1635         /* when looking through a selected camera, the manipulator can be at the
1636          * exact same position as the view, skip so we don't break selection */
1637         if (fabsf(mat4_to_scale(rv3d->twmat)) < 1e-7f)
1638                 return;
1639
1640         test_manipulator_axis(C);
1641         drawflags = rv3d->twdrawflag;    /* set in calc_manipulator_stats */
1642
1643         if (v3d->twflag & V3D_DRAW_MANIPULATOR) {
1644                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1645                 glEnable(GL_BLEND);
1646                 glLineWidth(1.0f);
1647
1648                 if (v3d->twtype & V3D_MANIP_ROTATE) {
1649                         if (G.debug_value == 3) {
1650                                 if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT))
1651                                         draw_manipulator_rotate_cyl(v3d, rv3d, drawflags, v3d->twtype, MAN_MOVECOL, true, is_picksel);
1652                                 else
1653                                         draw_manipulator_rotate_cyl(v3d, rv3d, drawflags, v3d->twtype, MAN_RGB, false, is_picksel);
1654                         }
1655                         else {
1656                                 draw_manipulator_rotate(v3d, rv3d, drawflags, v3d->twtype, false, is_picksel);
1657                         }
1658                 }
1659                 if (v3d->twtype & V3D_MANIP_SCALE) {
1660                         draw_manipulator_scale(v3d, rv3d, drawflags, v3d->twtype, MAN_RGB, false, is_picksel);
1661                 }
1662                 if (v3d->twtype & V3D_MANIP_TRANSLATE) {
1663                         draw_manipulator_translate(v3d, rv3d, drawflags, v3d->twtype, MAN_RGB, false, is_picksel);
1664                 }
1665
1666                 glDisable(GL_BLEND);
1667         }
1668 }
1669
1670 static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], float hotspot)
1671 {
1672         View3D *v3d = sa->spacedata.first;
1673         RegionView3D *rv3d = ar->regiondata;
1674         rctf rect, selrect;
1675         GLuint buffer[64];      // max 4 items per select, so large enuf
1676         short hits;
1677         const bool is_picksel = true;
1678         const bool do_passes = GPU_select_query_check_active();
1679
1680         /* XXX check a bit later on this... (ton) */
1681         extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect);
1682
1683         /* when looking through a selected camera, the manipulator can be at the
1684          * exact same position as the view, skip so we don't break selection */
1685         if (fabsf(mat4_to_scale(rv3d->twmat)) < 1e-7f)
1686                 return 0;
1687
1688         rect.xmin = mval[0] - hotspot;
1689         rect.xmax = mval[0] + hotspot;
1690         rect.ymin = mval[1] - hotspot;
1691         rect.ymax = mval[1] + hotspot;
1692
1693         selrect = rect;
1694
1695         view3d_winmatrix_set(ar, v3d, &rect);
1696         mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
1697
1698         if (do_passes)
1699                 GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
1700         else
1701                 GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_ALL, 0);
1702
1703         /* do the drawing */
1704         if (v3d->twtype & V3D_MANIP_ROTATE) {
1705                 if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
1706                 else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel);
1707         }
1708         if (v3d->twtype & V3D_MANIP_SCALE)
1709                 draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
1710         if (v3d->twtype & V3D_MANIP_TRANSLATE)
1711                 draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
1712
1713         hits = GPU_select_end();
1714
1715         if (do_passes) {
1716                 GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
1717
1718                 /* do the drawing */
1719                 if (v3d->twtype & V3D_MANIP_ROTATE) {
1720                         if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
1721                         else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel);
1722                 }
1723                 if (v3d->twtype & V3D_MANIP_SCALE)
1724                         draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
1725                 if (v3d->twtype & V3D_MANIP_TRANSLATE)
1726                         draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
1727
1728                 GPU_select_end();
1729         }
1730
1731         view3d_winmatrix_set(ar, v3d, NULL);
1732         mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
1733
1734         if (hits == 1) return buffer[3];
1735         else if (hits > 1) {
1736                 GLuint val, dep, mindep = 0, mindeprot = 0, minval = 0, minvalrot = 0;
1737                 int a;
1738
1739                 /* we compare the hits in buffer, but value centers highest */
1740                 /* we also store the rotation hits separate (because of arcs) and return hits on other widgets if there are */
1741
1742                 for (a = 0; a < hits; a++) {
1743                         dep = buffer[4 * a + 1];
1744                         val = buffer[4 * a + 3];
1745
1746                         if (val == MAN_TRANS_C) {
1747                                 return MAN_TRANS_C;
1748                         }
1749                         else if (val == MAN_SCALE_C) {
1750                                 return MAN_SCALE_C;
1751                         }
1752                         else {
1753                                 if (val & MAN_ROT_C) {
1754                                         if (minvalrot == 0 || dep < mindeprot) {
1755                                                 mindeprot = dep;
1756                                                 minvalrot = val;
1757                                         }
1758                                 }
1759                                 else {
1760                                         if (minval == 0 || dep < mindep) {
1761                                                 mindep = dep;
1762                                                 minval = val;
1763                                         }
1764                                 }
1765                         }
1766                 }
1767
1768                 if (minval)
1769                         return minval;
1770                 else
1771                         return minvalrot;
1772         }
1773         return 0;
1774 }
1775
1776
1777 /* return 0; nothing happened */
1778 int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
1779 {
1780         ScrArea *sa = CTX_wm_area(C);
1781         View3D *v3d = sa->spacedata.first;
1782         ARegion *ar = CTX_wm_region(C);
1783         int constraint_axis[3] = {0, 0, 0};
1784         int val;
1785         int shift = event->shift;
1786
1787         if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0;
1788         if (!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0;
1789
1790         /* Force orientation */
1791         RNA_enum_set(op->ptr, "constraint_orientation", v3d->twmode);
1792
1793         // find the hotspots first test narrow hotspot
1794         val = manipulator_selectbuf(sa, ar, event->mval, 0.5f * (float)U.tw_hotspot);
1795         if (val) {
1796
1797                 // drawflags still global, for drawing call above
1798                 drawflags = manipulator_selectbuf(sa, ar, event->mval, 0.2f * (float)U.tw_hotspot);
1799                 if (drawflags == 0) drawflags = val;
1800
1801                 if (drawflags & MAN_TRANS_C) {
1802                         switch (drawflags) {
1803                                 case MAN_TRANS_C:
1804                                         break;
1805                                 case MAN_TRANS_X:
1806                                         if (shift) {
1807                                                 constraint_axis[1] = 1;
1808                                                 constraint_axis[2] = 1;
1809                                         }
1810                                         else
1811                                                 constraint_axis[0] = 1;
1812                                         break;
1813                                 case MAN_TRANS_Y:
1814                                         if (shift) {
1815                                                 constraint_axis[0] = 1;
1816                                                 constraint_axis[2] = 1;
1817                                         }
1818                                         else
1819                                                 constraint_axis[1] = 1;
1820                                         break;
1821                                 case MAN_TRANS_Z:
1822                                         if (shift) {
1823                                                 constraint_axis[0] = 1;
1824                                                 constraint_axis[1] = 1;
1825                                         }
1826                                         else
1827                                                 constraint_axis[2] = 1;
1828                                         break;
1829                         }
1830                         RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
1831                         WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_DEFAULT, op->ptr);
1832                 }
1833                 else if (drawflags & MAN_SCALE_C) {
1834                         switch (drawflags) {
1835                                 case MAN_SCALE_X:
1836                                         if (shift) {
1837                                                 constraint_axis[1] = 1;
1838                                                 constraint_axis[2] = 1;
1839                                         }
1840                                         else
1841                                                 constraint_axis[0] = 1;
1842                                         break;
1843                                 case MAN_SCALE_Y:
1844                                         if (shift) {
1845                                                 constraint_axis[0] = 1;
1846                                                 constraint_axis[2] = 1;
1847                                         }
1848                                         else
1849                                                 constraint_axis[1] = 1;
1850                                         break;
1851                                 case MAN_SCALE_Z:
1852                                         if (shift) {
1853                                                 constraint_axis[0] = 1;
1854                                                 constraint_axis[1] = 1;
1855                                         }
1856                                         else
1857                                                 constraint_axis[2] = 1;
1858                                         break;
1859                         }
1860                         RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
1861                         WM_operator_name_call(C, "TRANSFORM_OT_resize", WM_OP_INVOKE_DEFAULT, op->ptr);
1862                 }
1863                 else if (drawflags == MAN_ROT_T) { /* trackball need special case, init is different */
1864                         /* Do not pass op->ptr!!! trackball has no "constraint" properties!
1865                          * See [#34621], it's a miracle it did not cause more problems!!! */
1866                         /* However, we need to copy the "release_confirm" property, but only if defined, see T41112. */
1867                         PointerRNA props_ptr;
1868                         PropertyRNA *prop;
1869                         wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_trackball", true);
1870                         WM_operator_properties_create_ptr(&props_ptr, ot);
1871                         if ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && RNA_property_is_set(op->ptr, prop)) {
1872                                 RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop));
1873                         }
1874                         WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
1875                         WM_operator_properties_free(&props_ptr);
1876                 }
1877                 else if (drawflags & MAN_ROT_C) {
1878                         switch (drawflags) {
1879                                 case MAN_ROT_X:
1880                                         constraint_axis[0] = 1;
1881                                         break;
1882                                 case MAN_ROT_Y:
1883                                         constraint_axis[1] = 1;
1884                                         break;
1885                                 case MAN_ROT_Z:
1886                                         constraint_axis[2] = 1;
1887                                         break;
1888                         }
1889                         RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
1890                         WM_operator_name_call(C, "TRANSFORM_OT_rotate", WM_OP_INVOKE_DEFAULT, op->ptr);
1891                 }
1892         }
1893         /* after transform, restore drawflags */
1894         drawflags = 0xFFFF;
1895
1896         return val;
1897 }
1898