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