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