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