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