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