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