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