54fb567b8a27f767b46aebea3739573d6fd1ef7d
[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_tessmesh.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 = BMEdit_FromObject(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 = (float)cos(theta);
723         sin_theta = (float)sin(theta);
724
725         for (i = nrings - 1; i >= 0; i--) {
726                 theta1 = theta + ring_delta;
727                 cos_theta1 = (float)cos(theta1);
728                 sin_theta1 = (float)sin(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 = (float)cos(phi);
770                                 sin_phi = (float)sin(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 axis_sort_v3(const float axis_values[3], int r_axis_order[3])
845 {
846         float v[3];
847         copy_v3_v3(v, axis_values);
848
849 #define SWAP_AXIS(a, b) { \
850         SWAP(float, v[a],            v[b]); \
851         SWAP(int,   r_axis_order[a], r_axis_order[b]); \
852 } (void)0
853
854         if (v[0] < v[1]) {
855                 if (v[2] < v[0]) {  SWAP_AXIS(0, 2); }
856         }
857         else {
858                 if (v[1] < v[2]) { SWAP_AXIS(0, 1); }
859                 else { SWAP_AXIS(0, 2); }
860         }
861         if (v[2] < v[1])     { SWAP_AXIS(1, 2); }
862
863 #undef SWAP_AXIS
864 }
865 static void manipulator_axis_order(RegionView3D *rv3d, int r_axis_order[3])
866 {
867         float axis_values[3];
868         float vec[3];
869
870         ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], vec);
871
872         axis_values[0] = -dot_v3v3(rv3d->twmat[0], vec);
873         axis_values[1] = -dot_v3v3(rv3d->twmat[1], vec);
874         axis_values[2] = -dot_v3v3(rv3d->twmat[2], vec);
875
876         axis_sort_v3(axis_values, r_axis_order);
877 }
878
879 /* viewmatrix should have been set OK, also no shademode! */
880 static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int colcode,
881                                          int flagx, int flagy, int flagz, int axis)
882 {
883         switch (axis) {
884                 case 0:
885                         /* axes */
886                         if (flagx) {
887                                 manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
888                                 if (flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X);
889                                 else if (flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X);
890                                 glBegin(GL_LINES);
891                                 glVertex3f(0.2f, 0.0f, 0.0f);
892                                 glVertex3f(1.0f, 0.0f, 0.0f);
893                                 glEnd();
894                         }
895                         break;
896                 case 1:
897                         if (flagy) {
898                                 if (flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y);
899                                 else if (flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y);
900                                 manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
901                                 glBegin(GL_LINES);
902                                 glVertex3f(0.0f, 0.2f, 0.0f);
903                                 glVertex3f(0.0f, 1.0f, 0.0f);
904                                 glEnd();
905                         }
906                         break;
907                 case 2:
908                         if (flagz) {
909                                 if (flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z);
910                                 else if (flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z);
911                                 manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
912                                 glBegin(GL_LINES);
913                                 glVertex3f(0.0f, 0.0f, 0.2f);
914                                 glVertex3f(0.0f, 0.0f, 1.0f);
915                                 glEnd();
916                         }
917                         break;
918         }
919 }
920 static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode,
921                                   int flagx, int flagy, int flagz,
922                                   const int axis_order[3])
923 {
924         int i;
925         for (i = 0; i < 3; i++) {
926                 draw_manipulator_axes_single(v3d, rv3d, colcode, flagx, flagy, flagz, axis_order[i]);
927         }
928 }
929
930 static void preOrthoFront(int ortho, float twmat[4][4], int axis)
931 {
932         if (ortho == 0) {
933                 float omat[4][4];
934                 copy_m4_m4(omat, twmat);
935                 orthogonalize_m4(omat, axis);
936                 glPushMatrix();
937                 glMultMatrixf(omat);
938                 glFrontFace(is_negative_m4(omat) ? GL_CW : GL_CCW);
939         }
940 }
941
942 static void postOrtho(int ortho)
943 {
944         if (ortho == 0) {
945                 glPopMatrix();
946         }
947 }
948
949 static void draw_manipulator_rotate(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo)
950 {
951         GLUquadricObj *qobj;
952         double plane[4];
953         float matt[4][4];
954         float size, unitmat[4][4];
955         float cywid = 0.33f * 0.01f * (float)U.tw_handlesize;
956         float cusize = cywid * 0.65f;
957         int arcs = (G.debug_value != 2);
958         int colcode;
959         int ortho;
960
961         if (moving) colcode = MAN_MOVECOL;
962         else colcode = MAN_RGB;
963
964         /* when called while moving in mixed mode, do not draw when... */
965         if ((drawflags & MAN_ROT_C) == 0) return;
966
967         /* Init stuff */
968         glDisable(GL_DEPTH_TEST);
969         unit_m4(unitmat);
970
971         qobj = gluNewQuadric();
972         gluQuadricDrawStyle(qobj, GLU_FILL);
973
974         /* prepare for screen aligned draw */
975         size = len_v3(rv3d->twmat[0]);
976         glPushMatrix();
977         glTranslatef(rv3d->twmat[3][0], rv3d->twmat[3][1], rv3d->twmat[3][2]);
978
979         if (arcs) {
980                 /* clipplane makes nice handles, calc here because of multmatrix but with translate! */
981                 copy_v3db_v3fl(plane, rv3d->viewinv[2]);
982                 plane[3] = -0.02f * size; // clip just a bit more
983                 glClipPlane(GL_CLIP_PLANE0, plane);
984         }
985         /* sets view screen aligned */
986         glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]);
987
988         /* Screen aligned help circle */
989         if (arcs) {
990                 if ((G.f & G_PICKSEL) == 0) {
991                         UI_ThemeColorShade(TH_BACK, -30);
992                         drawcircball(GL_LINE_LOOP, unitmat[3], size, unitmat);
993                 }
994         }
995
996         /* Screen aligned trackball rot circle */
997         if (drawflags & MAN_ROT_T) {
998                 if (G.f & G_PICKSEL) glLoadName(MAN_ROT_T);
999
1000                 UI_ThemeColor(TH_TRANSFORM);
1001                 drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
1002         }
1003
1004         /* Screen aligned view rot circle */
1005         if (drawflags & MAN_ROT_V) {
1006                 if (G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
1007                 UI_ThemeColor(TH_TRANSFORM);
1008                 drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat);
1009
1010                 if (moving) {
1011                         float vec[3];
1012                         vec[0] = 0; // XXX (float)(t->imval[0] - t->center2d[0]);
1013                         vec[1] = 0; // XXX (float)(t->imval[1] - t->center2d[1]);
1014                         vec[2] = 0.0f;
1015                         normalize_v3(vec);
1016                         mul_v3_fl(vec, 1.2f * size);
1017                         glBegin(GL_LINES);
1018                         glVertex3f(0.0f, 0.0f, 0.0f);
1019                         glVertex3fv(vec);
1020                         glEnd();
1021                 }
1022         }
1023         glPopMatrix();
1024
1025
1026         ortho = is_orthogonal_m4(rv3d->twmat);
1027         
1028         /* apply the transform delta */
1029         if (moving) {
1030                 copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
1031                 // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
1032                 if (ortho) {
1033                         glMultMatrixf(matt);
1034                         glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW);
1035                 }
1036         }
1037         else {
1038                 if (ortho) {
1039                         glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW);
1040                         glMultMatrixf(rv3d->twmat);
1041                 }
1042         }
1043
1044         /* axes */
1045         if (arcs == 0) {
1046                 if (!(G.f & G_PICKSEL)) {
1047                         if ((combo & V3D_MANIP_SCALE) == 0) {
1048                                 /* axis */
1049                                 if ((drawflags & MAN_ROT_X) || (moving && (drawflags & MAN_ROT_Z))) {
1050                                         preOrthoFront(ortho, rv3d->twmat, 2);
1051                                         manipulator_setcolor(v3d, 'X', colcode, 255);
1052                                         glBegin(GL_LINES);
1053                                         glVertex3f(0.2f, 0.0f, 0.0f);
1054                                         glVertex3f(1.0f, 0.0f, 0.0f);
1055                                         glEnd();
1056                                         postOrtho(ortho);
1057                                 }
1058                                 if ((drawflags & MAN_ROT_Y) || (moving && (drawflags & MAN_ROT_X))) {
1059                                         preOrthoFront(ortho, rv3d->twmat, 0);
1060                                         manipulator_setcolor(v3d, 'Y', colcode, 255);
1061                                         glBegin(GL_LINES);
1062                                         glVertex3f(0.0f, 0.2f, 0.0f);
1063                                         glVertex3f(0.0f, 1.0f, 0.0f);
1064                                         glEnd();
1065                                         postOrtho(ortho);
1066                                 }
1067                                 if ((drawflags & MAN_ROT_Z) || (moving && (drawflags & MAN_ROT_Y))) {
1068                                         preOrthoFront(ortho, rv3d->twmat, 1);
1069                                         manipulator_setcolor(v3d, 'Z', colcode, 255);
1070                                         glBegin(GL_LINES);
1071                                         glVertex3f(0.0f, 0.0f, 0.2f);
1072                                         glVertex3f(0.0f, 0.0f, 1.0f);
1073                                         glEnd();
1074                                         postOrtho(ortho);
1075                                 }
1076                         }
1077                 }
1078         }
1079
1080         if (arcs == 0 && moving) {
1081
1082                 /* Z circle */
1083                 if (drawflags & MAN_ROT_Z) {
1084                         preOrthoFront(ortho, matt, 2);
1085                         if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
1086                         manipulator_setcolor(v3d, 'Z', colcode, 255);
1087                         drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
1088                         postOrtho(ortho);
1089                 }
1090                 /* X circle */
1091                 if (drawflags & MAN_ROT_X) {
1092                         preOrthoFront(ortho, matt, 0);
1093                         if (G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
1094                         glRotatef(90.0, 0.0, 1.0, 0.0);
1095                         manipulator_setcolor(v3d, 'X', colcode, 255);
1096                         drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
1097                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1098                         postOrtho(ortho);
1099                 }
1100                 /* Y circle */
1101                 if (drawflags & MAN_ROT_Y) {
1102                         preOrthoFront(ortho, matt, 1);
1103                         if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
1104                         glRotatef(-90.0, 1.0, 0.0, 0.0);
1105                         manipulator_setcolor(v3d, 'Y', colcode, 255);
1106                         drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
1107                         glRotatef(90.0, 1.0, 0.0, 0.0);
1108                         postOrtho(ortho);
1109                 }
1110
1111                 if (arcs) glDisable(GL_CLIP_PLANE0);
1112         }
1113         // donut arcs
1114         if (arcs) {
1115                 glEnable(GL_CLIP_PLANE0);
1116
1117                 /* Z circle */
1118                 if (drawflags & MAN_ROT_Z) {
1119                         preOrthoFront(ortho, rv3d->twmat, 2);
1120                         if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
1121                         manipulator_setcolor(v3d, 'Z', colcode, 255);
1122                         partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
1123                         postOrtho(ortho);
1124                 }
1125                 /* X circle */
1126                 if (drawflags & MAN_ROT_X) {
1127                         preOrthoFront(ortho, rv3d->twmat, 0);
1128                         if (G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
1129                         glRotatef(90.0, 0.0, 1.0, 0.0);
1130                         manipulator_setcolor(v3d, 'X', colcode, 255);
1131                         partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
1132                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1133                         postOrtho(ortho);
1134                 }
1135                 /* Y circle */
1136                 if (drawflags & MAN_ROT_Y) {
1137                         preOrthoFront(ortho, rv3d->twmat, 1);
1138                         if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
1139                         glRotatef(-90.0, 1.0, 0.0, 0.0);
1140                         manipulator_setcolor(v3d, 'Y', colcode, 255);
1141                         partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
1142                         glRotatef(90.0, 1.0, 0.0, 0.0);
1143                         postOrtho(ortho);
1144                 }
1145
1146                 glDisable(GL_CLIP_PLANE0);
1147         }
1148
1149         if (arcs == 0) {
1150
1151                 /* Z handle on X axis */
1152                 if (drawflags & MAN_ROT_Z) {
1153                         preOrthoFront(ortho, rv3d->twmat, 2);
1154                         glPushMatrix();
1155                         if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
1156                         manipulator_setcolor(v3d, 'Z', colcode, 255);
1157
1158                         partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
1159
1160                         glPopMatrix();
1161                         postOrtho(ortho);
1162                 }
1163
1164                 /* Y handle on X axis */
1165                 if (drawflags & MAN_ROT_Y) {
1166                         preOrthoFront(ortho, rv3d->twmat, 1);
1167                         glPushMatrix();
1168                         if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
1169                         manipulator_setcolor(v3d, 'Y', colcode, 255);
1170
1171                         glRotatef(90.0, 1.0, 0.0, 0.0);
1172                         glRotatef(90.0, 0.0, 0.0, 1.0);
1173                         partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
1174
1175                         glPopMatrix();
1176                         postOrtho(ortho);
1177                 }
1178
1179                 /* X handle on Z axis */
1180                 if (drawflags & MAN_ROT_X) {
1181                         preOrthoFront(ortho, rv3d->twmat, 0);
1182                         glPushMatrix();
1183                         if (G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
1184                         manipulator_setcolor(v3d, 'X', colcode, 255);
1185
1186                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1187                         glRotatef(90.0, 0.0, 0.0, 1.0);
1188                         partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
1189
1190                         glPopMatrix();
1191                         postOrtho(ortho);
1192                 }
1193
1194         }
1195
1196         /* restore */
1197         glLoadMatrixf(rv3d->viewmat);
1198         gluDeleteQuadric(qobj);
1199         if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1200
1201 }
1202
1203 static void drawsolidcube(float size)
1204 {
1205         static float cube[8][3] = {
1206                 {-1.0, -1.0, -1.0},
1207                 {-1.0, -1.0,  1.0},
1208                 {-1.0,  1.0,  1.0},
1209                 {-1.0,  1.0, -1.0},
1210                 { 1.0, -1.0, -1.0},
1211                 { 1.0, -1.0,  1.0},
1212                 { 1.0,  1.0,  1.0},
1213                 { 1.0,  1.0, -1.0},
1214         };
1215         float n[3] = {0.0f};
1216
1217         glPushMatrix();
1218         glScalef(size, size, size);
1219
1220         glBegin(GL_QUADS);
1221         n[0] = -1.0;
1222         glNormal3fv(n);
1223         glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
1224         n[0] = 0;
1225         glEnd();
1226
1227         glBegin(GL_QUADS);
1228         n[1] = -1.0;
1229         glNormal3fv(n);
1230         glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]);
1231         n[1] = 0;
1232         glEnd();
1233
1234         glBegin(GL_QUADS);
1235         n[0] = 1.0;
1236         glNormal3fv(n);
1237         glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]);
1238         n[0] = 0;
1239         glEnd();
1240
1241         glBegin(GL_QUADS);
1242         n[1] = 1.0;
1243         glNormal3fv(n);
1244         glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]);
1245         n[1] = 0;
1246         glEnd();
1247
1248         glBegin(GL_QUADS);
1249         n[2] = 1.0;
1250         glNormal3fv(n);
1251         glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]);
1252         n[2] = 0;
1253         glEnd();
1254
1255         glBegin(GL_QUADS);
1256         n[2] = -1.0;
1257         glNormal3fv(n);
1258         glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]);
1259         glEnd();
1260
1261         glPopMatrix();
1262 }
1263
1264
1265 static void draw_manipulator_scale(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo, int colcode)
1266 {
1267         float cywid = 0.25f * 0.01f * (float)U.tw_handlesize;
1268         float cusize = cywid * 0.75f, dz;
1269         int axis_order[3] = {2, 0, 1};
1270         int i;
1271
1272         /* when called while moving in mixed mode, do not draw when... */
1273         if ((drawflags & MAN_SCALE_C) == 0) return;
1274
1275         manipulator_axis_order(rv3d, axis_order);
1276
1277         glDisable(GL_DEPTH_TEST);
1278
1279         /* not in combo mode */
1280         if ((combo & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) == 0) {
1281                 float size, unitmat[4][4];
1282                 int shift = 0; // XXX
1283
1284                 /* center circle, do not add to selection when shift is pressed (planar constraint)  */
1285                 if ((G.f & G_PICKSEL) && shift == 0) glLoadName(MAN_SCALE_C);
1286
1287                 manipulator_setcolor(v3d, 'C', colcode, 255);
1288                 glPushMatrix();
1289                 size = screen_aligned(rv3d, rv3d->twmat);
1290                 unit_m4(unitmat);
1291                 drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
1292                 glPopMatrix();
1293
1294                 dz = 1.0;
1295         }
1296         else dz = 1.0f - 4.0f * cusize;
1297
1298         if (moving) {
1299                 float matt[4][4];
1300
1301                 copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
1302                 // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
1303                 glMultMatrixf(matt);
1304                 glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW);
1305         }
1306         else {
1307                 glMultMatrixf(rv3d->twmat);
1308                 glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW);
1309         }
1310
1311         /* axis */
1312
1313         /* in combo mode, this is always drawn as first type */
1314         draw_manipulator_axes(v3d, rv3d, colcode,
1315                               drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z,
1316                               axis_order);
1317
1318
1319         for (i = 0; i < 3; i++) {
1320                 switch (axis_order[i]) {
1321                         case 0: /* X cube */
1322                                 if (drawflags & MAN_SCALE_X) {
1323                                         glTranslatef(dz, 0.0, 0.0);
1324                                         if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_X);
1325                                         manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
1326                                         drawsolidcube(cusize);
1327                                         glTranslatef(-dz, 0.0, 0.0);
1328                                 }
1329                                 break;
1330                         case 1: /* Y cube */
1331                                 if (drawflags & MAN_SCALE_Y) {
1332                                         glTranslatef(0.0, dz, 0.0);
1333                                         if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y);
1334                                         manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
1335                                         drawsolidcube(cusize);
1336                                         glTranslatef(0.0, -dz, 0.0);
1337                                 }
1338                                 break;
1339                         case 2: /* Z cube */
1340                                 if (drawflags & MAN_SCALE_Z) {
1341                                         glTranslatef(0.0, 0.0, dz);
1342                                         if (G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z);
1343                                         manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
1344                                         drawsolidcube(cusize);
1345                                         glTranslatef(0.0, 0.0, -dz);
1346                                 }
1347                                 break;
1348                 }
1349         }
1350
1351         /* if shiftkey, center point as last, for selectbuffer order */
1352         if (G.f & G_PICKSEL) {
1353                 int shift = 0; // XXX
1354
1355                 if (shift) {
1356                         glTranslatef(0.0, -dz, 0.0);
1357                         glLoadName(MAN_SCALE_C);
1358                         glBegin(GL_POINTS);
1359                         glVertex3f(0.0, 0.0, 0.0);
1360                         glEnd();
1361                 }
1362         }
1363
1364         /* restore */
1365         glLoadMatrixf(rv3d->viewmat);
1366
1367         if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1368         glFrontFace(GL_CCW);
1369 }
1370
1371
1372 static void draw_cone(GLUquadricObj *qobj, float len, float width)
1373 {
1374         glTranslatef(0.0, 0.0, -0.5f * len);
1375         gluCylinder(qobj, width, 0.0, len, 8, 1);
1376         gluQuadricOrientation(qobj, GLU_INSIDE);
1377         gluDisk(qobj, 0.0, width, 8, 1);
1378         gluQuadricOrientation(qobj, GLU_OUTSIDE);
1379         glTranslatef(0.0, 0.0, 0.5f * len);
1380 }
1381
1382 static void draw_cylinder(GLUquadricObj *qobj, float len, float width)
1383 {
1384
1385         width *= 0.8f;   // just for beauty
1386
1387         glTranslatef(0.0, 0.0, -0.5f * len);
1388         gluCylinder(qobj, width, width, len, 8, 1);
1389         gluQuadricOrientation(qobj, GLU_INSIDE);
1390         gluDisk(qobj, 0.0, width, 8, 1);
1391         gluQuadricOrientation(qobj, GLU_OUTSIDE);
1392         glTranslatef(0.0, 0.0, len);
1393         gluDisk(qobj, 0.0, width, 8, 1);
1394         glTranslatef(0.0, 0.0, -0.5f * len);
1395 }
1396
1397
1398 static void draw_manipulator_translate(View3D *v3d, RegionView3D *rv3d, int UNUSED(moving), int drawflags, int combo, int colcode)
1399 {
1400         GLUquadricObj *qobj;
1401         float cylen = 0.01f * (float)U.tw_handlesize;
1402         float cywid = 0.25f * cylen, dz, size;
1403         float unitmat[4][4];
1404         int shift = 0; // XXX
1405         int axis_order[3] = {0, 1, 2};
1406         int i;
1407
1408         /* when called while moving in mixed mode, do not draw when... */
1409         if ((drawflags & MAN_TRANS_C) == 0) return;
1410
1411         manipulator_axis_order(rv3d, axis_order);
1412
1413         // XXX if (moving) glTranslatef(t->vec[0], t->vec[1], t->vec[2]);
1414         glDisable(GL_DEPTH_TEST);
1415
1416         /* center circle, do not add to selection when shift is pressed (planar constraint) */
1417         if ((G.f & G_PICKSEL) && shift == 0) glLoadName(MAN_TRANS_C);
1418
1419         manipulator_setcolor(v3d, 'C', colcode, 255);
1420         glPushMatrix();
1421         size = screen_aligned(rv3d, rv3d->twmat);
1422         unit_m4(unitmat);
1423         drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
1424         glPopMatrix();
1425
1426         /* and now apply matrix, we move to local matrix drawing */
1427         glMultMatrixf(rv3d->twmat);
1428
1429         /* axis */
1430         glLoadName(-1);
1431
1432         // translate drawn as last, only axis when no combo with scale, or for ghosting
1433         if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) {
1434                 draw_manipulator_axes(v3d, rv3d, colcode,
1435                                       drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z,
1436                                       axis_order);
1437         }
1438
1439
1440         /* offset in combo mode, for rotate a bit more */
1441         if (combo & (V3D_MANIP_ROTATE)) dz = 1.0f + 2.0f * cylen;
1442         else if (combo & (V3D_MANIP_SCALE)) dz = 1.0f + 0.5f * cylen;
1443         else dz = 1.0f;
1444
1445         qobj = gluNewQuadric();
1446         gluQuadricDrawStyle(qobj, GLU_FILL);
1447
1448         for (i = 0; i < 3; i++) {
1449                 switch (axis_order[i]) {
1450                         case 0: /* Z Cone */
1451                                 if (drawflags & MAN_TRANS_Z) {
1452                                         glTranslatef(0.0, 0.0, dz);
1453                                         if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_Z);
1454                                         manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2]));
1455                                         draw_cone(qobj, cylen, cywid);
1456                                         glTranslatef(0.0, 0.0, -dz);
1457                                 }
1458                                 break;
1459                         case 1: /* X Cone */
1460                                 if (drawflags & MAN_TRANS_X) {
1461                                         glTranslatef(dz, 0.0, 0.0);
1462                                         if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_X);
1463                                         glRotatef(90.0, 0.0, 1.0, 0.0);
1464                                         manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0]));
1465                                         draw_cone(qobj, cylen, cywid);
1466                                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1467                                         glTranslatef(-dz, 0.0, 0.0);
1468                                 }
1469                                 break;
1470                         case 2: /* Y Cone */
1471                                 if (drawflags & MAN_TRANS_Y) {
1472                                         glTranslatef(0.0, dz, 0.0);
1473                                         if (G.f & G_PICKSEL) glLoadName(MAN_TRANS_Y);
1474                                         glRotatef(-90.0, 1.0, 0.0, 0.0);
1475                                         manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1]));
1476                                         draw_cone(qobj, cylen, cywid);
1477                                         glRotatef(90.0, 1.0, 0.0, 0.0);
1478                                         glTranslatef(0.0, -dz, 0.0);
1479                                 }
1480                                 break;
1481                 }
1482         }
1483
1484         gluDeleteQuadric(qobj);
1485         glLoadMatrixf(rv3d->viewmat);
1486
1487         if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1488
1489 }
1490
1491 static void draw_manipulator_rotate_cyl(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo, int colcode)
1492 {
1493         GLUquadricObj *qobj;
1494         float size;
1495         float cylen = 0.01f * (float)U.tw_handlesize;
1496         float cywid = 0.25f * cylen;
1497         int axis_order[3] = {2, 0, 1};
1498         int i;
1499         /* when called while moving in mixed mode, do not draw when... */
1500         if ((drawflags & MAN_ROT_C) == 0) return;
1501
1502         manipulator_axis_order(rv3d, axis_order);
1503
1504         /* prepare for screen aligned draw */
1505         glPushMatrix();
1506         size = screen_aligned(rv3d, rv3d->twmat);
1507
1508         glDisable(GL_DEPTH_TEST);
1509
1510         qobj = gluNewQuadric();
1511
1512         /* Screen aligned view rot circle */
1513         if (drawflags & MAN_ROT_V) {
1514                 float unitmat[4][4] = MAT4_UNITY;
1515
1516                 if (G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
1517                 UI_ThemeColor(TH_TRANSFORM);
1518                 drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat);
1519
1520                 if (moving) {
1521                         float vec[3];
1522                         vec[0] = 0; // XXX (float)(t->imval[0] - t->center2d[0]);
1523                         vec[1] = 0; // XXX (float)(t->imval[1] - t->center2d[1]);
1524                         vec[2] = 0.0f;
1525                         normalize_v3(vec);
1526                         mul_v3_fl(vec, 1.2f * size);
1527                         glBegin(GL_LINES);
1528                         glVertex3f(0.0, 0.0, 0.0);
1529                         glVertex3fv(vec);
1530                         glEnd();
1531                 }
1532         }
1533         glPopMatrix();
1534
1535         /* apply the transform delta */
1536         if (moving) {
1537                 float matt[4][4];
1538                 copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
1539                 // XXX      if (t->flag & T_USES_MANIPULATOR) {
1540                 // XXX          mul_m4_m3m4(matt, t->mat, rv3d->twmat);
1541                 // XXX }
1542                 glMultMatrixf(matt);
1543         }
1544         else {
1545                 glMultMatrixf(rv3d->twmat);
1546         }
1547
1548         glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW);
1549
1550         /* axis */
1551         if ((G.f & G_PICKSEL) == 0) {
1552
1553                 // only draw axis when combo didn't draw scale axes
1554                 if ((combo & V3D_MANIP_SCALE) == 0) {
1555                         draw_manipulator_axes(v3d, rv3d, colcode,
1556                                               drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z,
1557                                               axis_order);
1558                 }
1559
1560                 /* only has to be set when not in picking */
1561                 gluQuadricDrawStyle(qobj, GLU_FILL);
1562         }
1563
1564         for (i = 0; i < 3; i++) {
1565                 switch (axis_order[i]) {
1566                         case 0: /* X cylinder */
1567                                 if (drawflags & MAN_ROT_X) {
1568                                         glTranslatef(1.0, 0.0, 0.0);
1569                                         if (G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
1570                                         glRotatef(90.0, 0.0, 1.0, 0.0);
1571                                         manipulator_setcolor(v3d, 'X', colcode, 255);
1572                                         draw_cylinder(qobj, cylen, cywid);
1573                                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1574                                         glTranslatef(-1.0, 0.0, 0.0);
1575                                 }
1576                                 break;
1577                         case 1: /* Y cylinder */
1578                                 if (drawflags & MAN_ROT_Y) {
1579                                         glTranslatef(0.0, 1.0, 0.0);
1580                                         if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
1581                                         glRotatef(-90.0, 1.0, 0.0, 0.0);
1582                                         manipulator_setcolor(v3d, 'Y', colcode, 255);
1583                                         draw_cylinder(qobj, cylen, cywid);
1584                                         glRotatef(90.0, 1.0, 0.0, 0.0);
1585                                         glTranslatef(0.0, -1.0, 0.0);
1586                                 }
1587                                 break;
1588                         case 2: /* Z cylinder */
1589                                 if (drawflags & MAN_ROT_Z) {
1590                                         glTranslatef(0.0, 0.0, 1.0);
1591                                         if (G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
1592                                         manipulator_setcolor(v3d, 'Z', colcode, 255);
1593                                         draw_cylinder(qobj, cylen, cywid);
1594                                         glTranslatef(0.0, 0.0, -1.0);
1595                                 }
1596                                 break;
1597                 }
1598         }
1599
1600         /* restore */
1601
1602         gluDeleteQuadric(qobj);
1603         glLoadMatrixf(rv3d->viewmat);
1604
1605         if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
1606
1607 }
1608
1609
1610 /* ********************************************* */
1611
1612 /* main call, does calc centers & orientation too */
1613 /* uses global G.moving */
1614 static int drawflags = 0xFFFF;       // only for the calls below, belongs in scene...?
1615
1616 void BIF_draw_manipulator(const bContext *C)
1617 {
1618         ScrArea *sa = CTX_wm_area(C);
1619         ARegion *ar = CTX_wm_region(C);
1620         Scene *scene = CTX_data_scene(C);
1621         View3D *v3d = sa->spacedata.first;
1622         RegionView3D *rv3d = ar->regiondata;
1623         int totsel;
1624
1625         if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return;
1626 //      if (G.moving && (G.moving & G_TRANSFORM_MANIP)==0) return;
1627
1628 //      if (G.moving==0) {
1629         {
1630                 v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
1631
1632                 totsel = calc_manipulator_stats(C);
1633                 if (totsel == 0) return;
1634
1635                 v3d->twflag |= V3D_DRAW_MANIPULATOR;
1636
1637                 /* now we can define center */
1638                 switch (v3d->around) {
1639                         case V3D_CENTER:
1640                         case V3D_ACTIVE:
1641                                 rv3d->twmat[3][0] = (scene->twmin[0] + scene->twmax[0]) / 2.0f;
1642                                 rv3d->twmat[3][1] = (scene->twmin[1] + scene->twmax[1]) / 2.0f;
1643                                 rv3d->twmat[3][2] = (scene->twmin[2] + scene->twmax[2]) / 2.0f;
1644                                 if (v3d->around == V3D_ACTIVE && scene->obedit == NULL) {
1645                                         Object *ob = OBACT;
1646                                         if (ob && !(ob->mode & OB_MODE_POSE))
1647                                                 copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
1648                                 }
1649                                 break;
1650                         case V3D_LOCAL:
1651                         case V3D_CENTROID:
1652                                 copy_v3_v3(rv3d->twmat[3], scene->twcent);
1653                                 break;
1654                         case V3D_CURSOR:
1655                                 copy_v3_v3(rv3d->twmat[3], give_cursor(scene, v3d));
1656                                 break;
1657                 }
1658
1659                 mul_mat3_m4_fl(rv3d->twmat, ED_view3d_pixel_size(rv3d, rv3d->twmat[3]) * U.tw_size * 5.0f);
1660         }
1661
1662         test_manipulator_axis(C);
1663         drawflags = rv3d->twdrawflag;    /* set in calc_manipulator_stats */
1664
1665         if (v3d->twflag & V3D_DRAW_MANIPULATOR) {
1666
1667                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1668                 glEnable(GL_BLEND);
1669                 if (v3d->twtype & V3D_MANIP_ROTATE) {
1670
1671                         if (G.debug_value == 3) {
1672                                 if (G.moving) draw_manipulator_rotate_cyl(v3d, rv3d, 1, drawflags, v3d->twtype, MAN_MOVECOL);
1673                                 else draw_manipulator_rotate_cyl(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB);
1674                         }
1675                         else
1676                                 draw_manipulator_rotate(v3d, rv3d, 0 /* G.moving*/, drawflags, v3d->twtype);
1677                 }
1678                 if (v3d->twtype & V3D_MANIP_SCALE) {
1679                         draw_manipulator_scale(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB);
1680                 }
1681                 if (v3d->twtype & V3D_MANIP_TRANSLATE) {
1682                         draw_manipulator_translate(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB);
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         extern void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect); // XXX check a bit later on this... (ton)
1697
1698         G.f |= G_PICKSEL;
1699
1700         rect.xmin = mval[0] - hotspot;
1701         rect.xmax = mval[0] + hotspot;
1702         rect.ymin = mval[1] - hotspot;
1703         rect.ymax = mval[1] + hotspot;
1704
1705         setwinmatrixview3d(ar, v3d, &rect);
1706         mult_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
1707
1708         glSelectBuffer(64, buffer);
1709         glRenderMode(GL_SELECT);
1710         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1711         glPushName(-2);
1712
1713         /* do the drawing */
1714         if (v3d->twtype & V3D_MANIP_ROTATE) {
1715                 if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, 0, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB);
1716                 else draw_manipulator_rotate(v3d, rv3d, 0, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype);
1717         }
1718         if (v3d->twtype & V3D_MANIP_SCALE)
1719                 draw_manipulator_scale(v3d, rv3d, 0, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB);
1720         if (v3d->twtype & V3D_MANIP_TRANSLATE)
1721                 draw_manipulator_translate(v3d, rv3d, 0, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB);
1722
1723         glPopName();
1724         hits = glRenderMode(GL_RENDER);
1725
1726         G.f &= ~G_PICKSEL;
1727         setwinmatrixview3d(ar, v3d, NULL);
1728         mult_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
1729
1730         if (hits == 1) return buffer[3];
1731         else if (hits > 1) {
1732                 GLuint val, dep, mindep = 0, mindeprot = 0, minval = 0, minvalrot = 0;
1733                 int a;
1734
1735                 /* we compare the hits in buffer, but value centers highest */
1736                 /* we also store the rotation hits separate (because of arcs) and return hits on other widgets if there are */
1737
1738                 for (a = 0; a < hits; a++) {
1739                         dep = buffer[4 * a + 1];
1740                         val = buffer[4 * a + 3];
1741
1742                         if (val == MAN_TRANS_C) return MAN_TRANS_C;
1743                         else if (val == MAN_SCALE_C) return MAN_SCALE_C;
1744                         else {
1745                                 if (val & MAN_ROT_C) {
1746                                         if (minvalrot == 0 || dep < mindeprot) {
1747                                                 mindeprot = dep;
1748                                                 minvalrot = val;
1749                                         }
1750                                 }
1751                                 else {
1752                                         if (minval == 0 || dep < mindep) {
1753                                                 mindep = dep;
1754                                                 minval = val;
1755                                         }
1756                                 }
1757                         }
1758                 }
1759
1760                 if (minval)
1761                         return minval;
1762                 else
1763                         return minvalrot;
1764         }
1765         return 0;
1766 }
1767
1768
1769 /* return 0; nothing happened */
1770 int BIF_do_manipulator(bContext *C, struct wmEvent *event, wmOperator *op)
1771 {
1772         ScrArea *sa = CTX_wm_area(C);
1773         View3D *v3d = sa->spacedata.first;
1774         ARegion *ar = CTX_wm_region(C);
1775         int constraint_axis[3] = {0, 0, 0};
1776         int val;
1777         int shift = event->shift;
1778
1779         if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0;
1780         if (!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0;
1781
1782         /* Force orientation */
1783         RNA_enum_set(op->ptr, "constraint_orientation", v3d->twmode);
1784
1785         // find the hotspots first test narrow hotspot
1786         val = manipulator_selectbuf(sa, ar, event->mval, 0.5f * (float)U.tw_hotspot);
1787         if (val) {
1788
1789                 // drawflags still global, for drawing call above
1790                 drawflags = manipulator_selectbuf(sa, ar, event->mval, 0.2f * (float)U.tw_hotspot);
1791                 if (drawflags == 0) drawflags = val;
1792
1793                 if (drawflags & MAN_TRANS_C) {
1794                         switch (drawflags) {
1795                                 case MAN_TRANS_C:
1796                                         break;
1797                                 case MAN_TRANS_X:
1798                                         if (shift) {
1799                                                 constraint_axis[1] = 1;
1800                                                 constraint_axis[2] = 1;
1801                                         }
1802                                         else
1803                                                 constraint_axis[0] = 1;
1804                                         break;
1805                                 case MAN_TRANS_Y:
1806                                         if (shift) {
1807                                                 constraint_axis[0] = 1;
1808                                                 constraint_axis[2] = 1;
1809                                         }
1810                                         else
1811                                                 constraint_axis[1] = 1;
1812                                         break;
1813                                 case MAN_TRANS_Z:
1814                                         if (shift) {
1815                                                 constraint_axis[0] = 1;
1816                                                 constraint_axis[1] = 1;
1817                                         }
1818                                         else
1819                                                 constraint_axis[2] = 1;
1820                                         break;
1821                         }
1822                         RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
1823                         WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_DEFAULT, op->ptr);
1824                         //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_translate", 0), event, op->ptr, NULL, FALSE);
1825                 }
1826                 else if (drawflags & MAN_SCALE_C) {
1827                         switch (drawflags) {
1828                                 case MAN_SCALE_X:
1829                                         if (shift) {
1830                                                 constraint_axis[1] = 1;
1831                                                 constraint_axis[2] = 1;
1832                                         }
1833                                         else
1834                                                 constraint_axis[0] = 1;
1835                                         break;
1836                                 case MAN_SCALE_Y:
1837                                         if (shift) {
1838                                                 constraint_axis[0] = 1;
1839                                                 constraint_axis[2] = 1;
1840                                         }
1841                                         else
1842                                                 constraint_axis[1] = 1;
1843                                         break;
1844                                 case MAN_SCALE_Z:
1845                                         if (shift) {
1846                                                 constraint_axis[0] = 1;
1847                                                 constraint_axis[1] = 1;
1848                                         }
1849                                         else
1850                                                 constraint_axis[2] = 1;
1851                                         break;
1852                         }
1853                         RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
1854                         WM_operator_name_call(C, "TRANSFORM_OT_resize", WM_OP_INVOKE_DEFAULT, op->ptr);
1855                         //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_resize", 0), event, op->ptr, NULL, FALSE);
1856                 }
1857                 else if (drawflags == MAN_ROT_T) { /* trackball need special case, init is different */
1858                         WM_operator_name_call(C, "TRANSFORM_OT_trackball", WM_OP_INVOKE_DEFAULT, op->ptr);
1859                         //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_trackball", 0), event, op->ptr, NULL, FALSE);
1860                 }
1861                 else if (drawflags & MAN_ROT_C) {
1862                         switch (drawflags) {
1863                                 case MAN_ROT_X:
1864                                         constraint_axis[0] = 1;
1865                                         break;
1866                                 case MAN_ROT_Y:
1867                                         constraint_axis[1] = 1;
1868                                         break;
1869                                 case MAN_ROT_Z:
1870                                         constraint_axis[2] = 1;
1871                                         break;
1872                         }
1873                         RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
1874                         WM_operator_name_call(C, "TRANSFORM_OT_rotate", WM_OP_INVOKE_DEFAULT, op->ptr);
1875                         //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_rotate", 0), event, op->ptr, NULL, FALSE);
1876                 }
1877         }
1878         /* after transform, restore drawflags */
1879         drawflags = 0xFFFF;
1880
1881         return val;
1882 }
1883