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