- Removed temporal hack that switched manipulator type on G, R, S hotkeys.
[blender.git] / source / blender / src / transform_manipulator.c
1 /**
2 * $Id:
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2005 Blender Foundation
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifndef WIN32
42 #include <unistd.h>
43 #else
44 #include <io.h>
45 #endif
46
47 #include "MEM_guardedalloc.h"
48
49 #include "DNA_armature_types.h"
50 #include "DNA_curve_types.h"
51 #include "DNA_lattice_types.h"
52 #include "DNA_mesh_types.h"
53 #include "DNA_meta_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_screen_types.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_space_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_view3d_types.h"
60
61 #include "BKE_armature.h"
62 #include "BKE_global.h"
63 #include "BKE_lattice.h"
64 #include "BKE_object.h"
65 #include "BKE_utildefines.h"
66
67 #include "BLI_arithb.h"
68 #include "BLI_editVert.h"
69
70 #include "BIF_editarmature.h"
71 #include "BIF_gl.h"
72 #include "BIF_mywindow.h"
73 #include "BIF_resources.h"
74 #include "BIF_screen.h"
75 #include "BIF_space.h"
76 #include "BIF_transform.h"
77
78 #include "BSE_edit.h"
79 #include "BSE_view.h"
80 #include "BDR_drawobject.h"
81
82 #include "blendef.h"
83 #include "transform.h"
84 #include "transform_generics.h"
85
86 /* return codes for select */
87
88 #define MAN_TRANS_X             1
89 #define MAN_TRANS_Y             2
90 #define MAN_TRANS_Z             4
91 #define MAN_TRANS_C             7
92
93 #define MAN_ROT_X               8
94 #define MAN_ROT_Y               16
95 #define MAN_ROT_Z               32
96 #define MAN_ROT_V               64
97 #define MAN_ROT_T               128
98 #define MAN_ROT_C               248
99
100 #define MAN_SCALE_X             256
101 #define MAN_SCALE_Y             512
102 #define MAN_SCALE_Z             1024
103 #define MAN_SCALE_C             1792
104
105
106 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING  */
107 extern TransInfo Trans;
108
109
110 /* transform widget center calc helper for below */
111 static void calc_tw_center(float *co)
112 {
113         float *twcent= G.scene->twcent;
114         float *min= G.scene->twmin;
115         float *max= G.scene->twmax;
116         
117         DO_MINMAX(co, min, max);
118         VecAddf(twcent, twcent, co);
119 }
120
121 /* callback */
122 static void stats_pose(ListBase *lb, float *normal, float *plane)
123 {
124         Bone *bone;
125         float vec[3], mat[4][4];
126         
127         for(bone= lb->first; bone; bone= bone->next) {
128                 if (bone->flag & BONE_SELECTED) {
129                         /* We don't let IK children get "grabbed" */
130                         /* ALERT! abusive global Trans here */
131                         if ( (Trans.mode!=TFM_TRANSLATION) || (bone->flag & BONE_IK_TOPARENT)==0 ) {
132                                 
133                                 get_bone_root_pos (bone, vec, 1);
134                                 
135                                 calc_tw_center(vec);
136                                 where_is_bone(G.obpose, bone);
137                                 get_objectspace_bone_matrix(bone, mat, 1, 1);   // points in negative Y o_O
138                                         
139                                 VecAddf(normal, normal, mat[2]);
140                                 VecAddf(plane, plane, mat[1]);
141                                 
142                                 return; // see above function
143                         }
144                 }
145                 stats_pose(&bone->childbase, normal, plane);
146         }
147 }
148
149
150 /* centroid, boundbox, of selection */
151 /* returns total items selected */
152 static int calc_manipulator(ScrArea *sa)
153 {
154         extern ListBase editNurb;
155         View3D *v3d= sa->spacedata.first;
156         Base *base;
157         Object *ob=NULL;
158         float normal[3]={0.0, 0.0, 0.0};
159         float plane[3]={0.0, 0.0, 0.0};
160         int a, totsel=0;
161         
162         /* transform widget matrix */
163         Mat4One(v3d->twmat);
164         
165         /* transform widget centroid/center */
166         G.scene->twcent[0]= G.scene->twcent[1]= G.scene->twcent[2]= 0.0f;
167         INIT_MINMAX(G.scene->twmin, G.scene->twmax);
168         
169         if(G.obedit) {
170                 ob= G.obedit;
171                 
172                 if(G.obedit->type==OB_MESH) {
173                         EditMesh *em = G.editMesh;
174                         EditVert *eve;
175                         
176                         for(eve= em->verts.first; eve; eve= eve->next) {
177                                 if(eve->f & SELECT) {
178                                         totsel++;
179                                         calc_tw_center(eve->co);
180                                 }
181                         }
182                         if(G.vd->twmode == V3D_MANIPULATOR_NORMAL) {
183                                 EditFace *efa;
184                                 float vec[3];
185                                 for(efa= em->faces.first; efa; efa= efa->next) {
186                                         if(efa->f & SELECT) {
187                                                 VecAddf(normal, normal, efa->n);
188                                                 VecSubf(vec, efa->v2->co, efa->v1->co);
189                                                 VecAddf(plane, plane, vec);
190                                         }
191                                 }
192                         }
193                 }
194                 else if (G.obedit->type==OB_ARMATURE){
195                         EditBone *ebo;
196                         for (ebo=G.edbo.first;ebo;ebo=ebo->next){
197                                 
198                                 //      If this is an IK child and it's parent is being moved, don't count as selected
199                                 if ((ebo->flag & BONE_IK_TOPARENT)&& (ebo->flag & BONE_ROOTSEL) && ebo->parent && (ebo->parent->flag & BONE_TIPSEL));
200                                 else {
201                                         if (ebo->flag & BONE_TIPSEL) {
202                                                 calc_tw_center(ebo->tail);
203                                                 totsel++;
204                                         }
205                                         if (ebo->flag & BONE_ROOTSEL) {
206                                                 calc_tw_center(ebo->head);
207                                                 totsel++;
208                                         }
209                                 }
210                         }
211                 }
212                 else if ELEM3(G.obedit->type, OB_CURVE, OB_SURF, OB_FONT) {
213                         Nurb *nu;
214                         BezTriple *bezt;
215                         BPoint *bp;
216                         
217                         nu= editNurb.first;
218                         while(nu) {
219                                 if((nu->type & 7)==CU_BEZIER) {
220                                         bezt= nu->bezt;
221                                         a= nu->pntsu;
222                                         while(a--) {
223                                                 if(bezt->f1) {
224                                                         calc_tw_center(bezt->vec[0]);
225                                                         totsel++;
226                                                 }
227                                                 if(bezt->f2) {
228                                                         calc_tw_center(bezt->vec[1]);
229                                                         totsel++;
230                                                 }
231                                                 if(bezt->f3) {
232                                                         calc_tw_center(bezt->vec[2]);
233                                                         totsel++;
234                                                 }
235                                                 bezt++;
236                                         }
237                                 }
238                                 else {
239                                         bp= nu->bp;
240                                         a= nu->pntsu*nu->pntsv;
241                                         while(a--) {
242                                                 if(bp->f1 & 1) {
243                                                         calc_tw_center(bp->vec);
244                                                         totsel++;
245                                                 }
246                                                 bp++;
247                                         }
248                                 }
249                                 nu= nu->next;
250                         }
251                 }
252                 else if(G.obedit->type==OB_MBALL) {
253                         /* editmball.c */
254                         extern ListBase editelems;  /* go away ! */
255                         MetaElem *ml;
256                 
257                         ml= editelems.first;
258                         while(ml) {
259                                 if(ml->flag & SELECT) {
260                                         calc_tw_center(&ml->x);
261                                         totsel++;
262                                 }
263                                 ml= ml->next;
264                         }
265                 }
266                 else if(G.obedit->type==OB_LATTICE) {
267                         BPoint *bp;
268                         bp= editLatt->def;
269                         
270                         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
271                         while(a--) {
272                                 if(bp->f1 & 1) {
273                                         calc_tw_center(bp->vec);
274                                         totsel++;
275                                 }
276                                 bp++;
277                         }
278                 }
279                 
280                 /* selection center */
281                 if(totsel) {
282                         VecMulf(G.scene->twcent, 1.0f/(float)totsel);   // centroid!
283                         Mat4MulVecfl(G.obedit->obmat, G.scene->twcent);
284                         Mat4MulVecfl(G.obedit->obmat, G.scene->twmin);
285                         Mat4MulVecfl(G.obedit->obmat, G.scene->twmax);
286                 }
287         }
288         else if(G.obpose) {
289                 bArmature *arm= G.obpose->data;
290                 
291                 ob= G.obpose;
292                 Trans.mode= TFM_ROTATION;       // mislead counting bones... bah
293                 
294                 /* count total */
295                 count_bone_select(&arm->bonebase, &totsel);
296                 if(totsel) {
297                         /* recursive get stats */
298                         stats_pose(&arm->bonebase, normal, plane);
299                         
300                         //VecMulf(normal, -1.0);
301                         VecMulf(plane, -1.0);
302                         
303                         VecMulf(G.scene->twcent, 1.0f/(float)totsel);   // centroid!
304                         Mat4MulVecfl(G.obpose->obmat, G.scene->twcent);
305                         Mat4MulVecfl(G.obpose->obmat, G.scene->twmin);
306                         Mat4MulVecfl(G.obpose->obmat, G.scene->twmax);
307                 }
308         }
309         else if(G.f & (G_FACESELECT + G_VERTEXPAINT + G_TEXTUREPAINT +G_WEIGHTPAINT)) {
310                 ;
311         }
312         else {
313                 
314                 /* we need the one selected object, if its not active */
315                 ob= OBACT;
316                 if(ob && !(ob->flag & SELECT)) ob= NULL;
317                 
318                 base= (G.scene->base.first);
319                 while(base) {
320                         if(v3d->lay & base->lay) {
321                                 
322                                 if(base->flag & SELECT) {
323                                         if(ob==NULL) ob= base->object;
324                                         calc_tw_center(base->object->obmat[3]);
325                                         totsel++;
326                                 }
327                         }
328                         base= base->next;
329                 }
330                 
331                 /* selection center */
332                 if(totsel) {
333                         VecMulf(G.scene->twcent, 1.0f/(float)totsel);   // centroid!
334                 }
335         }
336         
337         /* global, local or normal orientation? */
338         if(ob && totsel) {
339                 
340                 switch(v3d->twmode) {
341                 case V3D_MANIPULATOR_GLOBAL:
342                         break;
343                         
344                 case V3D_MANIPULATOR_NORMAL:
345                         if(G.obedit || G.obpose) {
346                                 if(normal[0]!=0.0 || normal[1]!=0.0 || normal[2]!=0.0) {
347                                         float mat[3][3];
348                                         
349                                         Normalise(normal);
350                                         Normalise(plane);
351                                         VECCOPY(mat[2], normal);
352                                         Crossf(mat[0], normal, plane);
353                                         Crossf(mat[1], mat[2], mat[0]);
354                                         
355                                         Mat4MulMat43(v3d->twmat, ob->obmat, mat);
356                                         Mat4Ortho(v3d->twmat);
357                                         
358                                         break;
359                                 }
360                         }
361                         /* no break we define 'normal' as 'local' in Object mode */
362                 case V3D_MANIPULATOR_LOCAL:
363                         if(totsel==1 || v3d->around==V3D_LOCAL || G.obedit || G.obpose) {
364                                 Mat4CpyMat4(v3d->twmat, ob->obmat);
365                                 Mat4Ortho(v3d->twmat);
366                         }
367                         break;
368                 }               
369         }
370            
371         return totsel;
372 }
373
374 /* ******************** DRAWING STUFFIES *********** */
375
376 /* radring = radius of donut rings
377    radhole = radius hole
378    start = starting segment (based on nrings)
379    end   = end segment
380    nsides = amount of points in ring
381    nrigns = amount of rings
382 */
383 static void partial_donut(float radring, float radhole, int start, int end, int nsides, int nrings)
384 {
385         float theta, phi, theta1;
386         float cos_theta, sin_theta;
387         float cos_theta1, sin_theta1;
388         float ring_delta, side_delta;
389         int i, j;
390         
391         ring_delta= 2.0*M_PI/(float)nrings;
392         side_delta= 2.0*M_PI/(float)nsides;
393         
394         theta= M_PI+0.5*ring_delta;
395         cos_theta= cos(theta);
396         sin_theta= sin(theta);
397         
398         for(i= nrings - 1; i >= 0; i--) {
399                 theta1= theta + ring_delta;
400                 cos_theta1= cos(theta1);
401                 sin_theta1= sin(theta1);
402                 
403                 if(i==start) {  // cap
404                         glBegin(GL_POLYGON);
405                         glNormal3f(-sin_theta1, -cos_theta1, 0.0);
406                         phi= 0.0;
407                         for(j= nsides; j >= 0; j--) {
408                                 float cos_phi, sin_phi, dist;
409                                 
410                                 phi += side_delta;
411                                 cos_phi= cos(phi);
412                                 sin_phi= sin(phi);
413                                 dist= radhole + radring * cos_phi;
414                                 
415                                 glVertex3f(cos_theta1 * dist, -sin_theta1 * dist,  radring * sin_phi);
416                         }
417                         glEnd();
418                 }
419                 if(i>=start && i<=end) {
420                         glBegin(GL_QUAD_STRIP);
421                         phi= 0.0;
422                         for(j= nsides; j >= 0; j--) {
423                                 float cos_phi, sin_phi, dist;
424                                 
425                                 phi += side_delta;
426                                 cos_phi= cos(phi);
427                                 sin_phi= sin(phi);
428                                 dist= radhole + radring * cos_phi;
429                                 
430                                 glNormal3f(cos_theta1 * cos_phi, -sin_theta1 * cos_phi, sin_phi);
431                                 glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi);
432                                 glNormal3f(cos_theta * cos_phi, -sin_theta * cos_phi, sin_phi);
433                                 glVertex3f(cos_theta * dist, -sin_theta * dist,  radring * sin_phi);
434                         }
435                         glEnd();
436                 }
437                 
438                 if(i==end) {    // cap
439                         glBegin(GL_POLYGON);
440                         glNormal3f(sin_theta, cos_theta, 0.0);
441                         phi= 0.0;
442                         for(j= nsides; j >= 0; j--) {
443                                 float cos_phi, sin_phi, dist;
444                                 
445                                 phi -= side_delta;
446                                 cos_phi= cos(phi);
447                                 sin_phi= sin(phi);
448                                 dist= radhole + radring * cos_phi;
449                                 
450                                 glVertex3f(cos_theta * dist, -sin_theta * dist,  radring * sin_phi);
451                         }
452                         glEnd();
453                 }
454                 
455                 
456                 theta= theta1;
457                 cos_theta= cos_theta1;
458                 sin_theta= sin_theta1;
459         }
460 }
461
462 /* three colors can be set;
463    GL_BLEND: grey for ghosting
464    G.moving: in transform theme color
465    else the red/green/blue
466 */
467 static void manipulator_setcolor(char mode)
468 {
469         float vec[4];
470         
471         vec[3]= 1.0;
472         
473         if(glIsEnabled(GL_BLEND)) {
474                 if(mode > 'Z') glColor4ub(0, 0, 0, 70);
475                 else {
476                         vec[0]= vec[1]= vec[2]= 1.0; vec[3]= 0.3;
477                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
478                 }
479         }
480         else if(G.moving) {
481                 if(mode > 'Z') BIF_ThemeColor(TH_TRANSFORM);
482                 else {
483                         BIF_GetThemeColor3fv(TH_TRANSFORM, vec);
484                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
485                 }
486         }
487         else {
488                 switch(mode) {
489                 case 'x':
490                         glColor3ub(255, 0, 100);
491                         break;
492                 case 'y':
493                         glColor3ub(100, 255, 100);
494                         break;
495                 case 'z':
496                         glColor3ub(50, 50, 225);
497                         break;
498                 case 'X':
499                         vec[2]= vec[1]= 0.0; vec[0]= 1.0;
500                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
501                         break;
502                 case 'Y':
503                         vec[0]= vec[2]= 0.0; vec[1]= 1.0;
504                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
505                         break;
506                 case 'Z':
507                         vec[0]= vec[1]= 0.0; vec[2]= 1.0;
508                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
509                         break;
510                 }
511         }
512 }
513
514 static int Gval= 0xFFFF;        // defines drawmodus while moving...
515
516 /* viewmatrix should have been set OK, also no shademode! */
517 static void draw_manipulator_axes(int flagx, int flagy, int flagz)
518 {
519         
520         /* axes */
521         if(Gval & flagx) {
522                 manipulator_setcolor('x');
523                 glBegin(GL_LINES);
524                 glVertex3f(0.0, 0.0, 0.0);
525                 glVertex3f(1.0, 0.0, 0.0);
526                 glEnd();
527         }               
528         if(Gval & flagy) {
529                 manipulator_setcolor('y');
530                 glBegin(GL_LINES);
531                 glVertex3f(0.0, 0.0, 0.0);
532                 glVertex3f(0.0, 1.0, 0.0);
533                 glEnd();
534         }               
535         if(Gval & flagz) {
536                 manipulator_setcolor('z');
537                 glBegin(GL_LINES);
538                 glVertex3f(0.0, 0.0, 0.0);
539                 glVertex3f(0.0, 0.0, 1.0);
540                 glEnd();
541         }
542 }
543
544
545 /* only called while G.moving */
546 static void draw_manipulator_rotate_ghost(float mat[][4])
547 {
548         GLUquadricObj *qobj= gluNewQuadric(); 
549         float phi, vec[3], matt[4][4], cross[3];
550         
551         glDisable(GL_DEPTH_TEST);
552         gluQuadricDrawStyle(qobj, GLU_FILL); 
553         
554         /* we need both [4][4] transforms, Trans.mat seems to be premul, not post for mat[][4] */
555         Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
556         Mat4MulMat34(matt, Trans.mat, mat);
557         
558         mymultmatrix(mat);      // aligns with original widget
559         
560         glColor4ub(0,0,0,64);
561         glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
562         glEnable(GL_BLEND);
563         
564         /* Z disk */
565         if(Gval & MAN_ROT_Z) {
566                 VECCOPY(vec, mat[0]);   // use x axis to detect rotation
567                 Normalise(vec);
568                 Normalise(matt[0]);
569                 phi= saacos( Inpf(vec, matt[0]) );
570                 if(phi!=0.0) {
571                         Crossf(cross, vec, matt[0]);    // results in z vector
572                         if(Inpf(cross, mat[2]) > 0.0) phi= -phi;
573                         gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 90.0, 180.0*phi/M_PI);
574                 }
575         }
576         /* X disk */
577         if(Gval & MAN_ROT_X) {
578                 VECCOPY(vec, mat[1]);   // use y axis to detect rotation
579                 Normalise(vec);
580                 Normalise(matt[1]);
581                 phi= saacos( Inpf(vec, matt[1]) );
582                 if(phi!=0.0) {
583                         Crossf(cross, vec, matt[1]);    // results in x vector
584                         if(Inpf(cross, mat[0]) > 0.0) phi= -phi;
585                         glRotatef(90.0, 0.0, 1.0, 0.0);
586                         gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 0.0, 180.0*phi/M_PI);
587                         glRotatef(-90.0, 0.0, 1.0, 0.0);
588                 }
589         }       
590         /* Y circle */
591         if(Gval & MAN_ROT_Y) {
592                 VECCOPY(vec, mat[2]);   // use z axis to detect rotation
593                 Normalise(vec);
594                 Normalise(matt[2]);
595                 phi= saacos( Inpf(vec, matt[2]) );
596                 if(phi!=0.0) {
597                         Crossf(cross, vec, matt[2]);    // results in y vector
598                         if(Inpf(cross, mat[1]) > 0.0) phi= -phi;
599                         glRotatef(-90.0, 1.0, 0.0, 0.0);
600                         gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 180.0, 180.0*phi/M_PI);
601                         glRotatef(90.0, 1.0, 0.0, 0.0);
602                 }
603         }
604         
605         glDisable(GL_BLEND);
606         myloadmatrix(G.vd->viewmat);
607 }
608
609 static void draw_manipulator_rotate(float mat[][4])
610 {
611         GLUquadricObj *qobj= gluNewQuadric(); 
612         double plane[4];
613         float size, vec[3], unitmat[4][4];
614         float cywid= 0.33f*0.01f*(float)U.tw_handlesize;        
615         float cusize= cywid*0.75;
616         int arcs= (G.rt==2);
617         
618         if(G.rt==3) cusize= cywid*0.25;
619         
620         /* when called while moving in mixed mode, do not draw when... */
621         if((Gval & MAN_ROT_C)==0) return;
622         
623         /* Init stuff */
624         glDisable(GL_DEPTH_TEST);
625         Mat4One(unitmat);
626         gluQuadricDrawStyle(qobj, GLU_FILL); 
627         gluQuadricNormals(qobj, GLU_SMOOTH);
628         glEnable(GL_CULL_FACE);         // backface removal
629         glShadeModel(GL_SMOOTH);
630         
631         
632         /* prepare for screen aligned draw */
633         VECCOPY(vec, mat[0]);
634         size= Normalise(vec);
635         glPushMatrix();
636         glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
637         
638         if(arcs) {
639                 /* clipplane makes nice handles, calc here because of multmatrix but with translate! */
640                 VECCOPY(plane, G.vd->viewinv[2]);
641                 plane[3]= -0.1; // clip more
642                 glClipPlane(GL_CLIP_PLANE0, plane);
643         }
644         /* sets view screen aligned */
645         glRotatef( -360.0*saacos(G.vd->viewquat[0])/M_PI, G.vd->viewquat[1], G.vd->viewquat[2], G.vd->viewquat[3]);
646         
647         /* Screen aligned help circle */
648         if(arcs) {
649                 if((G.f & G_PICKSEL)==0) {
650                         BIF_ThemeColorShade(TH_BACK, -30);
651                         drawcircball(unitmat[3], size, unitmat);
652                 }
653         }
654         /* Screen aligned view rot circle */
655         if(Gval & MAN_ROT_V) {
656                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
657                 BIF_ThemeColor(TH_TRANSFORM);
658                 drawcircball(unitmat[3], 1.2*size, unitmat);
659                 
660                 if(G.moving) {  
661                         float vec[3];
662                         vec[0]= Trans.imval[0] - Trans.center2d[0];
663                         vec[1]= Trans.imval[1] - Trans.center2d[1];
664                         vec[2]= 0.0;
665                         Normalise(vec);
666                         VecMulf(vec, 1.2*size);
667                         glBegin(GL_LINES);
668                         glVertex3f(0.0, 0.0, 0.0);
669                         glVertex3fv(vec);
670                         glEnd();
671                 }
672         }
673         glPopMatrix();
674         
675         /* apply the transform delta */
676         if(G.moving) {
677                 float matt[4][4];
678                 Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
679                 Mat4MulMat34(matt, Trans.mat, mat);
680                 mymultmatrix(matt);
681         }
682         else mymultmatrix(mat);
683         
684         /* axes */
685         if(arcs==0) {
686                 if(!(G.f & G_PICKSEL)) {
687                         /* axis */
688                         glBegin(GL_LINES);
689                         if( (Gval & MAN_ROT_X) || (G.moving && (Gval & MAN_ROT_Z)) ) {
690                                 manipulator_setcolor('x');
691                                 glVertex3f(0.0, 0.0, 0.0);
692                                 glVertex3f(1.0, 0.0, 0.0);
693                         }               
694                         if( (Gval & MAN_ROT_Y) || (G.moving && (Gval & MAN_ROT_X)) ) {
695                                 manipulator_setcolor('y');
696                                 glVertex3f(0.0, 0.0, 0.0);
697                                 glVertex3f(0.0, 1.0, 0.0);
698                         }               
699                         if( (Gval & MAN_ROT_Z) || (G.moving && (Gval & MAN_ROT_Y)) ) {
700                                 manipulator_setcolor('z');
701                                 glVertex3f(0.0, 0.0, 0.0);
702                                 glVertex3f(0.0, 0.0, 1.0);
703                         }
704                         glEnd();
705                 }
706         }
707         
708         /* Trackball center */
709         if(Gval & MAN_ROT_T) {
710                 float smat[3][3], imat[3][3];
711                 float offset[3];
712                 
713                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_T);
714                 
715                 Mat3CpyMat4(smat, mat);
716                 Mat3Inv(imat, smat);
717
718                 getViewVector(mat[3], offset);
719                 Mat3MulVecfl(imat, offset);
720                 Normalise(offset);      // matrix space is such that 1.0 = size of sphere
721                 
722                 BIF_ThemeColor(TH_TRANSFORM);
723                 glBegin(GL_LINES);
724                 glVertex3f(0.0, 0.0, 0.0);
725                 glVertex3fv(offset);
726                 glEnd();
727                 
728                 glEnable(GL_LIGHTING);
729                 BIF_GetThemeColor3fv(TH_TRANSFORM, vec);
730                 if(G.vd->twmode == V3D_MANIPULATOR_LOCAL) {vec[0]+= 0.25; vec[1]+=0.25; vec[2]+=0.25;}
731                 else if(G.vd->twmode == V3D_MANIPULATOR_NORMAL) {vec[0]-= 0.2; vec[1]-=0.2; vec[2]-=0.2;}
732                 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
733                 
734                 VECCOPY(vec, offset);
735                 glTranslatef(vec[0], vec[1], vec[2]);
736                 gluSphere(qobj, cywid, 8, 6);
737                 
738                 /* restore */
739                 glTranslatef(-vec[0], -vec[1], -vec[2]);
740                 glDisable(GL_LIGHTING);
741         }
742         
743         if(arcs==0 && G.moving) {
744                 
745                 if(arcs) glEnable(GL_CLIP_PLANE0);
746
747                 /* Z circle */
748                 if(Gval & MAN_ROT_Z) {
749                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
750                         manipulator_setcolor('z');
751                         drawcircball(unitmat[3], 1.0, unitmat);
752                 }
753                 /* X circle */
754                 if(Gval & MAN_ROT_X) {
755                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
756                         glRotatef(90.0, 0.0, 1.0, 0.0);
757                         manipulator_setcolor('x');
758                         drawcircball(unitmat[3], 1.0, unitmat);
759                         glRotatef(-90.0, 0.0, 1.0, 0.0);
760                 }       
761                 /* Y circle */
762                 if(Gval & MAN_ROT_Y) {
763                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
764                         glRotatef(-90.0, 1.0, 0.0, 0.0);
765                         manipulator_setcolor('y');
766                         drawcircball(unitmat[3], 1.0, unitmat);
767                         glRotatef(90.0, 1.0, 0.0, 0.0);
768                 }
769                 
770                 if(arcs) glDisable(GL_CLIP_PLANE0);
771         }
772         // donut arcs
773         if(arcs) {
774                 glEnable(GL_LIGHTING);
775                 glEnable(GL_CLIP_PLANE0);
776                 
777                 /* Z circle */
778                 if(Gval & MAN_ROT_Z) {
779                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
780                         manipulator_setcolor('Z');
781                         partial_donut(cusize/3.0, 1.0, 0, 48, 8, 48);
782                 }
783                 /* X circle */
784                 if(Gval & MAN_ROT_X) {
785                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
786                         glRotatef(90.0, 0.0, 1.0, 0.0);
787                         manipulator_setcolor('X');
788                         partial_donut(cusize/3.0, 1.0, 0, 48, 8, 48);
789                         glRotatef(-90.0, 0.0, 1.0, 0.0);
790                 }       
791                 /* Y circle */
792                 if(Gval & MAN_ROT_Y) {
793                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
794                         glRotatef(-90.0, 1.0, 0.0, 0.0);
795                         manipulator_setcolor('Y');
796                         partial_donut(cusize/3.0, 1.0, 0, 48, 8, 48);
797                         glRotatef(90.0, 1.0, 0.0, 0.0);
798                 }
799                 
800                 glDisable(GL_CLIP_PLANE0);
801         }
802         
803         if(arcs==0) {
804                 glEnable(GL_LIGHTING);
805                 
806                 /* Z handle on X axis */
807                 if(Gval & MAN_ROT_Z) {
808                         glPushMatrix();
809                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
810                         manipulator_setcolor('Z');
811
812                         if(G.rt==3) {
813                                 partial_donut(cusize, 1.0, 21, 27, 8, 48);
814
815                                 /* Z handle on Y axis */
816                                 glRotatef(90.0, 0.0, 0.0, 1.0);
817                                 partial_donut(cusize, 1.0, 21, 27, 8, 48);
818                         }
819                         else {
820                                 partial_donut(cusize, 1.0, 23, 25, 8, 48);
821                         }
822                         glPopMatrix();
823                 }       
824
825                 /* Y handle on X axis */
826                 if(Gval & MAN_ROT_Y) {
827                         glPushMatrix();
828                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
829                         manipulator_setcolor('Y');
830                         
831                         if(G.rt==3) {
832                                 glRotatef(90.0, 1.0, 0.0, 0.0);
833                                 partial_donut(cusize, 1.0, 21, 27, 8, 48);
834                                 
835                                 /* Y handle on Z axis */
836                                 glRotatef(90.0, 0.0, 0.0, 1.0);
837                                 partial_donut(cusize, 1.0, 21, 27, 8, 48);
838                         }
839                         else {
840                                 glRotatef(90.0, 1.0, 0.0, 0.0);
841                                 glRotatef(90.0, 0.0, 0.0, 1.0);
842                                 partial_donut(cusize, 1.0, 23, 25, 8, 48);
843                         }
844                         
845                         glPopMatrix();
846                 }
847                 
848                 /* X handle on Z axis */
849                 if(Gval & MAN_ROT_X) {
850                         glPushMatrix();
851                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
852                         manipulator_setcolor('X');
853                         
854                         if(G.rt==3) {
855                                 glRotatef(-90.0, 0.0, 1.0, 0.0);
856                                 partial_donut(cusize, 1.0, 21, 27, 8, 48);
857                                 
858                                 /* X handle on Y axis */
859                                 glRotatef(90.0, 0.0, 0.0, 1.0);
860                                 partial_donut(cusize, 1.0, 21, 27, 8, 48);
861                         }
862                         else {
863                                 glRotatef(-90.0, 0.0, 1.0, 0.0);
864                                 glRotatef(90.0, 0.0, 0.0, 1.0);
865                                 partial_donut(cusize, 1.0, 23, 25, 8, 48);
866                         }
867                         glPopMatrix();
868                 }
869                 
870         }
871         
872         /* restore */
873         myloadmatrix(G.vd->viewmat);
874         glDisable(GL_CULL_FACE);
875         glDisable(GL_LIGHTING);
876         gluDeleteQuadric(qobj);
877         if(G.zbuf) glEnable(GL_DEPTH_TEST);             // shouldn't be global, tsk!
878         
879 }
880
881 /* only called while G.moving */
882 static void draw_manipulator_scale_ghost(float mat[][4])
883 {
884         float cywid= 0.33f*0.01f*(float)U.tw_handlesize;        
885         float cusize= cywid*0.75;
886         float vec[4];
887         
888         glDisable(GL_DEPTH_TEST);
889         glEnable(GL_CULL_FACE);         // backface removal
890         glEnable(GL_LIGHTING);
891         glShadeModel(GL_SMOOTH);
892         
893         mymultmatrix(mat);      // aligns with original widget
894         
895         glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
896         glEnable(GL_BLEND);
897         
898         draw_manipulator_axes(MAN_SCALE_X, MAN_SCALE_Y, MAN_SCALE_Z);
899         
900         vec[0]= vec[1]= vec[2]= 1.0; vec[3]= 0.3;
901         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
902
903         /* Z cube */
904         glTranslatef(0.0, 0.0, 1.0+cusize/2);
905         if(Gval & MAN_SCALE_Z) {
906                 drawsolidcube(cusize);
907         }       
908         /* X cube */
909         glTranslatef(1.0+cusize/2, 0.0, -(1.0+cusize/2));
910         if(Gval & MAN_SCALE_X) {
911                 drawsolidcube(cusize);
912         }       
913         /* Y cube */
914         glTranslatef(-(1.0+cusize/2), 1.0+cusize/2, 0.0);
915         if(Gval & MAN_SCALE_Y) {
916                 drawsolidcube(cusize);
917         }
918         
919         /* restore */
920         glDisable(GL_BLEND);
921         myloadmatrix(G.vd->viewmat);
922         if(G.zbuf) glEnable(GL_DEPTH_TEST);             // shouldn't be global, tsk!
923         glDisable(GL_CULL_FACE);
924         glDisable(GL_LIGHTING);
925 }       
926
927 static void draw_manipulator_scale(float mat[][4])
928 {
929         float cywid= 0.33f*0.01f*(float)U.tw_handlesize;        
930         float cusize= cywid*0.75;
931         float vec[3];
932         
933         /* when called while moving in mixed mode, do not draw when... */
934         if((Gval & MAN_SCALE_C)==0) return;
935         
936         if(G.moving) {
937                 float matt[4][4];
938                 
939                 Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
940                 Mat4MulMat34(matt, Trans.mat, mat);
941                 mymultmatrix(matt);
942         }
943         else mymultmatrix(mat);
944
945         /* axis */
946         if( (G.f & G_PICKSEL)==0 ) {
947                 
948                 glDisable(GL_DEPTH_TEST);
949                 
950                 draw_manipulator_axes(MAN_SCALE_X, MAN_SCALE_Y, MAN_SCALE_Z);
951
952                 /* only has to be set when not in picking */
953                 glEnable(GL_CULL_FACE);         // backface removal
954                 glEnable(GL_LIGHTING);
955                 glShadeModel(GL_SMOOTH);
956         }
957         
958         /* center cube, do not add to selection when shift is pressed (planar constraint)  */
959         if( (G.f & G_PICKSEL) && (G.qual & LR_SHIFTKEY)==0) glLoadName(MAN_SCALE_C);
960         
961         BIF_GetThemeColor3fv(TH_TRANSFORM, vec);
962         if(G.vd->twmode == V3D_MANIPULATOR_LOCAL) {vec[0]+= 0.25; vec[1]+=0.25; vec[2]+=0.25;}
963         else if(G.vd->twmode == V3D_MANIPULATOR_NORMAL) {vec[0]-= 0.2; vec[1]-=0.2; vec[2]-=0.2;}
964         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
965         
966         drawsolidcube(cusize);
967         
968         /* Z cube */
969         glTranslatef(0.0, 0.0, 1.0+cusize/2);
970         if(Gval & MAN_SCALE_Z) {
971                 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z);
972                 manipulator_setcolor('Z');
973                 drawsolidcube(cusize);
974         }       
975         /* X cube */
976         glTranslatef(1.0+cusize/2, 0.0, -(1.0+cusize/2));
977         if(Gval & MAN_SCALE_X) {
978                 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_X);
979                 manipulator_setcolor('X');
980                 drawsolidcube(cusize);
981         }       
982         /* Y cube */
983         glTranslatef(-(1.0+cusize/2), 1.0+cusize/2, 0.0);
984         if(Gval & MAN_SCALE_Y) {
985                 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y);
986                 manipulator_setcolor('Y');
987                 drawsolidcube(cusize);
988         }
989         
990         glDisable(GL_CULL_FACE);
991         glDisable(GL_LIGHTING);
992         
993         /* if shiftkey, center point as last, for selectbuffer order */
994         if(G.f & G_PICKSEL) {
995                 if(G.qual & LR_SHIFTKEY) {
996                         glTranslatef(0.0, -(1.0+cusize/2), 0.0);
997                         glLoadName(MAN_SCALE_C);
998                         glBegin(GL_POINTS);
999                         glVertex3f(0.0, 0.0, 0.0);
1000                         glEnd();
1001                 }
1002         }
1003         
1004         myloadmatrix(G.vd->viewmat);
1005         
1006         if(G.zbuf) glEnable(GL_DEPTH_TEST);             // shouldn't be global, tsk!
1007 }
1008
1009 static void draw_cone(GLUquadricObj *qobj, float len, float width)
1010 {
1011         gluCylinder(qobj, width, 0.0, len, 8, 1);
1012         gluQuadricOrientation(qobj, GLU_INSIDE);
1013         gluDisk(qobj, 0.0, width, 8, 1); 
1014         gluQuadricOrientation(qobj, GLU_OUTSIDE);
1015 }
1016
1017 /* only called while G.moving */
1018 static void draw_manipulator_translate_ghost(float mat[][4])
1019 {
1020         GLUquadricObj *qobj = gluNewQuadric(); 
1021         float vec[4];
1022         float cylen= 0.01f*(float)U.tw_handlesize;
1023         float cywid= 0.33f*cylen;
1024         
1025         glDisable(GL_DEPTH_TEST);
1026         
1027         mymultmatrix(mat);      // aligns with original widget
1028         
1029         glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
1030         glEnable(GL_BLEND);
1031         
1032         draw_manipulator_axes(MAN_TRANS_X, MAN_TRANS_Y, MAN_TRANS_Z);
1033         
1034         glEnable(GL_CULL_FACE);         // backface removal
1035         glEnable(GL_LIGHTING);
1036         glShadeModel(GL_SMOOTH);
1037         vec[0]= vec[1]= vec[2]= 1.0; vec[3]= 0.3;
1038         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
1039
1040         /* center sphere */
1041         gluSphere(qobj, cywid, 8, 6); 
1042         
1043         /* Z Cone */
1044         glTranslatef(0.0, 0.0, 1.0 - cylen);
1045         if(Gval & MAN_TRANS_Z) {
1046                 draw_cone(qobj, cylen, cywid);
1047         }       
1048         /* X Cone */
1049         glTranslatef(1.0 - cylen, 0.0, -(1.0 - cylen));
1050         if(Gval & MAN_TRANS_X) {
1051                 glRotatef(90.0, 0.0, 1.0, 0.0);
1052                 draw_cone(qobj, cylen, cywid);
1053                 glRotatef(-90.0, 0.0, 1.0, 0.0);
1054         }       
1055         /* Y Cone */
1056         glTranslatef(-(1.0 - cylen), 1.0 - cylen, 0.0);
1057         if(Gval & MAN_TRANS_Y) {
1058                 glRotatef(-90.0, 1.0, 0.0, 0.0);
1059                 draw_cone(qobj, cylen, cywid);
1060         }
1061         
1062         /* restore */
1063         glDisable(GL_BLEND);
1064         myloadmatrix(G.vd->viewmat);
1065         if(G.zbuf) glEnable(GL_DEPTH_TEST);             // shouldn't be global, tsk!
1066         glDisable(GL_CULL_FACE);
1067         glDisable(GL_LIGHTING);
1068 }       
1069
1070
1071
1072 static void draw_manipulator_translate(float mat[][4])
1073 {
1074         GLUquadricObj *qobj = gluNewQuadric(); 
1075         float vec[3];
1076         float cylen= 0.01f*(float)U.tw_handlesize;
1077         float cywid= 0.33f*cylen;
1078         
1079         /* when called while moving in mixed mode, do not draw when... */
1080         if((Gval & MAN_TRANS_C)==0) return;
1081         
1082         if(G.moving) glTranslatef(Trans.vec[0], Trans.vec[1], Trans.vec[2]);
1083         
1084         mymultmatrix(mat);
1085
1086         glDisable(GL_DEPTH_TEST);
1087         
1088         /* axis */
1089         if( (G.f & G_PICKSEL)==0 ) {
1090                 draw_manipulator_axes(MAN_TRANS_X, MAN_TRANS_Y, MAN_TRANS_Z);
1091         
1092                 /* only has to be set when not in picking */
1093                 gluQuadricDrawStyle(qobj, GLU_FILL); 
1094                 gluQuadricNormals(qobj, GLU_SMOOTH);
1095                 glEnable(GL_CULL_FACE);         // backface removal
1096                 glEnable(GL_LIGHTING);
1097                 glShadeModel(GL_SMOOTH);
1098         }
1099         
1100         /* center sphere, do not add to selection when shift is pressed (planar constraint) */
1101         if( (G.f & G_PICKSEL) && (G.qual & LR_SHIFTKEY)==0) glLoadName(MAN_TRANS_C);
1102         
1103         BIF_GetThemeColor3fv(TH_TRANSFORM, vec);
1104         if(G.vd->twmode == V3D_MANIPULATOR_LOCAL) {vec[0]+= 0.25; vec[1]+=0.25; vec[2]+=0.25;}
1105         else if(G.vd->twmode == V3D_MANIPULATOR_NORMAL) {vec[0]-= 0.2; vec[1]-=0.2; vec[2]-=0.2;}
1106         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
1107         
1108         gluSphere(qobj, cywid, 8, 6); 
1109         
1110         /* Z Cone */
1111         glTranslatef(0.0, 0.0, 1.0 - cylen);
1112         if(Gval & MAN_TRANS_Z) {
1113                 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Z);
1114                 manipulator_setcolor('Z');
1115                 draw_cone(qobj, cylen, cywid);
1116         }       
1117         /* X Cone */
1118         glTranslatef(1.0 - cylen, 0.0, -(1.0 - cylen));
1119         if(Gval & MAN_TRANS_X) {
1120                 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_X);
1121                 glRotatef(90.0, 0.0, 1.0, 0.0);
1122                 manipulator_setcolor('X');
1123                 draw_cone(qobj, cylen, cywid);
1124                 glRotatef(-90.0, 0.0, 1.0, 0.0);
1125         }       
1126         /* Y Cone */
1127         glTranslatef(-(1.0 - cylen), 1.0 - cylen, 0.0);
1128         if(Gval & MAN_TRANS_Y) {
1129                 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Y);
1130                 glRotatef(-90.0, 1.0, 0.0, 0.0);
1131                 manipulator_setcolor('Y');
1132                 draw_cone(qobj, cylen, cywid);
1133         }
1134         
1135         glDisable(GL_CULL_FACE);
1136         glDisable(GL_LIGHTING);
1137         
1138         /* if shiftkey, center point as last, for selectbuffer */
1139         if(G.f & G_PICKSEL) {
1140                 if(G.qual & LR_SHIFTKEY) {
1141                         glRotatef(90.0, 1.0, 0.0, 0.0);
1142                         glTranslatef(0.0, -(1.0 - cylen), 0.0);
1143                         //glLoadName(MAN_TRANS_C);
1144                         //glBegin(GL_POINTS);
1145                         //glVertex3f(0.0, 0.0, 0.0);
1146                         //glEnd();
1147                 }
1148         }
1149         
1150         gluDeleteQuadric(qobj);
1151         myloadmatrix(G.vd->viewmat);
1152         
1153         if(G.zbuf) glEnable(GL_DEPTH_TEST);             // shouldn't be global, tsk!
1154         
1155 }
1156
1157 /* main call, does calc centers & orientation too */
1158 void BIF_draw_manipulator(ScrArea *sa)
1159 {
1160         View3D *v3d= sa->spacedata.first;
1161         float len1, len2, size, vec[3];
1162         int totsel;
1163         
1164         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return;
1165         if(G.moving && (G.moving & G_TRANSFORM_MANIP)==0) return;
1166         
1167         if(G.moving==0) {
1168                 v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
1169                 
1170                 totsel= calc_manipulator(sa);
1171                 if(totsel==0) return;
1172                 
1173                 v3d->twflag |= V3D_DRAW_MANIPULATOR;
1174
1175                 /* now we can define centre */
1176                 switch(v3d->around) {
1177                 case V3D_CENTRE:
1178                 case V3D_LOCAL:
1179                         v3d->twmat[3][0]= (G.scene->twmin[0] + G.scene->twmax[0])/2.0;
1180                         v3d->twmat[3][1]= (G.scene->twmin[1] + G.scene->twmax[1])/2.0;
1181                         v3d->twmat[3][2]= (G.scene->twmin[2] + G.scene->twmax[2])/2.0;
1182                         break;
1183                 case V3D_CENTROID:
1184                         VECCOPY(v3d->twmat[3], G.scene->twcent);
1185                         break;
1186                 case V3D_CURSOR:
1187                         VECCOPY(v3d->twmat[3], G.scene->cursor);
1188                         break;
1189                 }
1190                 
1191                 /* size calculus, depending ortho/persp settings, like initgrabz() */
1192                 size= G.vd->persmat[0][3]*v3d->twmat[3][0]+ G.vd->persmat[1][3]*v3d->twmat[3][1]+ G.vd->persmat[2][3]*v3d->twmat[3][2]+ G.vd->persmat[3][3];
1193                 
1194                 VECCOPY(vec, G.vd->persinv[0]);
1195                 len1= Normalise(vec);
1196                 VECCOPY(vec, G.vd->persinv[1]);
1197                 len2= Normalise(vec);
1198                 
1199                 size*= (0.01f*(float)U.tw_size)*(len1>len2?len1:len2);
1200                 if(U.tw_flag & U_TW_ABSOLUTE) {
1201                         /* correct for relative window size */
1202                         if(sa->winx > sa->winy) size*= 1000.0f/(float)sa->winx;
1203                         else size*= 1000.0f/(float)sa->winy;
1204                 }
1205                 Mat4MulFloat3((float *)v3d->twmat, size);
1206         }
1207         
1208         if(v3d->twflag & V3D_DRAW_MANIPULATOR) {
1209                 
1210                 if(v3d->twtype & V3D_MANIPULATOR_ROTATE) {
1211                         if(G.moving) draw_manipulator_rotate_ghost(v3d->twmat);
1212                         draw_manipulator_rotate(v3d->twmat);
1213                 }
1214                 if(v3d->twtype & V3D_MANIPULATOR_SCALE) {
1215                         if(G.moving) draw_manipulator_scale_ghost(v3d->twmat);
1216                         draw_manipulator_scale(v3d->twmat);
1217                 }
1218                 if(v3d->twtype & V3D_MANIPULATOR_TRANSLATE) {
1219                         if(G.moving) draw_manipulator_translate_ghost(v3d->twmat);
1220                         draw_manipulator_translate(v3d->twmat);
1221                 }
1222         }
1223 }
1224
1225 static int manipulator_selectbuf(ScrArea *sa, float hotspot)
1226 {
1227         View3D *v3d= sa->spacedata.first;
1228         rctf rect;
1229         GLuint buffer[64];              // max 4 items per select, so large enuf
1230         short hits, mval[2];
1231         
1232         G.f |= G_PICKSEL;
1233         
1234         getmouseco_areawin(mval);
1235         rect.xmin= mval[0]-hotspot;
1236         rect.xmax= mval[0]+hotspot;
1237         rect.ymin= mval[1]-hotspot;
1238         rect.ymax= mval[1]+hotspot;
1239         
1240         /* get rid of overlay button matrix */
1241         persp(PERSP_VIEW);
1242         
1243         setwinmatrixview3d(&rect);
1244         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, sa->winmat);
1245         
1246         glSelectBuffer( 64, buffer);
1247         glRenderMode(GL_SELECT);
1248         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1249         glPushName(-2);
1250         
1251         /* do the drawing */
1252         if(v3d->twtype & V3D_MANIPULATOR_ROTATE)
1253                 draw_manipulator_rotate(v3d->twmat);
1254         if(v3d->twtype & V3D_MANIPULATOR_SCALE)
1255                 draw_manipulator_scale(v3d->twmat);
1256         if(v3d->twtype & V3D_MANIPULATOR_TRANSLATE)
1257                 draw_manipulator_translate(v3d->twmat);
1258         
1259         glPopName();
1260         hits= glRenderMode(GL_RENDER);
1261         
1262         G.f &= ~G_PICKSEL;
1263         setwinmatrixview3d(0);
1264         Mat4MulMat4(G.vd->persmat, G.vd->viewmat, sa->winmat);
1265         
1266         persp(PERSP_WIN);
1267         
1268         if(hits==1) return buffer[3];
1269         else if(hits>1) {
1270                 /* we compare the two first in buffer, but exclude centers */
1271                 
1272                 if(buffer[3]==MAN_TRANS_C || buffer[3]==MAN_SCALE_C);
1273                 else if(buffer[4+3]==MAN_TRANS_C || buffer[4+3]==MAN_SCALE_C);
1274                 else {
1275                         if(buffer[4+1] < buffer[1]) return buffer[4+3];
1276                 }
1277                 return buffer[3];
1278         }
1279         return 0;
1280 }
1281
1282 int BIF_do_manipulator(ScrArea *sa)
1283 {
1284         View3D *v3d= sa->spacedata.first;
1285         int val;
1286         
1287         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0;
1288         if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0;
1289         
1290         // find the hotspots (Gval is for draw). first test narrow hotspot
1291         // warning, Gval is ugly global defining how it draws, don't set it before doing select calls!
1292         val= manipulator_selectbuf(sa, 0.5*(float)U.tw_hotspot);
1293         if(val) {
1294                 short mvalo[2], mval[2];
1295                 
1296                 Gval= manipulator_selectbuf(sa, 0.2*(float)U.tw_hotspot);
1297                 if(Gval) val= Gval;
1298                 else Gval= val;
1299                 
1300                 getmouseco_areawin(mvalo);
1301                 
1302                 switch(val) {
1303                 case MAN_TRANS_C:
1304                         ManipulatorTransform(TFM_TRANSLATION);
1305                         break;
1306                 case MAN_TRANS_X:
1307                         if(G.qual & LR_SHIFTKEY) {
1308                                 Gval= MAN_TRANS_Y|MAN_TRANS_Z;
1309                                 BIF_setDualAxisConstraint(v3d->twmat[1], v3d->twmat[2]);
1310                         }
1311                         else
1312                                 BIF_setSingleAxisConstraint(v3d->twmat[0], " dX");
1313                         ManipulatorTransform(TFM_TRANSLATION);
1314                         break;
1315                 case MAN_TRANS_Y:
1316                         if(G.qual & LR_SHIFTKEY) {
1317                                 Gval= MAN_TRANS_X|MAN_TRANS_Z;
1318                                 BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[2]);
1319                         }
1320                         else
1321                                 BIF_setSingleAxisConstraint(v3d->twmat[1], " dY");
1322                         ManipulatorTransform(TFM_TRANSLATION);
1323                         break;
1324                 case MAN_TRANS_Z:
1325                         if(G.qual & LR_SHIFTKEY) {
1326                                 Gval= MAN_TRANS_X|MAN_TRANS_Y;
1327                                 BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[1]);
1328                         }
1329                         else
1330                                 BIF_setSingleAxisConstraint(v3d->twmat[2], " dZ");
1331                         ManipulatorTransform(TFM_TRANSLATION);
1332                         break;
1333                         
1334                 case MAN_SCALE_C:
1335                         ManipulatorTransform(TFM_RESIZE);
1336                         break;
1337                 case MAN_SCALE_X:
1338                         if(G.qual & LR_SHIFTKEY) {
1339                                 Gval= MAN_SCALE_Y|MAN_SCALE_Z;
1340                                 BIF_setDualAxisConstraint(v3d->twmat[1], v3d->twmat[2]);
1341                         }
1342                         else
1343                                 BIF_setSingleAxisConstraint(v3d->twmat[0], " SizeX");
1344                         ManipulatorTransform(TFM_RESIZE);
1345                         break;
1346                 case MAN_SCALE_Y:
1347                         if(G.qual & LR_SHIFTKEY) {
1348                                 Gval= MAN_SCALE_X|MAN_SCALE_Z;
1349                                 BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[2]);
1350                         }
1351                         else
1352                                 BIF_setSingleAxisConstraint(v3d->twmat[1], " SizeY");
1353                         ManipulatorTransform(TFM_RESIZE);
1354                         break;
1355                 case MAN_SCALE_Z:
1356                         if(G.qual & LR_SHIFTKEY) {
1357                                 Gval= MAN_SCALE_X|MAN_SCALE_Y;
1358                                 BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[1]);
1359                         }
1360                         else
1361                                 BIF_setSingleAxisConstraint(v3d->twmat[2], " SizeZ");
1362                         ManipulatorTransform(TFM_RESIZE);
1363                         break;
1364                 
1365                 case MAN_ROT_X:
1366                         BIF_setSingleAxisConstraint(v3d->twmat[0], " RotX");
1367                         ManipulatorTransform(TFM_ROTATION);
1368                         break;
1369                 case MAN_ROT_Y:
1370                         BIF_setSingleAxisConstraint(v3d->twmat[1], " RotY");
1371                         ManipulatorTransform(TFM_ROTATION);
1372                         break;
1373                 case MAN_ROT_Z:
1374                         BIF_setSingleAxisConstraint(v3d->twmat[2], " RotZ");
1375                         ManipulatorTransform(TFM_ROTATION);
1376                         break;
1377                 case MAN_ROT_T:
1378                         ManipulatorTransform(TFM_TRACKBALL);
1379                         break;                  
1380                 case MAN_ROT_V:
1381                         ManipulatorTransform(TFM_ROTATION);
1382                         break;
1383                 }
1384                 
1385                 /* cycling orientation modus */
1386                 getmouseco_areawin(mval);
1387                 if(val==MAN_ROT_V || val==MAN_SCALE_C || val==MAN_TRANS_C) {
1388                         if(mvalo[0]==mval[0] && mvalo[1]==mval[1]) {
1389                                 if(v3d->twmode==V3D_MANIPULATOR_GLOBAL)
1390                                         v3d->twmode= V3D_MANIPULATOR_LOCAL;
1391                                 else if(v3d->twmode==V3D_MANIPULATOR_LOCAL)
1392                                         if(G.obedit || G.obpose) v3d->twmode= V3D_MANIPULATOR_NORMAL;
1393                                         else v3d->twmode= V3D_MANIPULATOR_GLOBAL;
1394                                 else if(v3d->twmode==V3D_MANIPULATOR_NORMAL)
1395                                         v3d->twmode= V3D_MANIPULATOR_GLOBAL;
1396                                 
1397                         }
1398                 }
1399                 
1400         }
1401         Gval= 0xFFFF;
1402         
1403         return val;
1404 }
1405
1406