Removed casting warnings from transform_manipulator.
[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, and drawing flags */
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 /* color codes */
106
107 #define MAN_RGB         0
108 #define MAN_GREY        1
109 #define MAN_MOVECOL     2
110
111 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING  */
112 extern TransInfo Trans;
113
114
115 static int is_mat4_flipped(float mat[][4])
116 {
117         float vec[3];
118         
119         Crossf(vec, mat[0], mat[1]);
120         if( Inpf(vec, mat[2]) < 0.0 ) return 1;
121         return 0;
122 }       
123
124 /* transform widget center calc helper for below */
125 static void calc_tw_center(float *co)
126 {
127         float *twcent= G.scene->twcent;
128         float *min= G.scene->twmin;
129         float *max= G.scene->twmax;
130         
131         DO_MINMAX(co, min, max);
132         VecAddf(twcent, twcent, co);
133 }
134
135 /* callback */
136 static void stats_pose(ListBase *lb, float *normal, float *plane)
137 {
138         Bone *bone;
139         float vec[3], mat[4][4];
140         
141         for(bone= lb->first; bone; bone= bone->next) {
142                 if (bone->flag & BONE_SELECTED) {
143                         /* We don't let IK children get "grabbed" */
144                         /* ALERT! abusive global Trans here */
145                         if ( (Trans.mode!=TFM_TRANSLATION) || (bone->flag & BONE_IK_TOPARENT)==0 ) {
146                                 
147                                 get_bone_root_pos (bone, vec, 1);
148                                 
149                                 calc_tw_center(vec);
150                                 where_is_bone(G.obpose, bone);
151                                 get_objectspace_bone_matrix(bone, mat, 1, 1);   // points in negative Y o_O
152                                         
153                                 VecAddf(normal, normal, mat[2]);
154                                 VecAddf(plane, plane, mat[1]);
155                                 
156                                 return; // see above function
157                         }
158                 }
159                 stats_pose(&bone->childbase, normal, plane);
160         }
161 }
162
163
164 /* centroid, boundbox, of selection */
165 /* returns total items selected */
166 static int calc_manipulator(ScrArea *sa)
167 {
168         extern ListBase editNurb;
169         View3D *v3d= sa->spacedata.first;
170         Base *base;
171         Object *ob=NULL;
172         float normal[3]={0.0, 0.0, 0.0};
173         float plane[3]={0.0, 0.0, 0.0};
174         int a, totsel=0;
175         
176         /* transform widget matrix */
177         Mat4One(v3d->twmat);
178         
179         /* transform widget centroid/center */
180         G.scene->twcent[0]= G.scene->twcent[1]= G.scene->twcent[2]= 0.0f;
181         INIT_MINMAX(G.scene->twmin, G.scene->twmax);
182         
183         if(G.obedit) {
184                 ob= G.obedit;
185                 
186                 if(G.obedit->type==OB_MESH) {
187                         EditMesh *em = G.editMesh;
188                         EditVert *eve;
189                         
190                         for(eve= em->verts.first; eve; eve= eve->next) {
191                                 if(eve->f & SELECT) {
192                                         totsel++;
193                                         calc_tw_center(eve->co);
194                                 }
195                         }
196                         if(v3d->twmode == V3D_MANIP_NORMAL) {
197                                 EditFace *efa;
198                                 float vec[3];
199                                 for(efa= em->faces.first; efa; efa= efa->next) {
200                                         if(efa->f & SELECT) {
201                                                 VecAddf(normal, normal, efa->n);
202                                                 VecSubf(vec, efa->v2->co, efa->v1->co);
203                                                 VecAddf(plane, plane, vec);
204                                         }
205                                 }
206                         }
207                 }
208                 else if (G.obedit->type==OB_ARMATURE){
209                         EditBone *ebo;
210                         for (ebo=G.edbo.first;ebo;ebo=ebo->next){
211                                 
212                                 //      If this is an IK child and it's parent is being moved, don't count as selected
213                                 if ((ebo->flag & BONE_IK_TOPARENT)&& (ebo->flag & BONE_ROOTSEL) && ebo->parent && (ebo->parent->flag & BONE_TIPSEL));
214                                 else {
215                                         if (ebo->flag & BONE_TIPSEL) {
216                                                 calc_tw_center(ebo->tail);
217                                                 totsel++;
218                                         }
219                                         if (ebo->flag & BONE_ROOTSEL) {
220                                                 calc_tw_center(ebo->head);
221                                                 totsel++;
222                                         }
223                                 }
224                         }
225                 }
226                 else if ELEM3(G.obedit->type, OB_CURVE, OB_SURF, OB_FONT) {
227                         Nurb *nu;
228                         BezTriple *bezt;
229                         BPoint *bp;
230                         
231                         nu= editNurb.first;
232                         while(nu) {
233                                 if((nu->type & 7)==CU_BEZIER) {
234                                         bezt= nu->bezt;
235                                         a= nu->pntsu;
236                                         while(a--) {
237                                                 if(bezt->f1) {
238                                                         calc_tw_center(bezt->vec[0]);
239                                                         totsel++;
240                                                 }
241                                                 if(bezt->f2) {
242                                                         calc_tw_center(bezt->vec[1]);
243                                                         totsel++;
244                                                 }
245                                                 if(bezt->f3) {
246                                                         calc_tw_center(bezt->vec[2]);
247                                                         totsel++;
248                                                 }
249                                                 bezt++;
250                                         }
251                                 }
252                                 else {
253                                         bp= nu->bp;
254                                         a= nu->pntsu*nu->pntsv;
255                                         while(a--) {
256                                                 if(bp->f1 & 1) {
257                                                         calc_tw_center(bp->vec);
258                                                         totsel++;
259                                                 }
260                                                 bp++;
261                                         }
262                                 }
263                                 nu= nu->next;
264                         }
265                 }
266                 else if(G.obedit->type==OB_MBALL) {
267                         /* editmball.c */
268                         extern ListBase editelems;  /* go away ! */
269                         MetaElem *ml;
270                 
271                         ml= editelems.first;
272                         while(ml) {
273                                 if(ml->flag & SELECT) {
274                                         calc_tw_center(&ml->x);
275                                         totsel++;
276                                 }
277                                 ml= ml->next;
278                         }
279                 }
280                 else if(G.obedit->type==OB_LATTICE) {
281                         BPoint *bp;
282                         bp= editLatt->def;
283                         
284                         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
285                         while(a--) {
286                                 if(bp->f1 & 1) {
287                                         calc_tw_center(bp->vec);
288                                         totsel++;
289                                 }
290                                 bp++;
291                         }
292                 }
293                 
294                 /* selection center */
295                 if(totsel) {
296                         VecMulf(G.scene->twcent, 1.0f/(float)totsel);   // centroid!
297                         Mat4MulVecfl(G.obedit->obmat, G.scene->twcent);
298                         Mat4MulVecfl(G.obedit->obmat, G.scene->twmin);
299                         Mat4MulVecfl(G.obedit->obmat, G.scene->twmax);
300                 }
301         }
302         else if(G.obpose) {
303                 bArmature *arm= G.obpose->data;
304                 
305                 ob= G.obpose;
306                 Trans.mode= TFM_ROTATION;       // mislead counting bones... bah
307                 
308                 /* count total */
309                 count_bone_select(&arm->bonebase, &totsel);
310                 if(totsel) {
311                         /* recursive get stats */
312                         stats_pose(&arm->bonebase, normal, plane);
313                         
314                         //VecMulf(normal, -1.0);
315                         VecMulf(plane, -1.0);
316                         
317                         VecMulf(G.scene->twcent, 1.0f/(float)totsel);   // centroid!
318                         Mat4MulVecfl(G.obpose->obmat, G.scene->twcent);
319                         Mat4MulVecfl(G.obpose->obmat, G.scene->twmin);
320                         Mat4MulVecfl(G.obpose->obmat, G.scene->twmax);
321                 }
322         }
323         else if(G.f & (G_FACESELECT + G_VERTEXPAINT + G_TEXTUREPAINT +G_WEIGHTPAINT)) {
324                 ;
325         }
326         else {
327                 
328                 /* we need the one selected object, if its not active */
329                 ob= OBACT;
330                 if(ob && !(ob->flag & SELECT)) ob= NULL;
331                 
332                 base= (G.scene->base.first);
333                 while(base) {
334                         if(v3d->lay & base->lay) {
335                                 
336                                 if(base->flag & SELECT) {
337                                         if(ob==NULL) ob= base->object;
338                                         calc_tw_center(base->object->obmat[3]);
339                                         totsel++;
340                                 }
341                         }
342                         base= base->next;
343                 }
344                 
345                 /* selection center */
346                 if(totsel) {
347                         VecMulf(G.scene->twcent, 1.0f/(float)totsel);   // centroid!
348                 }
349         }
350         
351         /* global, local or normal orientation? */
352         if(ob && totsel) {
353                 
354                 switch(v3d->twmode) {
355                 case V3D_MANIP_GLOBAL:
356                         break;
357                         
358                 case V3D_MANIP_NORMAL:
359                         if(G.obedit || G.obpose) {
360                                 if(normal[0]!=0.0 || normal[1]!=0.0 || normal[2]!=0.0) {
361                                         float mat[3][3];
362                                         
363                                         Normalise(normal);
364                                         Normalise(plane);
365                                         VECCOPY(mat[2], normal);
366                                         Crossf(mat[0], normal, plane);
367                                         Crossf(mat[1], mat[2], mat[0]);
368                                         
369                                         Mat4MulMat43(v3d->twmat, ob->obmat, mat);
370                                         Mat4Ortho(v3d->twmat);
371                                         
372                                         break;
373                                 }
374                         }
375                         /* no break we define 'normal' as 'local' in Object mode */
376                 case V3D_MANIP_LOCAL:
377                         if(totsel==1 || v3d->around==V3D_LOCAL || G.obedit || G.obpose) {
378                                 Mat4CpyMat4(v3d->twmat, ob->obmat);
379                                 Mat4Ortho(v3d->twmat);
380                         }
381                         break;
382                 }               
383         }
384            
385         return totsel;
386 }
387
388 /* ******************** DRAWING STUFFIES *********** */
389
390 /* radring = radius of donut rings
391    radhole = radius hole
392    start = starting segment (based on nrings)
393    end   = end segment
394    nsides = amount of points in ring
395    nrigns = amount of rings
396 */
397 static void partial_donut(float radring, float radhole, int start, int end, int nsides, int nrings)
398 {
399         float theta, phi, theta1;
400         float cos_theta, sin_theta;
401         float cos_theta1, sin_theta1;
402         float ring_delta, side_delta;
403         int i, j;
404         
405         ring_delta= 2.0f*(float)M_PI/(float)nrings;
406         side_delta= 2.0f*(float)M_PI/(float)nsides;
407         
408         theta= (float)M_PI+0.5f*ring_delta;
409         cos_theta= (float)cos(theta);
410         sin_theta= (float)sin(theta);
411         
412         for(i= nrings - 1; i >= 0; i--) {
413                 theta1= theta + ring_delta;
414                 cos_theta1= (float)cos(theta1);
415                 sin_theta1= (float)sin(theta1);
416                 
417                 if(i==start) {  // cap
418                         glBegin(GL_POLYGON);
419                         glNormal3f(-sin_theta1, -cos_theta1, 0.0);
420                         phi= 0.0;
421                         for(j= nsides; j >= 0; j--) {
422                                 float cos_phi, sin_phi, dist;
423                                 
424                                 phi += side_delta;
425                                 cos_phi= (float)cos(phi);
426                                 sin_phi= (float)sin(phi);
427                                 dist= radhole + radring * cos_phi;
428                                 
429                                 glVertex3f(cos_theta1 * dist, -sin_theta1 * dist,  radring * sin_phi);
430                         }
431                         glEnd();
432                 }
433                 if(i>=start && i<=end) {
434                         glBegin(GL_QUAD_STRIP);
435                         phi= 0.0;
436                         for(j= nsides; j >= 0; j--) {
437                                 float cos_phi, sin_phi, dist;
438                                 
439                                 phi += side_delta;
440                                 cos_phi= (float)cos(phi);
441                                 sin_phi= (float)sin(phi);
442                                 dist= radhole + radring * cos_phi;
443                                 
444                                 glNormal3f(cos_theta1 * cos_phi, -sin_theta1 * cos_phi, sin_phi);
445                                 glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi);
446                                 glNormal3f(cos_theta * cos_phi, -sin_theta * cos_phi, sin_phi);
447                                 glVertex3f(cos_theta * dist, -sin_theta * dist,  radring * sin_phi);
448                         }
449                         glEnd();
450                 }
451                 
452                 if(i==end) {    // cap
453                         glBegin(GL_POLYGON);
454                         glNormal3f(sin_theta, cos_theta, 0.0);
455                         phi= 0.0;
456                         for(j= nsides; j >= 0; j--) {
457                                 float cos_phi, sin_phi, dist;
458                                 
459                                 phi -= side_delta;
460                                 cos_phi= (float)cos(phi);
461                                 sin_phi= (float)sin(phi);
462                                 dist= radhole + radring * cos_phi;
463                                 
464                                 glVertex3f(cos_theta * dist, -sin_theta * dist,  radring * sin_phi);
465                         }
466                         glEnd();
467                 }
468                 
469                 
470                 theta= theta1;
471                 cos_theta= cos_theta1;
472                 sin_theta= sin_theta1;
473         }
474 }
475
476 /* three colors can be set;
477    grey for ghosting
478    moving: in transform theme color
479    else the red/green/blue
480 */
481 static void manipulator_setcolor(char axis, int colcode)
482 {
483         float vec[4];
484         
485         vec[3]= 0.7f; // alpha set on 0.5, can be glEnabled or not
486         
487         if(colcode==MAN_GREY) {
488                 if(axis > 'Z') glColor4ub(0, 0, 0, 70);
489                 else {
490                         vec[0]= vec[1]= vec[2]= 1.0f; vec[3]= 0.3f;
491                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
492                 }
493         }
494         else if(colcode==MAN_MOVECOL) {
495                 if(axis > 'Z') BIF_ThemeColor(TH_TRANSFORM);
496                 else {
497                         BIF_GetThemeColor3fv(TH_TRANSFORM, vec);
498                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
499                 }
500         }
501         else {
502                 switch(axis) {
503                 case 'x':
504                         glColor3ub(255, 0, 100);
505                         break;
506                 case 'y':
507                         glColor3ub(100, 255, 100);
508                         break;
509                 case 'z':
510                         glColor3ub(50, 50, 225);
511                         break;
512                 case 'X':
513                         vec[2]= vec[1]= 0.0f; vec[0]= 1.0f;
514                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
515                         break;
516                 case 'Y':
517                         vec[0]= vec[2]= 0.0f; vec[1]= 1.0f;
518                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
519                         break;
520                 case 'Z':
521                         vec[0]= vec[1]= 0.0f; vec[2]= 1.0f;
522                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
523                         break;
524                 case 'C':
525                         BIF_GetThemeColor3fv(TH_TRANSFORM, vec);
526                         if(G.vd->twmode == V3D_MANIP_LOCAL) {vec[0]+= 0.25f; vec[1]+=0.25f; vec[2]+=0.25f;}
527                         else if(G.vd->twmode == V3D_MANIP_NORMAL) {vec[0]-= 0.2f; vec[1]-=0.2f; vec[2]-=0.2f;}
528                         glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
529                         break;
530                 }
531         }
532 }
533
534 /* viewmatrix should have been set OK, also no shademode! */
535 static void draw_manipulator_axes(int colcode, int flagx, int flagy, int flagz)
536 {
537         
538         /* axes */
539         if(flagx) {
540                 manipulator_setcolor('x', colcode);
541                 glBegin(GL_LINES);
542                 glVertex3f(0.0, 0.0, 0.0);
543                 glVertex3f(1.0, 0.0, 0.0);
544                 glEnd();
545         }               
546         if(flagy) {
547                 manipulator_setcolor('y', colcode);
548                 glBegin(GL_LINES);
549                 glVertex3f(0.0, 0.0, 0.0);
550                 glVertex3f(0.0, 1.0, 0.0);
551                 glEnd();
552         }               
553         if(flagz) {
554                 manipulator_setcolor('z', colcode);
555                 glBegin(GL_LINES);
556                 glVertex3f(0.0, 0.0, 0.0);
557                 glVertex3f(0.0, 0.0, 1.0);
558                 glEnd();
559         }
560 }
561
562 /* only called while G.moving */
563 static void draw_manipulator_rotate_ghost(float mat[][4], int drawflags)
564 {
565         GLUquadricObj *qobj= gluNewQuadric(); 
566         float size, phi, vec[3], matt[4][4], cross[3];
567         
568         glDisable(GL_DEPTH_TEST);
569         gluQuadricDrawStyle(qobj, GLU_FILL); 
570         
571         glColor4ub(0,0,0,64);
572         glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
573         glEnable(GL_BLEND);
574                 
575         /* we need both [4][4] transforms, Trans.mat seems to be premul, not post for mat[][4] */
576         Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
577         Mat4MulMat34(matt, Trans.mat, mat);
578
579         /* Screen aligned view rot circle */
580         if(drawflags & MAN_ROT_V) {
581                 float startphi;
582                 
583                 /* prepare for screen aligned draw */
584                 VECCOPY(vec, mat[0]);
585                 size= Normalise(vec);
586                 glPushMatrix();
587                 glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
588                 
589                 /* sets view screen aligned */
590                 glRotatef( -360.0f*saacos(G.vd->viewquat[0])/(float)M_PI, G.vd->viewquat[1], G.vd->viewquat[2], G.vd->viewquat[3]);
591         
592                 vec[0]= (float)(Trans.imval[0] - Trans.center2d[0]);
593                 vec[1]= (float)(Trans.imval[1] - Trans.center2d[1]);
594                 vec[2]= 0.0f;
595                 Normalise(vec);
596                 
597                 startphi= saacos( vec[1] );
598                 if(vec[0]<0.0) startphi= -startphi;
599                 
600                 phi= (float)fmod(-180.0*Trans.val/M_PI, 360.0);
601                 if(phi > 180.0) phi-= 360.0;
602                 else if(phi<-180.0) phi+= 360.0;
603                 
604                 gluPartialDisk(qobj, 0.0, size, 32, 1, 180.0*startphi/M_PI, phi);
605                 
606                 glPopMatrix();
607         }
608         
609         
610         mymultmatrix(mat);      // aligns with original widget
611         
612         /* Z disk */
613         if(drawflags & MAN_ROT_Z) {
614                 VECCOPY(vec, mat[0]);   // use x axis to detect rotation
615                 Normalise(vec);
616                 Normalise(matt[0]);
617                 phi= saacos( Inpf(vec, matt[0]) );
618                 if(phi!=0.0) {
619                         Crossf(cross, vec, matt[0]);    // results in z vector
620                         if(Inpf(cross, mat[2]) > 0.0) phi= -phi;
621                         gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 90.0, 180.0*phi/M_PI);
622                 }
623         }
624         /* X disk */
625         if(drawflags & MAN_ROT_X) {
626                 VECCOPY(vec, mat[1]);   // use y axis to detect rotation
627                 Normalise(vec);
628                 Normalise(matt[1]);
629                 phi= saacos( Inpf(vec, matt[1]) );
630                 if(phi!=0.0) {
631                         Crossf(cross, vec, matt[1]);    // results in x vector
632                         if(Inpf(cross, mat[0]) > 0.0) phi= -phi;
633                         glRotatef(90.0, 0.0, 1.0, 0.0);
634                         gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 0.0, 180.0*phi/M_PI);
635                         glRotatef(-90.0, 0.0, 1.0, 0.0);
636                 }
637         }       
638         /* Y circle */
639         if(drawflags & MAN_ROT_Y) {
640                 VECCOPY(vec, mat[2]);   // use z axis to detect rotation
641                 Normalise(vec);
642                 Normalise(matt[2]);
643                 phi= saacos( Inpf(vec, matt[2]) );
644                 if(phi!=0.0) {
645                         Crossf(cross, vec, matt[2]);    // results in y vector
646                         if(Inpf(cross, mat[1]) > 0.0) phi= -phi;
647                         glRotatef(-90.0, 1.0, 0.0, 0.0);
648                         gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 180.0, 180.0*phi/M_PI);
649                         glRotatef(90.0, 1.0, 0.0, 0.0);
650                 }
651         }
652         
653         glDisable(GL_BLEND);
654         myloadmatrix(G.vd->viewmat);
655 }
656
657 static void draw_manipulator_rotate(float mat[][4], int moving, int drawflags, int combo)
658 {
659         GLUquadricObj *qobj= gluNewQuadric(); 
660         double plane[4];
661         float size, vec[3], unitmat[4][4];
662         float cywid= 0.33f*0.01f*(float)U.tw_handlesize;        
663         float cusize= cywid*0.65f;
664         int arcs= (G.rt==2);
665         int colcode;
666         
667         if(moving) colcode= MAN_MOVECOL;
668         else colcode= MAN_RGB;
669         
670         if(G.rt==3) cusize= cywid*0.3f;
671         
672         /* when called while moving in mixed mode, do not draw when... */
673         if((drawflags & MAN_ROT_C)==0) return;
674         
675         /* Init stuff */
676         glDisable(GL_DEPTH_TEST);
677         Mat4One(unitmat);
678         gluQuadricDrawStyle(qobj, GLU_FILL); 
679         gluQuadricNormals(qobj, GLU_SMOOTH);
680         glEnable(GL_CULL_FACE);         // backface removal
681         glShadeModel(GL_SMOOTH);
682         
683         
684         /* prepare for screen aligned draw */
685         VECCOPY(vec, mat[0]);
686         size= Normalise(vec);
687         glPushMatrix();
688         glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
689         
690         if(arcs) {
691                 /* clipplane makes nice handles, calc here because of multmatrix but with translate! */
692                 VECCOPY(plane, G.vd->viewinv[2]);
693                 plane[3]= -0.1; // clip more
694                 glClipPlane(GL_CLIP_PLANE0, plane);
695         }
696         /* sets view screen aligned */
697         glRotatef( -360.0f*saacos(G.vd->viewquat[0])/(float)M_PI, G.vd->viewquat[1], G.vd->viewquat[2], G.vd->viewquat[3]);
698         
699         /* Screen aligned help circle */
700         if(arcs) {
701                 if((G.f & G_PICKSEL)==0) {
702                         BIF_ThemeColorShade(TH_BACK, -30);
703                         drawcircball(unitmat[3], size, unitmat);
704                 }
705         }
706         /* Screen aligned view rot circle */
707         if(drawflags & MAN_ROT_V) {
708                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
709                 BIF_ThemeColor(TH_TRANSFORM);
710                 drawcircball(unitmat[3], 1.2f*size, unitmat);
711                 
712                 if(moving) {    
713                         float vec[3];
714                         vec[0]= (float)(Trans.imval[0] - Trans.center2d[0]);
715                         vec[1]= (float)(Trans.imval[1] - Trans.center2d[1]);
716                         vec[2]= 0.0f;
717                         Normalise(vec);
718                         VecMulf(vec, 1.2f*size);
719                         glBegin(GL_LINES);
720                         glVertex3f(0.0f, 0.0f, 0.0f);
721                         glVertex3fv(vec);
722                         glEnd();
723                 }
724         }
725         glPopMatrix();
726         
727         /* apply the transform delta */
728         if(moving) {
729                 float matt[4][4];
730                 Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
731                 Mat4MulMat34(matt, Trans.mat, mat);
732                 mymultmatrix(matt);
733                 glFrontFace( is_mat4_flipped(matt)?GL_CW:GL_CCW);
734         }
735         else {
736                 glFrontFace( is_mat4_flipped(mat)?GL_CW:GL_CCW);
737                 mymultmatrix(mat);
738         }
739         
740         /* axes */
741         if(arcs==0) {
742                 if(!(G.f & G_PICKSEL)) {
743                         if( (combo & V3D_MANIP_SCALE)==0) {
744                                 /* axis */
745                                 glBegin(GL_LINES);
746                                 if( (drawflags & MAN_ROT_X) || (moving && (drawflags & MAN_ROT_Z)) ) {
747                                         manipulator_setcolor('x', colcode);
748                                         glVertex3f(0.0, 0.0, 0.0);
749                                         glVertex3f(1.0, 0.0, 0.0);
750                                 }               
751                                 if( (drawflags & MAN_ROT_Y) || (moving && (drawflags & MAN_ROT_X)) ) {
752                                         manipulator_setcolor('y', colcode);
753                                         glVertex3f(0.0, 0.0, 0.0);
754                                         glVertex3f(0.0, 1.0, 0.0);
755                                 }               
756                                 if( (drawflags & MAN_ROT_Z) || (moving && (drawflags & MAN_ROT_Y)) ) {
757                                         manipulator_setcolor('z', colcode);
758                                         glVertex3f(0.0, 0.0, 0.0);
759                                         glVertex3f(0.0, 0.0, 1.0);
760                                 }
761                                 glEnd();
762                         }
763                 }
764         }
765         
766         /* Trackball center */
767         if((drawflags & MAN_ROT_T) && (combo & V3D_MANIP_TRANSLATE)==0) {
768                 float smat[3][3], imat[3][3];
769                 float offset[3];
770                 
771                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_T);
772                 
773                 Mat3CpyMat4(smat, mat);
774                 Mat3Inv(imat, smat);
775
776                 getViewVector(mat[3], offset);
777                 Mat3MulVecfl(imat, offset);
778                 Normalise(offset);      // matrix space is such that 1.0 = size of sphere
779                 
780                 if(moving) {
781                         BIF_ThemeColor(TH_TRANSFORM);
782                         glBegin(GL_LINES);
783                         glVertex3f(0.0, 0.0, 0.0);
784                         glVertex3fv(offset);
785                         glEnd();
786                 }
787                 
788                 glEnable(GL_LIGHTING);
789                 
790                 VECCOPY(vec, offset);
791                 glTranslatef(vec[0], vec[1], vec[2]);
792                 manipulator_setcolor('C', colcode);
793                 gluSphere(qobj, cywid, 8, 6);
794                 
795                 /* restore */
796                 glTranslatef(-vec[0], -vec[1], -vec[2]);
797                 glDisable(GL_LIGHTING);
798         }
799         
800         if(arcs==0 && moving) {
801                 
802                 if(arcs) glEnable(GL_CLIP_PLANE0);
803
804                 /* Z circle */
805                 if(drawflags & MAN_ROT_Z) {
806                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
807                         manipulator_setcolor('z', colcode);
808                         drawcircball(unitmat[3], 1.0, unitmat);
809                 }
810                 /* X circle */
811                 if(drawflags & MAN_ROT_X) {
812                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
813                         glRotatef(90.0, 0.0, 1.0, 0.0);
814                         manipulator_setcolor('x', colcode);
815                         drawcircball(unitmat[3], 1.0, unitmat);
816                         glRotatef(-90.0, 0.0, 1.0, 0.0);
817                 }       
818                 /* Y circle */
819                 if(drawflags & MAN_ROT_Y) {
820                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
821                         glRotatef(-90.0, 1.0, 0.0, 0.0);
822                         manipulator_setcolor('y', colcode);
823                         drawcircball(unitmat[3], 1.0, unitmat);
824                         glRotatef(90.0, 1.0, 0.0, 0.0);
825                 }
826                 
827                 if(arcs) glDisable(GL_CLIP_PLANE0);
828         }
829         // donut arcs
830         if(arcs) {
831                 glEnable(GL_LIGHTING);
832                 glEnable(GL_CLIP_PLANE0);
833                 
834                 /* Z circle */
835                 if(drawflags & MAN_ROT_Z) {
836                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
837                         manipulator_setcolor('Z', colcode);
838                         partial_donut(cusize/3.0f, 1.0f, 0, 48, 8, 48);
839                 }
840                 /* X circle */
841                 if(drawflags & MAN_ROT_X) {
842                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
843                         glRotatef(90.0, 0.0, 1.0, 0.0);
844                         manipulator_setcolor('X', colcode);
845                         partial_donut(cusize/3.0f, 1.0f, 0, 48, 8, 48);
846                         glRotatef(-90.0, 0.0, 1.0, 0.0);
847                 }       
848                 /* Y circle */
849                 if(drawflags & MAN_ROT_Y) {
850                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
851                         glRotatef(-90.0, 1.0, 0.0, 0.0);
852                         manipulator_setcolor('Y', colcode);
853                         partial_donut(cusize/3.0f, 1.0f, 0, 48, 8, 48);
854                         glRotatef(90.0, 1.0, 0.0, 0.0);
855                 }
856                 
857                 glDisable(GL_CLIP_PLANE0);
858         }
859         
860         if(arcs==0) {
861                 glEnable(GL_LIGHTING);
862                 
863                 /* Z handle on X axis */
864                 if(drawflags & MAN_ROT_Z) {
865                         glPushMatrix();
866                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
867                         manipulator_setcolor('Z', colcode);
868
869                         if(G.rt==3) {
870                                 partial_donut(cusize, 1.0, 21, 27, 8, 48);
871
872                                 /* Z handle on Y axis */
873                                 glRotatef(90.0, 0.0, 0.0, 1.0);
874                                 partial_donut(cusize, 1.0, 21, 27, 8, 48);
875                         }
876                         else {
877                                 partial_donut(cusize, 1.0, 23, 25, 8, 48);
878                         }
879                         glPopMatrix();
880                 }       
881
882                 /* Y handle on X axis */
883                 if(drawflags & MAN_ROT_Y) {
884                         glPushMatrix();
885                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
886                         manipulator_setcolor('Y', colcode);
887                         
888                         if(G.rt==3) {
889                                 glRotatef(90.0, 1.0, 0.0, 0.0);
890                                 partial_donut(cusize, 1.0, 21, 27, 8, 48);
891                                 
892                                 /* Y handle on Z axis */
893                                 glRotatef(90.0, 0.0, 0.0, 1.0);
894                                 partial_donut(cusize, 1.0, 21, 27, 8, 48);
895                         }
896                         else {
897                                 glRotatef(90.0, 1.0, 0.0, 0.0);
898                                 glRotatef(90.0, 0.0, 0.0, 1.0);
899                                 partial_donut(cusize, 1.0, 23, 25, 8, 48);
900                         }
901                         
902                         glPopMatrix();
903                 }
904                 
905                 /* X handle on Z axis */
906                 if(drawflags & MAN_ROT_X) {
907                         glPushMatrix();
908                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
909                         manipulator_setcolor('X', colcode);
910                         
911                         if(G.rt==3) {
912                                 glRotatef(-90.0, 0.0, 1.0, 0.0);
913                                 partial_donut(cusize, 1.0, 21, 27, 8, 48);
914                                 
915                                 /* X handle on Y axis */
916                                 glRotatef(90.0, 0.0, 0.0, 1.0);
917                                 partial_donut(cusize, 1.0, 21, 27, 8, 48);
918                         }
919                         else {
920                                 glRotatef(-90.0, 0.0, 1.0, 0.0);
921                                 glRotatef(90.0, 0.0, 0.0, 1.0);
922                                 partial_donut(cusize, 1.0, 23, 25, 8, 48);
923                         }
924                         glPopMatrix();
925                 }
926                 
927         }
928         
929         /* restore */
930         myloadmatrix(G.vd->viewmat);
931         glDisable(GL_CULL_FACE);
932         glDisable(GL_LIGHTING);
933         glFrontFace(GL_CCW);
934         gluDeleteQuadric(qobj);
935         if(G.zbuf) glEnable(GL_DEPTH_TEST);             // shouldn't be global, tsk!
936         
937 }
938
939 static void draw_manipulator_scale(float mat[][4], int moving, int drawflags, int combo, int colcode)
940 {
941         float cywid= 0.33f*0.01f*(float)U.tw_handlesize;        
942         float cusize= cywid*0.75f, dz;
943         
944         /* when called while moving in mixed mode, do not draw when... */
945         if((drawflags & MAN_SCALE_C)==0) return;
946         
947         if(moving) {
948                 float matt[4][4];
949                 
950                 Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
951                 Mat4MulMat34(matt, Trans.mat, mat);
952                 mymultmatrix(matt);
953                 glFrontFace( is_mat4_flipped(matt)?GL_CW:GL_CCW);
954         }
955         else {
956                 mymultmatrix(mat);
957                 glFrontFace( is_mat4_flipped(mat)?GL_CW:GL_CCW);
958         }
959         
960         /* axis */
961         if( (G.f & G_PICKSEL)==0 ) {
962                 
963                 glDisable(GL_DEPTH_TEST);
964                 
965                 /* in combo mode, this is always drawn as first type */
966                 draw_manipulator_axes(colcode, drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z);
967
968                 /* only has to be set when not in picking */
969                 glEnable(GL_CULL_FACE);         // backface removal
970                 glEnable(GL_LIGHTING);
971                 glShadeModel(GL_SMOOTH);
972         }
973         
974         /* not in combo mode */
975         if( (combo & (V3D_MANIP_TRANSLATE|V3D_MANIP_ROTATE))==0) {
976                 /* center cube, do not add to selection when shift is pressed (planar constraint)  */
977                 if( (G.f & G_PICKSEL) && (G.qual & LR_SHIFTKEY)==0) glLoadName(MAN_SCALE_C);
978                 
979                 manipulator_setcolor('C', colcode);
980                 drawsolidcube(cusize);
981                 
982                 dz= 1.0;
983         }
984         else dz= 1.0f-3.0f*cusize;
985         
986         /* Z cube */
987         glTranslatef(0.0, 0.0, dz);
988         if(drawflags & MAN_SCALE_Z) {
989                 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z);
990                 manipulator_setcolor('Z', colcode);
991                 drawsolidcube(cusize);
992         }       
993         /* X cube */
994         glTranslatef(dz, 0.0, -dz);
995         if(drawflags & MAN_SCALE_X) {
996                 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_X);
997                 manipulator_setcolor('X', colcode);
998                 drawsolidcube(cusize);
999         }       
1000         /* Y cube */
1001         glTranslatef(-dz, dz, 0.0);
1002         if(drawflags & MAN_SCALE_Y) {
1003                 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y);
1004                 manipulator_setcolor('Y', colcode);
1005                 drawsolidcube(cusize);
1006         }
1007         
1008         glDisable(GL_CULL_FACE);
1009         glDisable(GL_LIGHTING);
1010         
1011         /* if shiftkey, center point as last, for selectbuffer order */
1012         if(G.f & G_PICKSEL) {
1013                 if(G.qual & LR_SHIFTKEY) {
1014                         glTranslatef(0.0, -dz, 0.0);
1015                         glLoadName(MAN_SCALE_C);
1016                         glBegin(GL_POINTS);
1017                         glVertex3f(0.0, 0.0, 0.0);
1018                         glEnd();
1019                 }
1020         }
1021         
1022         /* restore */
1023         myloadmatrix(G.vd->viewmat);
1024         
1025         if(G.zbuf) glEnable(GL_DEPTH_TEST);             // shouldn't be global, tsk!
1026         glFrontFace(GL_CCW);
1027 }
1028
1029 static void draw_cone(GLUquadricObj *qobj, float len, float width)
1030 {
1031         glTranslatef(0.0, 0.0, -0.5f*len);
1032         gluCylinder(qobj, width, 0.0, len, 8, 1);
1033         gluQuadricOrientation(qobj, GLU_INSIDE);
1034         gluDisk(qobj, 0.0, width, 8, 1); 
1035         gluQuadricOrientation(qobj, GLU_OUTSIDE);
1036         glTranslatef(0.0, 0.0, 0.5f*len);
1037 }
1038
1039 static void draw_cylinder(GLUquadricObj *qobj, float len, float width)
1040 {
1041         
1042         width*= 0.8f;   // just for beauty
1043         
1044         glTranslatef(0.0, 0.0, -0.5f*len);
1045         gluCylinder(qobj, width, width, len, 8, 1);
1046         gluQuadricOrientation(qobj, GLU_INSIDE);
1047         gluDisk(qobj, 0.0, width, 8, 1); 
1048         gluQuadricOrientation(qobj, GLU_OUTSIDE);
1049         glTranslatef(0.0, 0.0, len);
1050         gluDisk(qobj, 0.0, width, 8, 1); 
1051         glTranslatef(0.0, 0.0, -0.5f*len);
1052 }
1053
1054
1055 static void draw_manipulator_translate(float mat[][4], int moving, int drawflags, int combo, int colcode)
1056 {
1057         GLUquadricObj *qobj = gluNewQuadric(); 
1058         float cylen= 0.01f*(float)U.tw_handlesize;
1059         float cywid= 0.33f*cylen, dz;
1060         
1061         /* when called while moving in mixed mode, do not draw when... */
1062         if((drawflags & MAN_TRANS_C)==0) return;
1063         
1064         if(moving) glTranslatef(Trans.vec[0], Trans.vec[1], Trans.vec[2]);
1065         
1066         mymultmatrix(mat);
1067
1068         glDisable(GL_DEPTH_TEST);
1069         
1070         /* axis */
1071         if( (G.f & G_PICKSEL)==0 ) {
1072                 
1073                 // translate drawn as last, only axis when no combo
1074                 if(combo==V3D_MANIP_TRANSLATE)
1075                         draw_manipulator_axes(colcode, drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z);
1076         
1077                 /* only has to be set when not in picking */
1078                 gluQuadricDrawStyle(qobj, GLU_FILL); 
1079                 gluQuadricNormals(qobj, GLU_SMOOTH);
1080                 glEnable(GL_CULL_FACE);         // backface removal
1081                 glFrontFace( is_mat4_flipped(mat)?GL_CW:GL_CCW);
1082                 glEnable(GL_LIGHTING);
1083                 glShadeModel(GL_SMOOTH);
1084         }
1085         
1086         /* center sphere, do not add to selection when shift is pressed (planar constraint) */
1087         if( (G.f & G_PICKSEL) && (G.qual & LR_SHIFTKEY)==0) glLoadName(MAN_TRANS_C);
1088         
1089         manipulator_setcolor('C', colcode);
1090         gluSphere(qobj, cywid, 8, 6); 
1091         
1092         /* offset in combo mode */
1093         if(combo & (V3D_MANIP_ROTATE|V3D_MANIP_SCALE)) dz= 1.0f+cylen;
1094         else dz= 1.0f;
1095         
1096         /* Z Cone */
1097         glTranslatef(0.0, 0.0, dz);
1098         if(drawflags & MAN_TRANS_Z) {
1099                 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Z);
1100                 manipulator_setcolor('Z', colcode);
1101                 draw_cone(qobj, cylen, cywid);
1102         }       
1103         /* X Cone */
1104         glTranslatef(dz, 0.0, -dz);
1105         if(drawflags & MAN_TRANS_X) {
1106                 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_X);
1107                 glRotatef(90.0, 0.0, 1.0, 0.0);
1108                 manipulator_setcolor('X', colcode);
1109                 draw_cone(qobj, cylen, cywid);
1110                 glRotatef(-90.0, 0.0, 1.0, 0.0);
1111         }       
1112         /* Y Cone */
1113         glTranslatef(-dz, dz, 0.0);
1114         if(drawflags & MAN_TRANS_Y) {
1115                 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Y);
1116                 glRotatef(-90.0, 1.0, 0.0, 0.0);
1117                 manipulator_setcolor('Y', colcode);
1118                 draw_cone(qobj, cylen, cywid);
1119         }
1120
1121         /* restore */
1122         glDisable(GL_CULL_FACE);
1123         glDisable(GL_LIGHTING);
1124                 
1125         gluDeleteQuadric(qobj);
1126         myloadmatrix(G.vd->viewmat);
1127         glFrontFace(GL_CCW);
1128         
1129         if(G.zbuf) glEnable(GL_DEPTH_TEST);             // shouldn't be global, tsk!
1130         
1131 }
1132
1133 static void draw_manipulator_rotate_cyl(float mat[][4], int moving, int drawflags, int combo, int colcode)
1134 {
1135         GLUquadricObj *qobj = gluNewQuadric(); 
1136         float vec[3], size;
1137         float cylen= 0.01f*(float)U.tw_handlesize;
1138         float cywid= 0.33f*cylen;
1139         
1140         /* when called while moving in mixed mode, do not draw when... */
1141         if((drawflags & MAN_ROT_C)==0) return;
1142         
1143         /* prepare for screen aligned draw */
1144         VECCOPY(vec, mat[0]);
1145         size= Normalise(vec);
1146         glPushMatrix();
1147         glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
1148         
1149         /* sets view screen aligned */
1150         glRotatef( -360.0f*saacos(G.vd->viewquat[0])/(float)M_PI, G.vd->viewquat[1], G.vd->viewquat[2], G.vd->viewquat[3]);
1151         
1152         /* Screen aligned view rot circle */
1153         if(drawflags & MAN_ROT_V) {
1154                 float unitmat[4][4];
1155                 Mat4One(unitmat);
1156                 
1157                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
1158                 BIF_ThemeColor(TH_TRANSFORM);
1159                 drawcircball(unitmat[3], 1.2f*size, unitmat);
1160                 
1161                 if(moving) {
1162                         float vec[3];
1163                         vec[0]= (float)(Trans.imval[0] - Trans.center2d[0]);
1164                         vec[1]= (float)(Trans.imval[1] - Trans.center2d[1]);
1165                         vec[2]= 0.0f;
1166                         Normalise(vec);
1167                         VecMulf(vec, 1.2f*size);
1168                         glBegin(GL_LINES);
1169                         glVertex3f(0.0, 0.0, 0.0);
1170                         glVertex3fv(vec);
1171                         glEnd();
1172                 }
1173         }
1174         glPopMatrix();
1175         
1176         /* apply the transform delta */
1177         if(moving) {
1178                 float matt[4][4];
1179                 Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
1180                 if (Trans.flag & T_USES_MANIPULATOR) {
1181                         Mat4MulMat34(matt, Trans.mat, mat);
1182                 }
1183                 mymultmatrix(matt);
1184         }
1185         else {
1186                 mymultmatrix(mat);
1187         }
1188         
1189         glFrontFace( is_mat4_flipped(mat)?GL_CW:GL_CCW);
1190         glDisable(GL_DEPTH_TEST);
1191         
1192         /* axis */
1193         if( (G.f & G_PICKSEL)==0 ) {
1194                 
1195                 // only draw axis when combo didn't draw scale axes
1196                 if((combo & V3D_MANIP_SCALE)==0)
1197                         draw_manipulator_axes(colcode, drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z);
1198                 
1199                 /* only has to be set when not in picking */
1200                 gluQuadricDrawStyle(qobj, GLU_FILL); 
1201                 gluQuadricNormals(qobj, GLU_SMOOTH);
1202                 glEnable(GL_CULL_FACE);         // backface removal
1203                 glEnable(GL_LIGHTING);
1204                 glShadeModel(GL_SMOOTH);
1205         }
1206         
1207
1208         /* Trackball */
1209         if((drawflags & MAN_ROT_T) && (combo & V3D_MANIP_TRANSLATE)==0) {
1210                 float smat[3][3], imat[3][3];
1211                 float offset[3];
1212                 
1213                 Mat3CpyMat4(smat, mat);
1214                 Mat3Inv(imat, smat);
1215                 
1216                 getViewVector(mat[3], offset);
1217                 Mat3MulVecfl(imat, offset);
1218                 Normalise(offset);      // matrix space is such that 1.0 = size of sphere
1219                 
1220                 if(moving) {
1221                         glDisable(GL_LIGHTING);
1222                         BIF_ThemeColor(TH_TRANSFORM);
1223                         glBegin(GL_LINES);
1224                         glVertex3f(0.0, 0.0, 0.0);
1225                         glVertex3fv(offset);
1226                         glEnd();
1227                         glEnable(GL_LIGHTING);
1228                 }
1229                 
1230                 /* center sphere, do not add to selection when shift is pressed (planar constraint) */
1231                 if( (G.f & G_PICKSEL) && (G.qual & LR_SHIFTKEY)==0) glLoadName(MAN_ROT_T);
1232                 
1233                 VECCOPY(vec, offset);
1234                 glTranslatef(vec[0], vec[1], vec[2]);
1235                 manipulator_setcolor('C', colcode);
1236                 gluSphere(qobj, cywid, 8, 6);
1237                 
1238                 /* restore */
1239                 glTranslatef(-vec[0], -vec[1], -vec[2]);
1240         }
1241         
1242         /* Z cyl */
1243         glTranslatef(0.0, 0.0, 1.0);
1244         if(drawflags & MAN_ROT_Z) {
1245                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
1246                 manipulator_setcolor('Z', colcode);
1247                 draw_cylinder(qobj, cylen, cywid);
1248         }       
1249         /* X cyl */
1250         glTranslatef(1.0, 0.0, -1.0);
1251         if(drawflags & MAN_ROT_X) {
1252                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
1253                 glRotatef(90.0, 0.0, 1.0, 0.0);
1254                 manipulator_setcolor('X', colcode);
1255                 draw_cylinder(qobj, cylen, cywid);
1256                 glRotatef(-90.0, 0.0, 1.0, 0.0);
1257         }       
1258         /* Y cylinder */
1259         glTranslatef(-1.0, 1.0, 0.0);
1260         if(drawflags & MAN_ROT_Y) {
1261                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
1262                 glRotatef(-90.0, 1.0, 0.0, 0.0);
1263                 manipulator_setcolor('Y', colcode);
1264                 draw_cylinder(qobj, cylen, cywid);
1265         }
1266         
1267         /* restore */
1268         glDisable(GL_CULL_FACE);
1269         glDisable(GL_LIGHTING);
1270         glFrontFace(GL_CCW);
1271         
1272         gluDeleteQuadric(qobj);
1273         myloadmatrix(G.vd->viewmat);
1274         
1275         if(G.zbuf) glEnable(GL_DEPTH_TEST);             // shouldn't be global, tsk!
1276         
1277 }
1278
1279
1280 static float get_manipulator_drawsize(ScrArea *sa)
1281 {
1282         View3D *v3d= sa->spacedata.first;
1283         float size, vec[3], len1, len2;
1284         
1285         /* size calculus, depending ortho/persp settings, like initgrabz() */
1286         size= v3d->persmat[0][3]*v3d->twmat[3][0]+ v3d->persmat[1][3]*v3d->twmat[3][1]+ v3d->persmat[2][3]*v3d->twmat[3][2]+ v3d->persmat[3][3];
1287         
1288         VECCOPY(vec, v3d->persinv[0]);
1289         len1= Normalise(vec);
1290         VECCOPY(vec, v3d->persinv[1]);
1291         len2= Normalise(vec);
1292         
1293         size*= (0.01f*(float)U.tw_size)*(len1>len2?len1:len2);
1294         if(U.tw_flag & U_TW_ABSOLUTE) {
1295                 /* correct for relative window size */
1296                 if(sa->winx > sa->winy) size*= 1000.0f/(float)sa->winx;
1297                 else size*= 1000.0f/(float)sa->winy;
1298         }
1299         return size;
1300 }
1301
1302 /* exported to transform_constraints.c */
1303 /* mat, vec = default orientation and location */
1304 /* type = transform type */
1305 /* axis = x, y, z, c */
1306 /* col: 0 = colored, 1 = moving, 2 = ghost */
1307 void draw_manipulator_ext(ScrArea *sa, int type, char axis, int col, float vec[3], float mat[][3])
1308 {
1309         int drawflags= 0;
1310         float mat4[4][4];
1311         int colcode;
1312         
1313         Mat4CpyMat3(mat4, mat);
1314         VECCOPY(mat4[3], vec);
1315         
1316         Mat4MulFloat3((float *)mat4, get_manipulator_drawsize(sa));
1317         
1318         glEnable(GL_BLEND);     // let's do it transparent by default
1319         if(col==0) colcode= MAN_RGB;
1320         else if(col==1) colcode= MAN_MOVECOL;
1321         else colcode= MAN_GREY;
1322         
1323         
1324         if(type==TFM_ROTATION) {
1325                 if(axis=='x') drawflags= MAN_ROT_X;
1326                 else if(axis=='y') drawflags= MAN_ROT_Y;
1327                 else if(axis=='z') drawflags= MAN_ROT_Z;
1328                 else drawflags= MAN_ROT_C;
1329
1330                 draw_manipulator_rotate_cyl(mat4, col, drawflags, V3D_MANIP_ROTATE, colcode);
1331         }       
1332         else if(type==TFM_RESIZE) {
1333                 if(axis=='x') drawflags= MAN_SCALE_X;
1334                 else if(axis=='y') drawflags= MAN_SCALE_Y;
1335                 else if(axis=='z') drawflags= MAN_SCALE_Z;
1336                 else drawflags= MAN_SCALE_C;
1337
1338                 draw_manipulator_scale(mat4, col, drawflags, V3D_MANIP_SCALE, colcode);
1339         }       
1340         else {
1341                 if(axis=='x') drawflags= MAN_TRANS_X;
1342                 else if(axis=='y') drawflags= MAN_TRANS_Y;
1343                 else if(axis=='z') drawflags= MAN_TRANS_Z;
1344                 else drawflags= MAN_TRANS_C;
1345
1346                 draw_manipulator_translate(mat4, 0, drawflags, V3D_MANIP_TRANSLATE, colcode);
1347         }       
1348         
1349
1350         glDisable(GL_BLEND);
1351 }
1352
1353 /* main call, does calc centers & orientation too */
1354 /* uses global G.moving */
1355 static int drawflags= 0xFFFF;           // only for the calls below, belongs in scene...?
1356 void BIF_draw_manipulator(ScrArea *sa)
1357 {
1358         View3D *v3d= sa->spacedata.first;
1359         int totsel;
1360         
1361         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return;
1362         if(G.moving && (G.moving & G_TRANSFORM_MANIP)==0) return;
1363         
1364         if(G.moving==0) {
1365                 v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
1366                 
1367                 totsel= calc_manipulator(sa);
1368                 if(totsel==0) return;
1369                 
1370                 v3d->twflag |= V3D_DRAW_MANIPULATOR;
1371
1372                 /* now we can define centre */
1373                 switch(v3d->around) {
1374                 case V3D_CENTRE:
1375                 case V3D_LOCAL:
1376                         v3d->twmat[3][0]= (G.scene->twmin[0] + G.scene->twmax[0])/2.0f;
1377                         v3d->twmat[3][1]= (G.scene->twmin[1] + G.scene->twmax[1])/2.0f;
1378                         v3d->twmat[3][2]= (G.scene->twmin[2] + G.scene->twmax[2])/2.0f;
1379                         break;
1380                 case V3D_CENTROID:
1381                         VECCOPY(v3d->twmat[3], G.scene->twcent);
1382                         break;
1383                 case V3D_CURSOR:
1384                         VECCOPY(v3d->twmat[3], G.scene->cursor);
1385                         break;
1386                 }
1387                 
1388                 Mat4MulFloat3((float *)v3d->twmat, get_manipulator_drawsize(sa));
1389         }
1390         
1391         if(v3d->twflag & V3D_DRAW_MANIPULATOR) {
1392                 
1393                 if(v3d->twtype & V3D_MANIP_ROTATE) {
1394                         /* rotate has special ghosting draw, for pie chart */
1395                         if(G.moving) draw_manipulator_rotate_ghost(v3d->twmat, drawflags);
1396                         
1397                         if(G.moving) glEnable(GL_BLEND);
1398                         
1399                         if(G.rt==4) {
1400                                 if(G.moving) draw_manipulator_rotate_cyl(v3d->twmat, 1, drawflags, v3d->twtype, MAN_MOVECOL);
1401                                 else draw_manipulator_rotate_cyl(v3d->twmat, 0, drawflags, v3d->twtype, MAN_RGB);
1402                         }
1403                         else draw_manipulator_rotate(v3d->twmat, G.moving, drawflags, v3d->twtype);
1404                         
1405                         glDisable(GL_BLEND);
1406                 }
1407                 if(v3d->twtype & V3D_MANIP_SCALE) {
1408                         if(G.moving) {
1409                                 glEnable(GL_BLEND);
1410                                 draw_manipulator_scale(v3d->twmat, 0, drawflags, v3d->twtype, MAN_GREY);
1411                                 draw_manipulator_scale(v3d->twmat, 1, drawflags, v3d->twtype, MAN_MOVECOL);
1412                                 glDisable(GL_BLEND);
1413                         }
1414                         else draw_manipulator_scale(v3d->twmat, 0, drawflags, v3d->twtype, MAN_RGB);
1415                 }
1416                 if(v3d->twtype & V3D_MANIP_TRANSLATE) {
1417                         if(G.moving) {
1418                                 glEnable(GL_BLEND);
1419                                 draw_manipulator_translate(v3d->twmat, 0, drawflags, v3d->twtype, MAN_GREY);
1420                                 draw_manipulator_translate(v3d->twmat, 1, drawflags, v3d->twtype, MAN_MOVECOL);
1421                                 glDisable(GL_BLEND);
1422                         }
1423                         else draw_manipulator_translate(v3d->twmat, 0, drawflags, v3d->twtype, MAN_RGB);
1424                 }
1425         }
1426 }
1427
1428 static int manipulator_selectbuf(ScrArea *sa, float hotspot)
1429 {
1430         View3D *v3d= sa->spacedata.first;
1431         rctf rect;
1432         GLuint buffer[64];              // max 4 items per select, so large enuf
1433         short hits, mval[2];
1434         
1435         G.f |= G_PICKSEL;
1436         
1437         getmouseco_areawin(mval);
1438         rect.xmin= mval[0]-hotspot;
1439         rect.xmax= mval[0]+hotspot;
1440         rect.ymin= mval[1]-hotspot;
1441         rect.ymax= mval[1]+hotspot;
1442         
1443         /* get rid of overlay button matrix */
1444         persp(PERSP_VIEW);
1445         
1446         setwinmatrixview3d(&rect);
1447         Mat4MulMat4(v3d->persmat, v3d->viewmat, sa->winmat);
1448         
1449         glSelectBuffer( 64, buffer);
1450         glRenderMode(GL_SELECT);
1451         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1452         glPushName(-2);
1453         
1454         /* do the drawing */
1455         if(v3d->twtype & V3D_MANIP_ROTATE) {
1456                 if(G.rt==4) draw_manipulator_rotate_cyl(v3d->twmat, 0, MAN_ROT_C, v3d->twtype, MAN_RGB);
1457                 else draw_manipulator_rotate(v3d->twmat, 0, MAN_ROT_C, v3d->twtype);
1458         }
1459         if(v3d->twtype & V3D_MANIP_SCALE)
1460                 draw_manipulator_scale(v3d->twmat, 0, MAN_SCALE_C, v3d->twtype, MAN_RGB);
1461         if(v3d->twtype & V3D_MANIP_TRANSLATE)
1462                 draw_manipulator_translate(v3d->twmat, 0, MAN_TRANS_C, v3d->twtype, MAN_RGB);
1463         
1464         glPopName();
1465         hits= glRenderMode(GL_RENDER);
1466         
1467         G.f &= ~G_PICKSEL;
1468         setwinmatrixview3d(0);
1469         Mat4MulMat4(v3d->persmat, v3d->viewmat, sa->winmat);
1470         
1471         persp(PERSP_WIN);
1472         
1473         if(hits==1) return buffer[3];
1474         else if(hits>1) {
1475                 GLuint mindep, minval;
1476                 int a;
1477                 
1478                 /* we compare the hits in buffer, but value centers highest */
1479                 mindep= buffer[1];
1480                 minval= buffer[3];
1481
1482                 for(a=1; a<hits; a++) {
1483                         if(minval==MAN_TRANS_C || minval==MAN_SCALE_C) break;
1484                         
1485                         if(buffer[4*a + 3]==MAN_TRANS_C || buffer[4*a + 3]==MAN_SCALE_C || buffer[4*a + 1] < mindep) {
1486                                 mindep= buffer[4*a + 1];
1487                                 minval= buffer[4*a + 3];
1488                         }
1489                 }
1490                 return minval;
1491         }
1492         return 0;
1493 }
1494
1495 /* return 0; nothing happened */
1496 int BIF_do_manipulator(ScrArea *sa)
1497 {
1498         View3D *v3d= sa->spacedata.first;
1499         int val;
1500         
1501         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0;
1502         if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0;
1503         
1504         // find the hotspots first test narrow hotspot
1505         val= manipulator_selectbuf(sa, 0.5f*(float)U.tw_hotspot);
1506         if(val) {
1507                 short mvalo[2], mval[2];
1508                 
1509                 // drawflags still global, for drawing call above
1510                 drawflags= manipulator_selectbuf(sa, 0.2f*(float)U.tw_hotspot);
1511                 if(drawflags==0) drawflags= val;
1512                 
1513                 getmouseco_areawin(mvalo);
1514                 
1515                 switch(drawflags) {
1516                 case MAN_TRANS_C:
1517                         ManipulatorTransform(TFM_TRANSLATION);
1518                         break;
1519                 case MAN_TRANS_X:
1520                         if(G.qual & LR_SHIFTKEY) {
1521                                 drawflags= MAN_TRANS_Y|MAN_TRANS_Z;
1522                                 BIF_setDualAxisConstraint(v3d->twmat[1], v3d->twmat[2]);
1523                         }
1524                         else
1525                                 BIF_setSingleAxisConstraint(v3d->twmat[0], " dX");
1526                         ManipulatorTransform(TFM_TRANSLATION);
1527                         break;
1528                 case MAN_TRANS_Y:
1529                         if(G.qual & LR_SHIFTKEY) {
1530                                 drawflags= MAN_TRANS_X|MAN_TRANS_Z;
1531                                 BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[2]);
1532                         }
1533                         else
1534                                 BIF_setSingleAxisConstraint(v3d->twmat[1], " dY");
1535                         ManipulatorTransform(TFM_TRANSLATION);
1536                         break;
1537                 case MAN_TRANS_Z:
1538                         if(G.qual & LR_SHIFTKEY) {
1539                                 drawflags= MAN_TRANS_X|MAN_TRANS_Y;
1540                                 BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[1]);
1541                         }
1542                         else
1543                                 BIF_setSingleAxisConstraint(v3d->twmat[2], " dZ");
1544                         ManipulatorTransform(TFM_TRANSLATION);
1545                         break;
1546                         
1547                 case MAN_SCALE_C:
1548                         ManipulatorTransform(TFM_RESIZE);
1549                         break;
1550                 case MAN_SCALE_X:
1551                         if(G.qual & LR_SHIFTKEY) {
1552                                 drawflags= MAN_SCALE_Y|MAN_SCALE_Z;
1553                                 BIF_setDualAxisConstraint(v3d->twmat[1], v3d->twmat[2]);
1554                         }
1555                         else
1556                                 BIF_setSingleAxisConstraint(v3d->twmat[0], " SizeX");
1557                         ManipulatorTransform(TFM_RESIZE);
1558                         break;
1559                 case MAN_SCALE_Y:
1560                         if(G.qual & LR_SHIFTKEY) {
1561                                 drawflags= MAN_SCALE_X|MAN_SCALE_Z;
1562                                 BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[2]);
1563                         }
1564                         else
1565                                 BIF_setSingleAxisConstraint(v3d->twmat[1], " SizeY");
1566                         ManipulatorTransform(TFM_RESIZE);
1567                         break;
1568                 case MAN_SCALE_Z:
1569                         if(G.qual & LR_SHIFTKEY) {
1570                                 drawflags= MAN_SCALE_X|MAN_SCALE_Y;
1571                                 BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[1]);
1572                         }
1573                         else
1574                                 BIF_setSingleAxisConstraint(v3d->twmat[2], " SizeZ");
1575                         ManipulatorTransform(TFM_RESIZE);
1576                         break;
1577                 
1578                 case MAN_ROT_X:
1579                         BIF_setSingleAxisConstraint(v3d->twmat[0], " RotX");
1580                         ManipulatorTransform(TFM_ROTATION);
1581                         break;
1582                 case MAN_ROT_Y:
1583                         BIF_setSingleAxisConstraint(v3d->twmat[1], " RotY");
1584                         ManipulatorTransform(TFM_ROTATION);
1585                         break;
1586                 case MAN_ROT_Z:
1587                         BIF_setSingleAxisConstraint(v3d->twmat[2], " RotZ");
1588                         ManipulatorTransform(TFM_ROTATION);
1589                         break;
1590                 case MAN_ROT_T:
1591                         ManipulatorTransform(TFM_TRACKBALL);
1592                         break;                  
1593                 case MAN_ROT_V:
1594                         ManipulatorTransform(TFM_ROTATION);
1595                         break;
1596                 }
1597                 
1598                 /* cycling orientation modus */
1599                 getmouseco_areawin(mval);
1600                 if(val==MAN_ROT_T || val==MAN_SCALE_C || val==MAN_TRANS_C) {
1601                         if(mvalo[0]==mval[0] && mvalo[1]==mval[1]) {
1602                                 if(v3d->twmode==V3D_MANIP_GLOBAL)
1603                                         v3d->twmode= V3D_MANIP_LOCAL;
1604                                 else if(v3d->twmode==V3D_MANIP_LOCAL)
1605                                         if(G.obedit || G.obpose) v3d->twmode= V3D_MANIP_NORMAL;
1606                                         else v3d->twmode= V3D_MANIP_GLOBAL;
1607                                 else if(v3d->twmode==V3D_MANIP_NORMAL)
1608                                         v3d->twmode= V3D_MANIP_GLOBAL;
1609                                 
1610                         }
1611                 }
1612                 
1613         }
1614         /* after transform, restore drawflags */
1615         drawflags= 0xFFFF;
1616         
1617         return val;
1618 }
1619
1620