Mitchell Stokes BGE MouseWarp patch + warning fix
[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_action.h"
59 #include "BKE_armature.h"
60 #include "BKE_context.h"
61 #include "BKE_global.h"
62 #include "BKE_lattice.h"
63 #include "BKE_mesh.h"
64 #include "BKE_object.h"
65 #include "BKE_particle.h"
66 #include "BKE_pointcache.h"
67 #include "BKE_utildefines.h"
68
69 #include "BLI_math.h"
70 #include "BLI_editVert.h"
71
72 #include "BIF_gl.h"
73
74 #include "WM_api.h"
75 #include "WM_types.h"
76
77 #include "ED_armature.h"
78 #include "ED_mesh.h"
79 #include "ED_particle.h"
80 #include "ED_space_api.h"
81 #include "ED_transform.h"
82 #include "ED_view3d.h"
83
84 #include "UI_resources.h"
85
86 /* local module include */
87 #include "transform.h"
88
89 /* return codes for select, and drawing flags */
90
91 #define MAN_TRANS_X             1
92 #define MAN_TRANS_Y             2
93 #define MAN_TRANS_Z             4
94 #define MAN_TRANS_C             7
95
96 #define MAN_ROT_X               8
97 #define MAN_ROT_Y               16
98 #define MAN_ROT_Z               32
99 #define MAN_ROT_V               64
100 #define MAN_ROT_T               128
101 #define MAN_ROT_C               248
102
103 #define MAN_SCALE_X             256
104 #define MAN_SCALE_Y             512
105 #define MAN_SCALE_Z             1024
106 #define MAN_SCALE_C             1792
107
108 /* color codes */
109
110 #define MAN_RGB         0
111 #define MAN_GHOST       1
112 #define MAN_MOVECOL     2
113
114
115 static int is_mat4_flipped(float mat[][4])
116 {
117         float vec[3];
118
119         cross_v3_v3v3(vec, mat[0], mat[1]);
120         if( dot_v3v3(vec, mat[2]) < 0.0 ) return 1;
121         return 0;
122 }
123
124 /* transform widget center calc helper for below */
125 static void calc_tw_center(Scene *scene, float *co)
126 {
127         float *twcent= scene->twcent;
128         float *min= scene->twmin;
129         float *max= scene->twmax;
130
131         DO_MINMAX(co, min, max);
132         add_v3_v3v3(twcent, twcent, co);
133 }
134
135 static void protectflag_to_drawflags(short protectflag, short *drawflags)
136 {
137         if(protectflag & OB_LOCK_LOCX)
138                 *drawflags &= ~MAN_TRANS_X;
139         if(protectflag & OB_LOCK_LOCY)
140                 *drawflags &= ~MAN_TRANS_Y;
141         if(protectflag & OB_LOCK_LOCZ)
142                 *drawflags &= ~MAN_TRANS_Z;
143
144         if(protectflag & OB_LOCK_ROTX)
145                 *drawflags &= ~MAN_ROT_X;
146         if(protectflag & OB_LOCK_ROTY)
147                 *drawflags &= ~MAN_ROT_Y;
148         if(protectflag & OB_LOCK_ROTZ)
149                 *drawflags &= ~MAN_ROT_Z;
150
151         if(protectflag & OB_LOCK_SCALEX)
152                 *drawflags &= ~MAN_SCALE_X;
153         if(protectflag & OB_LOCK_SCALEY)
154                 *drawflags &= ~MAN_SCALE_Y;
155         if(protectflag & OB_LOCK_SCALEZ)
156                 *drawflags &= ~MAN_SCALE_Z;
157 }
158
159 /* for pose mode */
160 static void stats_pose(Scene *scene, View3D *v3d, bPoseChannel *pchan)
161 {
162         Bone *bone= pchan->bone;
163
164         if(bone) {
165                 if (bone->flag & BONE_TRANSFORM) {
166                         calc_tw_center(scene, pchan->pose_head);
167                         protectflag_to_drawflags(pchan->protectflag, &v3d->twdrawflag);
168                 }
169         }
170 }
171
172 /* for editmode*/
173 static void stats_editbone(View3D *v3d, EditBone *ebo)
174 {
175         if (ebo->flag & BONE_EDITMODE_LOCKED)
176                 protectflag_to_drawflags(OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE, &v3d->twdrawflag);
177 }
178
179
180 static int test_rotmode_euler(short rotmode)
181 {
182         return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0:1;
183 }
184
185 void gimbal_axis(Object *ob, float gmat[][3])
186 {
187         if(ob->mode & OB_MODE_POSE)
188         {
189                 bPoseChannel *pchan= get_active_posechannel(ob);
190
191                 if(pchan && test_rotmode_euler(pchan->rotmode)) {
192                         float mat[3][3], tmat[3][3], obmat[3][3];
193
194                         eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
195
196                         /* apply bone transformation */
197                         mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
198                         
199                         if (pchan->parent)
200                         {
201                                 float parent_mat[3][3];
202
203                                 copy_m3_m4(parent_mat, pchan->parent->pose_mat);
204                                 mul_m3_m3m3(mat, parent_mat, tmat);
205
206                                 /* needed if object transformation isn't identity */
207                                 copy_m3_m4(obmat, ob->obmat);
208                                 mul_m3_m3m3(gmat, obmat, mat);
209                         }
210                         else
211                         {
212                                 /* needed if object transformation isn't identity */
213                                 copy_m3_m4(obmat, ob->obmat);
214                                 mul_m3_m3m3(gmat, obmat, tmat);
215                         }
216
217                         normalize_m3(gmat);
218                 }
219         }
220         else {
221                 if(test_rotmode_euler(ob->rotmode)) {
222                         
223                         
224                         if (ob->parent)
225                         {
226                                 float parent_mat[3][3], amat[3][3];
227                                 
228                                 eulO_to_gimbal_axis(amat, ob->rot, ob->rotmode);
229                                 copy_m3_m4(parent_mat, ob->parent->obmat);
230                                 normalize_m3(parent_mat);
231                                 mul_m3_m3m3(gmat, parent_mat, amat);
232                         }
233                         else
234                         {
235                                 eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
236                         }
237                 }
238         }
239 }
240
241
242 /* centroid, boundbox, of selection */
243 /* returns total items selected */
244 int calc_manipulator_stats(const bContext *C)
245 {
246         ScrArea *sa= CTX_wm_area(C);
247         ARegion *ar= CTX_wm_region(C);
248         Scene *scene= CTX_data_scene(C);
249         Object *obedit= CTX_data_edit_object(C);
250         View3D *v3d= sa->spacedata.first;
251         RegionView3D *rv3d= ar->regiondata;
252         Base *base;
253         Object *ob= OBACT;
254         int a, totsel= 0;
255
256         /* transform widget matrix */
257         unit_m4(rv3d->twmat);
258
259         v3d->twdrawflag= 0xFFFF;
260
261         /* transform widget centroid/center */
262         scene->twcent[0]= scene->twcent[1]= scene->twcent[2]= 0.0f;
263         INIT_MINMAX(scene->twmin, scene->twmax);
264
265         if(obedit) {
266                 ob= obedit;
267                 if((ob->lay & v3d->lay)==0) return 0;
268
269                 if(obedit->type==OB_MESH) {
270                         EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
271                         EditVert *eve;
272                         EditSelection ese;
273                         float vec[3]= {0,0,0};
274
275                         /* USE LAST SELECTE WITH ACTIVE */
276                         if (v3d->around==V3D_ACTIVE && EM_get_actSelection(em, &ese)) {
277                                 EM_editselection_center(vec, &ese);
278                                 calc_tw_center(scene, vec);
279                                 totsel= 1;
280                         } else {
281                                 /* do vertices for center, and if still no normal found, use vertex normals */
282                                 for(eve= em->verts.first; eve; eve= eve->next) {
283                                         if(eve->f & SELECT) {
284                                                 totsel++;
285                                                 calc_tw_center(scene, eve->co);
286                                         }
287                                 }
288                         }
289                 } /* end editmesh */
290                 else if (obedit->type==OB_ARMATURE){
291                         bArmature *arm= obedit->data;
292                         EditBone *ebo;
293                         for (ebo= arm->edbo->first; ebo; ebo=ebo->next){
294                                 if(ebo->layer & arm->layer) {
295                                         if (ebo->flag & BONE_TIPSEL) {
296                                                 calc_tw_center(scene, ebo->tail);
297                                                 totsel++;
298                                         }
299                                         if (ebo->flag & BONE_ROOTSEL) {
300                                                 calc_tw_center(scene, ebo->head);
301                                                 totsel++;
302                                         }
303                                         if (ebo->flag & BONE_SELECTED) {
304                                                 stats_editbone(v3d, ebo);
305                                         }
306                                 }
307                         }
308                 }
309                 else if ELEM(obedit->type, OB_CURVE, OB_SURF) {
310                         Curve *cu= obedit->data;
311                         Nurb *nu;
312                         BezTriple *bezt;
313                         BPoint *bp;
314
315                         nu= cu->editnurb->first;
316                         while(nu) {
317                                 if(nu->type == CU_BEZIER) {
318                                         bezt= nu->bezt;
319                                         a= nu->pntsu;
320                                         while(a--) {
321                                                 /* exceptions
322                                                  * if handles are hidden then only check the center points.
323                                                  * If 2 or more are selected then only use the center point too.
324                                                  */
325                                                 if (cu->drawflag & CU_HIDE_HANDLES) {
326                                                         if (bezt->f2 & SELECT) {
327                                                                 calc_tw_center(scene, bezt->vec[1]);
328                                                                 totsel++;
329                                                         }
330                                                 }
331                                                 else if ( (bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT ) {
332                                                         calc_tw_center(scene, bezt->vec[1]);
333                                                         totsel++;
334                                                 }
335                                                 else {
336                                                         if(bezt->f1) {
337                                                                 calc_tw_center(scene, bezt->vec[0]);
338                                                                 totsel++;
339                                                         }
340                                                         if(bezt->f2) {
341                                                                 calc_tw_center(scene, bezt->vec[1]);
342                                                                 totsel++;
343                                                         }
344                                                         if(bezt->f3) {
345                                                                 calc_tw_center(scene, bezt->vec[2]);
346                                                                 totsel++;
347                                                         }
348                                                 }
349                                                 bezt++;
350                                         }
351                                 }
352                                 else {
353                                         bp= nu->bp;
354                                         a= nu->pntsu*nu->pntsv;
355                                         while(a--) {
356                                                 if(bp->f1 & SELECT) {
357                                                         calc_tw_center(scene, bp->vec);
358                                                         totsel++;
359                                                 }
360                                                 bp++;
361                                         }
362                                 }
363                                 nu= nu->next;
364                         }
365                 }
366                 else if(obedit->type==OB_MBALL) {
367                         MetaBall *mb = (MetaBall*)obedit->data;
368                         MetaElem *ml, *ml_sel=NULL;
369
370                         ml= mb->editelems->first;
371                         while(ml) {
372                                 if(ml->flag & SELECT) {
373                                         calc_tw_center(scene, &ml->x);
374                                         ml_sel = ml;
375                                         totsel++;
376                                 }
377                                 ml= ml->next;
378                         }
379                 }
380                 else if(obedit->type==OB_LATTICE) {
381                         BPoint *bp;
382                         Lattice *lt= obedit->data;
383
384                         bp= lt->editlatt->def;
385
386                         a= lt->editlatt->pntsu*lt->editlatt->pntsv*lt->editlatt->pntsw;
387                         while(a--) {
388                                 if(bp->f1 & SELECT) {
389                                         calc_tw_center(scene, bp->vec);
390                                         totsel++;
391                                 }
392                                 bp++;
393                         }
394                 }
395
396                 /* selection center */
397                 if(totsel) {
398                         mul_v3_fl(scene->twcent, 1.0f/(float)totsel);   // centroid!
399                         mul_m4_v3(obedit->obmat, scene->twcent);
400                         mul_m4_v3(obedit->obmat, scene->twmin);
401                         mul_m4_v3(obedit->obmat, scene->twmax);
402                 }
403         }
404         else if(ob && (ob->mode & OB_MODE_POSE)) {
405                 bPoseChannel *pchan;
406                 int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed
407
408                 if((ob->lay & v3d->lay)==0) return 0;
409
410                 totsel = count_set_pose_transflags(&mode, 0, ob);
411
412                 if(totsel) {
413                         /* use channels to get stats */
414                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
415                                 stats_pose(scene, v3d, pchan);
416                         }
417
418                         mul_v3_fl(scene->twcent, 1.0f/(float)totsel);   // centroid!
419                         mul_m4_v3(ob->obmat, scene->twcent);
420                         mul_m4_v3(ob->obmat, scene->twmin);
421                         mul_m4_v3(ob->obmat, scene->twmax);
422                 }
423         }
424         else if(ob && (ob->mode & (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT))) {
425                 ;
426         }
427         else if(ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
428                 PTCacheEdit *edit= PE_get_current(scene, ob);
429                 PTCacheEditPoint *point;
430                 PTCacheEditKey *ek;
431                 int k;
432
433                 if(edit) {
434                         point = edit->points;
435                         for(a=0; a<edit->totpoint; a++,point++) {
436                                 if(point->flag & PEP_HIDE) continue;
437
438                                 for(k=0, ek=point->keys; k<point->totkey; k++, ek++) {
439                                         if(ek->flag & PEK_SELECT) {
440                                                 calc_tw_center(scene, ek->flag & PEK_USE_WCO ? ek->world_co : ek->co);
441                                                 totsel++;
442                                         }
443                                 }
444                         }
445
446                         /* selection center */
447                         if(totsel)
448                                 mul_v3_fl(scene->twcent, 1.0f/(float)totsel);   // centroid!
449                 }
450         }
451         else {
452
453                 /* we need the one selected object, if its not active */
454                 ob= OBACT;
455                 if(ob && !(ob->flag & SELECT)) ob= NULL;
456
457                 for(base= scene->base.first; base; base= base->next) {
458                         if TESTBASELIB(scene, base) {
459                                 if(ob==NULL)
460                                         ob= base->object;
461                                 calc_tw_center(scene, base->object->obmat[3]);
462                                 protectflag_to_drawflags(base->object->protectflag, &v3d->twdrawflag);
463                                 totsel++;
464                         }
465                 }
466
467                 /* selection center */
468                 if(totsel) {
469                         mul_v3_fl(scene->twcent, 1.0f/(float)totsel);   // centroid!
470                 }
471         }
472
473         /* global, local or normal orientation? */
474         if(ob && totsel) {
475
476                 switch(v3d->twmode) {
477                 
478                 case V3D_MANIP_GLOBAL:
479                         break; /* nothing to do */
480
481                 case V3D_MANIP_GIMBAL:
482                 {
483                         float mat[3][3];
484                         unit_m3(mat);
485                         gimbal_axis(ob, mat);
486                         copy_m4_m3(rv3d->twmat, mat);
487                         break;
488                 }
489                 case V3D_MANIP_NORMAL:
490                         if(obedit || ob->mode & OB_MODE_POSE) {
491                                 float mat[3][3];
492                                 ED_getTransformOrientationMatrix(C, mat, (v3d->around == V3D_ACTIVE));
493                                 copy_m4_m3(rv3d->twmat, mat);
494                                 break;
495                         }
496                         /* no break we define 'normal' as 'local' in Object mode */
497                 case V3D_MANIP_LOCAL:
498                         copy_m4_m4(rv3d->twmat, ob->obmat);
499                         normalize_m4(rv3d->twmat);
500                         break;
501
502                 case V3D_MANIP_VIEW:
503                         {
504                                 float mat[3][3];
505                                 copy_m3_m4(mat, rv3d->viewinv);
506                                 normalize_m3(mat);
507                                 copy_m4_m3(rv3d->twmat, mat);
508                         }
509                         break;
510                 default: /* V3D_MANIP_CUSTOM */
511                         {
512                                 float mat[3][3];
513                                 applyTransformOrientation(C, mat, NULL);
514                                 copy_m4_m3(rv3d->twmat, mat);
515                                 break;
516                         }
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_v3(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 static void preOrtho(int ortho, float twmat[][4], int axis)
709 {
710         if (ortho == 0) {
711                 float omat[4][4];
712                 copy_m4_m4(omat, twmat);
713                 orthogonalize_m4(omat, axis);
714                 glPushMatrix();
715                 wmMultMatrix(omat);
716         }
717 }
718
719 static void preOrthoFront(int ortho, float twmat[][4], int axis)
720 {
721         if (ortho == 0) {
722                 float omat[4][4];
723                 copy_m4_m4(omat, twmat);
724                 orthogonalize_m4(omat, axis);
725                 glPushMatrix();
726                 wmMultMatrix(omat);
727                 glFrontFace( is_mat4_flipped(omat)?GL_CW:GL_CCW);
728         }
729 }
730
731 static void postOrtho(int ortho)
732 {
733         if (ortho == 0) {
734                 glPopMatrix();
735         }
736 }
737
738 /* only called while G.moving */
739 static void draw_manipulator_rotate_ghost(View3D *v3d, RegionView3D *rv3d, int drawflags)
740 {
741         GLUquadricObj *qobj;
742         float size, phi, startphi, vec[3], svec[3], matt[4][4], cross[3], tmat[3][3];
743         int arcs= (G.rt!=2);
744         int ortho;
745
746         glDisable(GL_DEPTH_TEST);
747
748         qobj= gluNewQuadric();
749         gluQuadricDrawStyle(qobj, GLU_FILL);
750
751         glColor4ub(0,0,0,64);
752         glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
753         glEnable(GL_BLEND);
754
755         /* we need both [4][4] transforms, t->mat seems to be premul, not post for mat[][4] */
756         copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
757 // XXX  mul_m4_m3m4(matt, t->mat, rv3d->twmat);
758
759         /* Screen aligned view rot circle */
760         if(drawflags & MAN_ROT_V) {
761
762                 /* prepare for screen aligned draw */
763                 glPushMatrix();
764                 size= screen_aligned(rv3d, rv3d->twmat);
765
766                 vec[0]= 0; // XXX (float)(t->con.imval[0] - t->center2d[0]);
767                 vec[1]= 0; // XXX (float)(t->con.imval[1] - t->center2d[1]);
768                 vec[2]= 0.0f;
769                 normalize_v3(vec);
770
771                 startphi= saacos( vec[1] );
772                 if(vec[0]<0.0) startphi= -startphi;
773
774                 phi= 0; // XXX (float)fmod(180.0*t->val/M_PI, 360.0);
775                 if(phi > 180.0) phi-= 360.0;
776                 else if(phi<-180.0) phi+= 360.0;
777
778                 gluPartialDisk(qobj, 0.0, size, 32, 1, 180.0*startphi/M_PI, phi);
779
780                 glPopMatrix();
781         }
782         else if(arcs) {
783                 float imat[3][3], ivmat[3][3];
784                 /* try to get the start rotation */
785
786                 svec[0]= 0; // XXX (float)(t->con.imval[0] - t->center2d[0]);
787                 svec[1]= 0; // XXX (float)(t->con.imval[1] - t->center2d[1]);
788                 svec[2]= 0.0f;
789
790                 /* screen aligned vec transform back to manipulator space */
791                 copy_m3_m4(ivmat, rv3d->viewinv);
792                 copy_m3_m4(tmat, rv3d->twmat);
793                 invert_m3_m3(imat, tmat);
794                 mul_m3_m3m3(tmat, imat, ivmat);
795
796                 mul_m3_v3(tmat, svec);  // tmat is used further on
797                 normalize_v3(svec);
798         }
799         
800         ortho = is_orthogonal_m4(rv3d->twmat);
801
802         if (ortho) {
803                 wmMultMatrix(rv3d->twmat);      // aligns with original widget
804         }
805         
806
807         /* Z disk */
808         if(drawflags & MAN_ROT_Z) {
809                 preOrtho(ortho, rv3d->twmat, 2);
810                 
811                 if(arcs) {
812                         /* correct for squeezed arc */
813                         svec[0]+= tmat[2][0];
814                         svec[1]+= tmat[2][1];
815                         normalize_v3(svec);
816
817                         startphi= (float)atan2(svec[0], svec[1]);
818                 }
819                 else startphi= 0.5f*(float)M_PI;
820
821                 VECCOPY(vec, rv3d->twmat[0]);   // use x axis to detect rotation
822                 normalize_v3(vec);
823                 normalize_v3(matt[0]);
824                 phi= saacos( dot_v3v3(vec, matt[0]) );
825                 if(phi!=0.0) {
826                         cross_v3_v3v3(cross, vec, matt[0]);     // results in z vector
827                         if(dot_v3v3(cross, rv3d->twmat[2]) > 0.0) phi= -phi;
828                         gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 180.0*startphi/M_PI, 180.0*(phi)/M_PI);
829                 }
830
831                 postOrtho(ortho);
832         }
833         /* X disk */
834         if(drawflags & MAN_ROT_X) {
835                 preOrtho(ortho, rv3d->twmat, 0);
836                 
837                 if(arcs) {
838                         /* correct for squeezed arc */
839                         svec[1]+= tmat[2][1];
840                         svec[2]+= tmat[2][2];
841                         normalize_v3(svec);
842
843                         startphi= (float)(M_PI + atan2(svec[2], -svec[1]));
844                 }
845                 else startphi= 0.0f;
846
847                 VECCOPY(vec, rv3d->twmat[1]);   // use y axis to detect rotation
848                 normalize_v3(vec);
849                 normalize_v3(matt[1]);
850                 phi= saacos( dot_v3v3(vec, matt[1]) );
851                 if(phi!=0.0) {
852                         cross_v3_v3v3(cross, vec, matt[1]);     // results in x vector
853                         if(dot_v3v3(cross, rv3d->twmat[0]) > 0.0) phi= -phi;
854                         glRotatef(90.0, 0.0, 1.0, 0.0);
855                         gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 180.0*startphi/M_PI, 180.0*phi/M_PI);
856                         glRotatef(-90.0, 0.0, 1.0, 0.0);
857                 }
858
859                 postOrtho(ortho);
860         }
861         /* Y circle */
862         if(drawflags & MAN_ROT_Y) {
863                 preOrtho(ortho, rv3d->twmat, 1);
864                 
865                 if(arcs) {
866                         /* correct for squeezed arc */
867                         svec[0]+= tmat[2][0];
868                         svec[2]+= tmat[2][2];
869                         normalize_v3(svec);
870
871                         startphi= (float)(M_PI + atan2(-svec[0], svec[2]));
872                 }
873                 else startphi= (float)M_PI;
874
875                 VECCOPY(vec, rv3d->twmat[2]);   // use z axis to detect rotation
876                 normalize_v3(vec);
877                 normalize_v3(matt[2]);
878                 phi= saacos( dot_v3v3(vec, matt[2]) );
879                 if(phi!=0.0) {
880                         cross_v3_v3v3(cross, vec, matt[2]);     // results in y vector
881                         if(dot_v3v3(cross, rv3d->twmat[1]) > 0.0) phi= -phi;
882                         glRotatef(-90.0, 1.0, 0.0, 0.0);
883                         gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 180.0*startphi/M_PI, 180.0*phi/M_PI);
884                         glRotatef(90.0, 1.0, 0.0, 0.0);
885                 }
886
887                 postOrtho(ortho);
888         }
889
890         glDisable(GL_BLEND);
891         wmLoadMatrix(rv3d->viewmat);
892 }
893
894 static void draw_manipulator_rotate(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo)
895 {
896         GLUquadricObj *qobj;
897         double plane[4];
898         float matt[4][4];
899         float size, vec[3], unitmat[4][4];
900         float cywid= 0.33f*0.01f*(float)U.tw_handlesize;
901         float cusize= cywid*0.65f;
902         int arcs= (G.rt!=2);
903         int colcode;
904         int ortho;
905
906         if(moving) colcode= MAN_MOVECOL;
907         else colcode= MAN_RGB;
908
909         /* when called while moving in mixed mode, do not draw when... */
910         if((drawflags & MAN_ROT_C)==0) return;
911
912         /* Init stuff */
913         glDisable(GL_DEPTH_TEST);
914         unit_m4(unitmat);
915
916         qobj= gluNewQuadric();
917         gluQuadricDrawStyle(qobj, GLU_FILL);
918
919         /* prepare for screen aligned draw */
920         VECCOPY(vec, rv3d->twmat[0]);
921         size= normalize_v3(vec);
922         glPushMatrix();
923         glTranslatef(rv3d->twmat[3][0], rv3d->twmat[3][1], rv3d->twmat[3][2]);
924
925         if(arcs) {
926                 /* clipplane makes nice handles, calc here because of multmatrix but with translate! */
927                 VECCOPY(plane, rv3d->viewinv[2]);
928                 plane[3]= -0.02*size; // clip just a bit more
929                 glClipPlane(GL_CLIP_PLANE0, plane);
930         }
931         /* sets view screen aligned */
932         glRotatef( -360.0f*saacos(rv3d->viewquat[0])/(float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]);
933
934         /* Screen aligned help circle */
935         if(arcs) {
936                 if((G.f & G_PICKSEL)==0) {
937                         UI_ThemeColorShade(TH_BACK, -30);
938                         drawcircball(GL_LINE_LOOP, unitmat[3], size, unitmat);
939                 }
940         }
941
942         /* Screen aligned trackball rot circle */
943         if(drawflags & MAN_ROT_T) {
944                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_T);
945
946                 UI_ThemeColor(TH_TRANSFORM);
947                 drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f*size, unitmat);
948         }
949
950         /* Screen aligned view rot circle */
951         if(drawflags & MAN_ROT_V) {
952                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
953                 UI_ThemeColor(TH_TRANSFORM);
954                 drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f*size, unitmat);
955
956                 if(moving) {
957                         float vec[3];
958                         vec[0]= 0; // XXX (float)(t->imval[0] - t->center2d[0]);
959                         vec[1]= 0; // XXX (float)(t->imval[1] - t->center2d[1]);
960                         vec[2]= 0.0f;
961                         normalize_v3(vec);
962                         mul_v3_fl(vec, 1.2f*size);
963                         glBegin(GL_LINES);
964                         glVertex3f(0.0f, 0.0f, 0.0f);
965                         glVertex3fv(vec);
966                         glEnd();
967                 }
968         }
969         glPopMatrix();
970
971
972         ortho = is_orthogonal_m4(rv3d->twmat);
973         
974         /* apply the transform delta */
975         if(moving) {
976                 copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
977                 // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
978                 if (ortho) {
979                         wmMultMatrix(matt);
980                         glFrontFace( is_mat4_flipped(matt)?GL_CW:GL_CCW);
981                 }
982         }
983         else {
984                 if (ortho) {
985                         glFrontFace( is_mat4_flipped(rv3d->twmat)?GL_CW:GL_CCW);
986                         wmMultMatrix(rv3d->twmat);
987                 }
988         }
989
990         /* axes */
991         if(arcs==0) {
992                 if(!(G.f & G_PICKSEL)) {
993                         if( (combo & V3D_MANIP_SCALE)==0) {
994                                 /* axis */
995                                 if( (drawflags & MAN_ROT_X) || (moving && (drawflags & MAN_ROT_Z)) ) {
996                                         preOrthoFront(ortho, rv3d->twmat, 2);
997                                         manipulator_setcolor(v3d, 'x', colcode);
998                                         glBegin(GL_LINES);
999                                         glVertex3f(0.2f, 0.0f, 0.0f);
1000                                         glVertex3f(1.0f, 0.0f, 0.0f);
1001                                         glEnd();
1002                                         postOrtho(ortho);
1003                                 }
1004                                 if( (drawflags & MAN_ROT_Y) || (moving && (drawflags & MAN_ROT_X)) ) {
1005                                         preOrthoFront(ortho, rv3d->twmat, 0);
1006                                         manipulator_setcolor(v3d, 'y', colcode);
1007                                         glBegin(GL_LINES);
1008                                         glVertex3f(0.0f, 0.2f, 0.0f);
1009                                         glVertex3f(0.0f, 1.0f, 0.0f);
1010                                         glEnd();
1011                                         postOrtho(ortho);
1012                                 }
1013                                 if( (drawflags & MAN_ROT_Z) || (moving && (drawflags & MAN_ROT_Y)) ) {
1014                                         preOrthoFront(ortho, rv3d->twmat, 1);
1015                                         manipulator_setcolor(v3d, 'z', colcode);
1016                                         glBegin(GL_LINES);
1017                                         glVertex3f(0.0f, 0.0f, 0.2f);
1018                                         glVertex3f(0.0f, 0.0f, 1.0f);
1019                                         glEnd();
1020                                         postOrtho(ortho);
1021                                 }
1022                         }
1023                 }
1024         }
1025
1026         if(arcs==0 && moving) {
1027
1028                 /* Z circle */
1029                 if(drawflags & MAN_ROT_Z) {
1030                         preOrthoFront(ortho, matt, 2);
1031                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
1032                         manipulator_setcolor(v3d, 'z', colcode);
1033                         drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
1034                         postOrtho(ortho);
1035                 }
1036                 /* X circle */
1037                 if(drawflags & MAN_ROT_X) {
1038                         preOrthoFront(ortho, matt, 0);
1039                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
1040                         glRotatef(90.0, 0.0, 1.0, 0.0);
1041                         manipulator_setcolor(v3d, 'x', colcode);
1042                         drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
1043                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1044                         postOrtho(ortho);
1045                 }
1046                 /* Y circle */
1047                 if(drawflags & MAN_ROT_Y) {
1048                         preOrthoFront(ortho, matt, 1);
1049                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
1050                         glRotatef(-90.0, 1.0, 0.0, 0.0);
1051                         manipulator_setcolor(v3d, 'y', colcode);
1052                         drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
1053                         glRotatef(90.0, 1.0, 0.0, 0.0);
1054                         postOrtho(ortho);
1055                 }
1056
1057                 if(arcs) glDisable(GL_CLIP_PLANE0);
1058         }
1059         // donut arcs
1060         if(arcs) {
1061                 glEnable(GL_CLIP_PLANE0);
1062
1063                 /* Z circle */
1064                 if(drawflags & MAN_ROT_Z) {
1065                         preOrthoFront(ortho, rv3d->twmat, 2);
1066                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
1067                         manipulator_setcolor(v3d, 'z', colcode);
1068                         partial_donut(cusize/4.0f, 1.0f, 0, 48, 8, 48);
1069                         postOrtho(ortho);
1070                 }
1071                 /* X circle */
1072                 if(drawflags & MAN_ROT_X) {
1073                         preOrthoFront(ortho, rv3d->twmat, 0);
1074                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
1075                         glRotatef(90.0, 0.0, 1.0, 0.0);
1076                         manipulator_setcolor(v3d, 'x', colcode);
1077                         partial_donut(cusize/4.0f, 1.0f, 0, 48, 8, 48);
1078                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1079                         postOrtho(ortho);
1080                 }
1081                 /* Y circle */
1082                 if(drawflags & MAN_ROT_Y) {
1083                         preOrthoFront(ortho, rv3d->twmat, 1);
1084                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
1085                         glRotatef(-90.0, 1.0, 0.0, 0.0);
1086                         manipulator_setcolor(v3d, 'y', colcode);
1087                         partial_donut(cusize/4.0f, 1.0f, 0, 48, 8, 48);
1088                         glRotatef(90.0, 1.0, 0.0, 0.0);
1089                         postOrtho(ortho);
1090                 }
1091
1092                 glDisable(GL_CLIP_PLANE0);
1093         }
1094
1095         if(arcs==0) {
1096
1097                 /* Z handle on X axis */
1098                 if(drawflags & MAN_ROT_Z) {
1099                         preOrthoFront(ortho, rv3d->twmat, 2);
1100                         glPushMatrix();
1101                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
1102                         manipulator_setcolor(v3d, 'z', colcode);
1103
1104                         partial_donut(0.7f*cusize, 1.0f, 31, 33, 8, 64);
1105
1106                         glPopMatrix();
1107                         postOrtho(ortho);
1108                 }
1109
1110                 /* Y handle on X axis */
1111                 if(drawflags & MAN_ROT_Y) {
1112                         preOrthoFront(ortho, rv3d->twmat, 1);
1113                         glPushMatrix();
1114                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
1115                         manipulator_setcolor(v3d, 'y', colcode);
1116
1117                         glRotatef(90.0, 1.0, 0.0, 0.0);
1118                         glRotatef(90.0, 0.0, 0.0, 1.0);
1119                         partial_donut(0.7f*cusize, 1.0f, 31, 33, 8, 64);
1120
1121                         glPopMatrix();
1122                         postOrtho(ortho);
1123                 }
1124
1125                 /* X handle on Z axis */
1126                 if(drawflags & MAN_ROT_X) {
1127                         preOrthoFront(ortho, rv3d->twmat, 0);
1128                         glPushMatrix();
1129                         if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
1130                         manipulator_setcolor(v3d, 'x', colcode);
1131
1132                         glRotatef(-90.0, 0.0, 1.0, 0.0);
1133                         glRotatef(90.0, 0.0, 0.0, 1.0);
1134                         partial_donut(0.7f*cusize, 1.0f, 31, 33, 8, 64);
1135
1136                         glPopMatrix();
1137                         postOrtho(ortho);
1138                 }
1139
1140         }
1141
1142         /* restore */
1143         wmLoadMatrix(rv3d->viewmat);
1144         gluDeleteQuadric(qobj);
1145         if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
1146
1147 }
1148
1149 static void drawsolidcube(float size)
1150 {
1151         static float cube[8][3] = {
1152         {-1.0, -1.0, -1.0},
1153         {-1.0, -1.0,  1.0},
1154         {-1.0,  1.0,  1.0},
1155         {-1.0,  1.0, -1.0},
1156         { 1.0, -1.0, -1.0},
1157         { 1.0, -1.0,  1.0},
1158         { 1.0,  1.0,  1.0},
1159         { 1.0,  1.0, -1.0},     };
1160         float n[3];
1161
1162         glPushMatrix();
1163         glScalef(size, size, size);
1164
1165         n[0]=0; n[1]=0; n[2]=0;
1166         glBegin(GL_QUADS);
1167         n[0]= -1.0;
1168         glNormal3fv(n);
1169         glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
1170         n[0]=0;
1171         glEnd();
1172
1173         glBegin(GL_QUADS);
1174         n[1]= -1.0;
1175         glNormal3fv(n);
1176         glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]);
1177         n[1]=0;
1178         glEnd();
1179
1180         glBegin(GL_QUADS);
1181         n[0]= 1.0;
1182         glNormal3fv(n);
1183         glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]);
1184         n[0]=0;
1185         glEnd();
1186
1187         glBegin(GL_QUADS);
1188         n[1]= 1.0;
1189         glNormal3fv(n);
1190         glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]);
1191         n[1]=0;
1192         glEnd();
1193
1194         glBegin(GL_QUADS);
1195         n[2]= 1.0;
1196         glNormal3fv(n);
1197         glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]);
1198         n[2]=0;
1199         glEnd();
1200
1201         glBegin(GL_QUADS);
1202         n[2]= -1.0;
1203         glNormal3fv(n);
1204         glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]);
1205         glEnd();
1206
1207         glPopMatrix();
1208 }
1209
1210
1211 static void draw_manipulator_scale(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo, int colcode)
1212 {
1213         float cywid= 0.25f*0.01f*(float)U.tw_handlesize;
1214         float cusize= cywid*0.75f, dz;
1215
1216         /* when called while moving in mixed mode, do not draw when... */
1217         if((drawflags & MAN_SCALE_C)==0) return;
1218
1219         glDisable(GL_DEPTH_TEST);
1220
1221         /* not in combo mode */
1222         if( (combo & (V3D_MANIP_TRANSLATE|V3D_MANIP_ROTATE))==0) {
1223                 float size, unitmat[4][4];
1224                 int shift= 0; // XXX
1225
1226                 /* center circle, do not add to selection when shift is pressed (planar constraint)  */
1227                 if( (G.f & G_PICKSEL) && shift==0) glLoadName(MAN_SCALE_C);
1228
1229                 manipulator_setcolor(v3d, 'c', colcode);
1230                 glPushMatrix();
1231                 size= screen_aligned(rv3d, rv3d->twmat);
1232                 unit_m4(unitmat);
1233                 drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f*size, unitmat);
1234                 glPopMatrix();
1235
1236                 dz= 1.0;
1237         }
1238         else dz= 1.0f-4.0f*cusize;
1239
1240         if(moving) {
1241                 float matt[4][4];
1242
1243                 copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
1244                 // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
1245                 wmMultMatrix(matt);
1246                 glFrontFace( is_mat4_flipped(matt)?GL_CW:GL_CCW);
1247         }
1248         else {
1249                 wmMultMatrix(rv3d->twmat);
1250                 glFrontFace( is_mat4_flipped(rv3d->twmat)?GL_CW:GL_CCW);
1251         }
1252
1253         /* axis */
1254
1255         /* in combo mode, this is always drawn as first type */
1256         draw_manipulator_axes(v3d, colcode, drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z);
1257
1258         /* Z cube */
1259         glTranslatef(0.0, 0.0, dz);
1260         if(drawflags & MAN_SCALE_Z) {
1261                 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z);
1262                 manipulator_setcolor(v3d, 'z', colcode);
1263                 drawsolidcube(cusize);
1264         }
1265         /* X cube */
1266         glTranslatef(dz, 0.0, -dz);
1267         if(drawflags & MAN_SCALE_X) {
1268                 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_X);
1269                 manipulator_setcolor(v3d, 'x', colcode);
1270                 drawsolidcube(cusize);
1271         }
1272         /* Y cube */
1273         glTranslatef(-dz, dz, 0.0);
1274         if(drawflags & MAN_SCALE_Y) {
1275                 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y);
1276                 manipulator_setcolor(v3d, 'y', colcode);
1277                 drawsolidcube(cusize);
1278         }
1279
1280         /* if shiftkey, center point as last, for selectbuffer order */
1281         if(G.f & G_PICKSEL) {
1282                 int shift= 0; // XXX
1283
1284                 if(shift) {
1285                         glTranslatef(0.0, -dz, 0.0);
1286                         glLoadName(MAN_SCALE_C);
1287                         glBegin(GL_POINTS);
1288                         glVertex3f(0.0, 0.0, 0.0);
1289                         glEnd();
1290                 }
1291         }
1292
1293         /* restore */
1294         wmLoadMatrix(rv3d->viewmat);
1295
1296         if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
1297         glFrontFace(GL_CCW);
1298 }
1299
1300
1301 static void draw_cone(GLUquadricObj *qobj, float len, float width)
1302 {
1303         glTranslatef(0.0, 0.0, -0.5f*len);
1304         gluCylinder(qobj, width, 0.0, len, 8, 1);
1305         gluQuadricOrientation(qobj, GLU_INSIDE);
1306         gluDisk(qobj, 0.0, width, 8, 1);
1307         gluQuadricOrientation(qobj, GLU_OUTSIDE);
1308         glTranslatef(0.0, 0.0, 0.5f*len);
1309 }
1310
1311 static void draw_cylinder(GLUquadricObj *qobj, float len, float width)
1312 {
1313
1314         width*= 0.8f;   // just for beauty
1315
1316         glTranslatef(0.0, 0.0, -0.5f*len);
1317         gluCylinder(qobj, width, width, len, 8, 1);
1318         gluQuadricOrientation(qobj, GLU_INSIDE);
1319         gluDisk(qobj, 0.0, width, 8, 1);
1320         gluQuadricOrientation(qobj, GLU_OUTSIDE);
1321         glTranslatef(0.0, 0.0, len);
1322         gluDisk(qobj, 0.0, width, 8, 1);
1323         glTranslatef(0.0, 0.0, -0.5f*len);
1324 }
1325
1326
1327 static void draw_manipulator_translate(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo, int colcode)
1328 {
1329         GLUquadricObj *qobj;
1330         float cylen= 0.01f*(float)U.tw_handlesize;
1331         float cywid= 0.25f*cylen, dz, size;
1332         float unitmat[4][4];
1333         int shift= 0; // XXX
1334
1335         /* when called while moving in mixed mode, do not draw when... */
1336         if((drawflags & MAN_TRANS_C)==0) return;
1337
1338         // XXX if(moving) glTranslatef(t->vec[0], t->vec[1], t->vec[2]);
1339         glDisable(GL_DEPTH_TEST);
1340
1341         qobj= gluNewQuadric();
1342         gluQuadricDrawStyle(qobj, GLU_FILL);
1343
1344         /* center circle, do not add to selection when shift is pressed (planar constraint) */
1345         if( (G.f & G_PICKSEL) && shift==0) glLoadName(MAN_TRANS_C);
1346
1347         manipulator_setcolor(v3d, 'c', colcode);
1348         glPushMatrix();
1349         size= screen_aligned(rv3d, rv3d->twmat);
1350         unit_m4(unitmat);
1351         drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f*size, unitmat);
1352         glPopMatrix();
1353
1354         /* and now apply matrix, we move to local matrix drawing */
1355         wmMultMatrix(rv3d->twmat);
1356
1357         /* axis */
1358         glLoadName(-1);
1359
1360         // translate drawn as last, only axis when no combo with scale, or for ghosting
1361         if((combo & V3D_MANIP_SCALE)==0 || colcode==MAN_GHOST)
1362                 draw_manipulator_axes(v3d, colcode, drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z);
1363
1364
1365         /* offset in combo mode, for rotate a bit more */
1366         if(combo & (V3D_MANIP_ROTATE)) dz= 1.0f+2.0f*cylen;
1367         else if(combo & (V3D_MANIP_SCALE)) dz= 1.0f+0.5f*cylen;
1368         else dz= 1.0f;
1369
1370         /* Z Cone */
1371         glTranslatef(0.0, 0.0, dz);
1372         if(drawflags & MAN_TRANS_Z) {
1373                 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Z);
1374                 manipulator_setcolor(v3d, 'z', colcode);
1375                 draw_cone(qobj, cylen, cywid);
1376         }
1377         /* X Cone */
1378         glTranslatef(dz, 0.0, -dz);
1379         if(drawflags & MAN_TRANS_X) {
1380                 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_X);
1381                 glRotatef(90.0, 0.0, 1.0, 0.0);
1382                 manipulator_setcolor(v3d, 'x', colcode);
1383                 draw_cone(qobj, cylen, cywid);
1384                 glRotatef(-90.0, 0.0, 1.0, 0.0);
1385         }
1386         /* Y Cone */
1387         glTranslatef(-dz, dz, 0.0);
1388         if(drawflags & MAN_TRANS_Y) {
1389                 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Y);
1390                 glRotatef(-90.0, 1.0, 0.0, 0.0);
1391                 manipulator_setcolor(v3d, 'y', colcode);
1392                 draw_cone(qobj, cylen, cywid);
1393         }
1394
1395         gluDeleteQuadric(qobj);
1396         wmLoadMatrix(rv3d->viewmat);
1397
1398         if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
1399
1400 }
1401
1402 static void draw_manipulator_rotate_cyl(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo, int colcode)
1403 {
1404         GLUquadricObj *qobj;
1405         float size;
1406         float cylen= 0.01f*(float)U.tw_handlesize;
1407         float cywid= 0.25f*cylen;
1408
1409         /* when called while moving in mixed mode, do not draw when... */
1410         if((drawflags & MAN_ROT_C)==0) return;
1411
1412         /* prepare for screen aligned draw */
1413         glPushMatrix();
1414         size= screen_aligned(rv3d, rv3d->twmat);
1415
1416         glDisable(GL_DEPTH_TEST);
1417
1418         qobj= gluNewQuadric();
1419
1420         /* Screen aligned view rot circle */
1421         if(drawflags & MAN_ROT_V) {
1422                 float unitmat[4][4];
1423                 unit_m4(unitmat);
1424
1425                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
1426                 UI_ThemeColor(TH_TRANSFORM);
1427                 drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f*size, unitmat);
1428
1429                 if(moving) {
1430                         float vec[3];
1431                         vec[0]= 0; // XXX (float)(t->imval[0] - t->center2d[0]);
1432                         vec[1]= 0; // XXX (float)(t->imval[1] - t->center2d[1]);
1433                         vec[2]= 0.0f;
1434                         normalize_v3(vec);
1435                         mul_v3_fl(vec, 1.2f*size);
1436                         glBegin(GL_LINES);
1437                         glVertex3f(0.0, 0.0, 0.0);
1438                         glVertex3fv(vec);
1439                         glEnd();
1440                 }
1441         }
1442         glPopMatrix();
1443
1444         /* apply the transform delta */
1445         if(moving) {
1446                 float matt[4][4];
1447                 copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
1448                 // XXX          if (t->flag & T_USES_MANIPULATOR) {
1449                 // XXX                  mul_m4_m3m4(matt, t->mat, rv3d->twmat);
1450                 // XXX }
1451                 wmMultMatrix(matt);
1452         }
1453         else {
1454                 wmMultMatrix(rv3d->twmat);
1455         }
1456
1457         glFrontFace( is_mat4_flipped(rv3d->twmat)?GL_CW:GL_CCW);
1458
1459         /* axis */
1460         if( (G.f & G_PICKSEL)==0 ) {
1461
1462                 // only draw axis when combo didn't draw scale axes
1463                 if((combo & V3D_MANIP_SCALE)==0)
1464                         draw_manipulator_axes(v3d, colcode, drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z);
1465
1466                 /* only has to be set when not in picking */
1467                 gluQuadricDrawStyle(qobj, GLU_FILL);
1468         }
1469
1470         /* Z cyl */
1471         glTranslatef(0.0, 0.0, 1.0);
1472         if(drawflags & MAN_ROT_Z) {
1473                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
1474                 manipulator_setcolor(v3d, 'z', colcode);
1475                 draw_cylinder(qobj, cylen, cywid);
1476         }
1477         /* X cyl */
1478         glTranslatef(1.0, 0.0, -1.0);
1479         if(drawflags & MAN_ROT_X) {
1480                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
1481                 glRotatef(90.0, 0.0, 1.0, 0.0);
1482                 manipulator_setcolor(v3d, 'x', colcode);
1483                 draw_cylinder(qobj, cylen, cywid);
1484                 glRotatef(-90.0, 0.0, 1.0, 0.0);
1485         }
1486         /* Y cylinder */
1487         glTranslatef(-1.0, 1.0, 0.0);
1488         if(drawflags & MAN_ROT_Y) {
1489                 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
1490                 glRotatef(-90.0, 1.0, 0.0, 0.0);
1491                 manipulator_setcolor(v3d, 'y', colcode);
1492                 draw_cylinder(qobj, cylen, cywid);
1493         }
1494
1495         /* restore */
1496
1497         gluDeleteQuadric(qobj);
1498         wmLoadMatrix(rv3d->viewmat);
1499
1500         if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
1501
1502 }
1503
1504
1505 /* ********************************************* */
1506
1507 static float get_manipulator_drawsize(ARegion *ar)
1508 {
1509         RegionView3D *rv3d= ar->regiondata;
1510         float size = get_drawsize(ar, rv3d->twmat[3]);
1511
1512         size*= (float)U.tw_size;
1513
1514         return size;
1515 }
1516
1517
1518 /* main call, does calc centers & orientation too */
1519 /* uses global G.moving */
1520 static int drawflags= 0xFFFF;           // only for the calls below, belongs in scene...?
1521
1522 void BIF_draw_manipulator(const bContext *C)
1523 {
1524         ScrArea *sa= CTX_wm_area(C);
1525         ARegion *ar= CTX_wm_region(C);
1526         Scene *scene= CTX_data_scene(C);
1527         View3D *v3d= sa->spacedata.first;
1528         RegionView3D *rv3d= ar->regiondata;
1529         int totsel;
1530
1531         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return;
1532 //      if(G.moving && (G.moving & G_TRANSFORM_MANIP)==0) return;
1533
1534 //      if(G.moving==0) {
1535         {
1536                 v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
1537
1538                 totsel= calc_manipulator_stats(C);
1539                 if(totsel==0) return;
1540                 drawflags= v3d->twdrawflag;     /* set in calc_manipulator_stats */
1541
1542                 v3d->twflag |= V3D_DRAW_MANIPULATOR;
1543
1544                 /* now we can define center */
1545                 switch(v3d->around) {
1546                 case V3D_CENTER:
1547                 case V3D_ACTIVE:
1548                         rv3d->twmat[3][0]= (scene->twmin[0] + scene->twmax[0])/2.0f;
1549                         rv3d->twmat[3][1]= (scene->twmin[1] + scene->twmax[1])/2.0f;
1550                         rv3d->twmat[3][2]= (scene->twmin[2] + scene->twmax[2])/2.0f;
1551                         if(v3d->around==V3D_ACTIVE && scene->obedit==NULL) {
1552                                 Object *ob= OBACT;
1553                                 if(ob && !(ob->mode & OB_MODE_POSE))
1554                                         VECCOPY(rv3d->twmat[3], ob->obmat[3]);
1555                         }
1556                         break;
1557                 case V3D_LOCAL:
1558                 case V3D_CENTROID:
1559                         VECCOPY(rv3d->twmat[3], scene->twcent);
1560                         break;
1561                 case V3D_CURSOR:
1562                         VECCOPY(rv3d->twmat[3], give_cursor(scene, v3d));
1563                         break;
1564                 }
1565
1566                 mul_mat3_m4_fl(rv3d->twmat, get_manipulator_drawsize(ar));
1567         }
1568
1569         if(v3d->twflag & V3D_DRAW_MANIPULATOR) {
1570
1571                 if(v3d->twtype & V3D_MANIP_ROTATE) {
1572
1573                         /* rotate has special ghosting draw, for pie chart */
1574                         if(G.moving) draw_manipulator_rotate_ghost(v3d, rv3d, drawflags);
1575
1576                         if(G.moving) glEnable(GL_BLEND);
1577
1578                         if(G.rt==3) {
1579                                 if(G.moving) draw_manipulator_rotate_cyl(v3d, rv3d, 1, drawflags, v3d->twtype, MAN_MOVECOL);
1580                                 else draw_manipulator_rotate_cyl(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB);
1581                         }
1582                         else
1583                                 draw_manipulator_rotate(v3d, rv3d, 0 /* G.moving*/, drawflags, v3d->twtype);
1584
1585                         glDisable(GL_BLEND);
1586                 }
1587                 if(v3d->twtype & V3D_MANIP_SCALE) {
1588                         if(G.moving) {
1589                                 glEnable(GL_BLEND);
1590                                 draw_manipulator_scale(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_GHOST);
1591                                 draw_manipulator_scale(v3d, rv3d, 1, drawflags, v3d->twtype, MAN_MOVECOL);
1592                                 glDisable(GL_BLEND);
1593                         }
1594                         else draw_manipulator_scale(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB);
1595                 }
1596                 if(v3d->twtype & V3D_MANIP_TRANSLATE) {
1597                         if(G.moving) {
1598                                 glEnable(GL_BLEND);
1599                                 draw_manipulator_translate(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_GHOST);
1600                                 draw_manipulator_translate(v3d, rv3d, 1, drawflags, v3d->twtype, MAN_MOVECOL);
1601                                 glDisable(GL_BLEND);
1602                         }
1603                         else draw_manipulator_translate(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB);
1604                 }
1605         }
1606 }
1607
1608 static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, short *mval, float hotspot)
1609 {
1610         View3D *v3d= sa->spacedata.first;
1611         RegionView3D *rv3d= ar->regiondata;
1612         rctf rect;
1613         GLuint buffer[64];              // max 4 items per select, so large enuf
1614         short hits;
1615         extern void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect); // XXX check a bit later on this... (ton)
1616
1617         G.f |= G_PICKSEL;
1618
1619         rect.xmin= mval[0]-hotspot;
1620         rect.xmax= mval[0]+hotspot;
1621         rect.ymin= mval[1]-hotspot;
1622         rect.ymax= mval[1]+hotspot;
1623
1624         setwinmatrixview3d(ar, v3d, &rect);
1625         mul_m4_m4m4(rv3d->persmat, rv3d->viewmat, rv3d->winmat);
1626
1627         glSelectBuffer( 64, buffer);
1628         glRenderMode(GL_SELECT);
1629         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1630         glPushName(-2);
1631
1632         /* do the drawing */
1633         if(v3d->twtype & V3D_MANIP_ROTATE) {
1634                 if(G.rt==3) draw_manipulator_rotate_cyl(v3d, rv3d, 0, MAN_ROT_C & v3d->twdrawflag, v3d->twtype, MAN_RGB);
1635                 else draw_manipulator_rotate(v3d, rv3d, 0, MAN_ROT_C & v3d->twdrawflag, v3d->twtype);
1636         }
1637         if(v3d->twtype & V3D_MANIP_SCALE)
1638                 draw_manipulator_scale(v3d, rv3d, 0, MAN_SCALE_C & v3d->twdrawflag, v3d->twtype, MAN_RGB);
1639         if(v3d->twtype & V3D_MANIP_TRANSLATE)
1640                 draw_manipulator_translate(v3d, rv3d, 0, MAN_TRANS_C & v3d->twdrawflag, v3d->twtype, MAN_RGB);
1641
1642         glPopName();
1643         hits= glRenderMode(GL_RENDER);
1644
1645         G.f &= ~G_PICKSEL;
1646         setwinmatrixview3d(ar, v3d, NULL);
1647         mul_m4_m4m4(rv3d->persmat, rv3d->viewmat, rv3d->winmat);
1648
1649         if(hits==1) return buffer[3];
1650         else if(hits>1) {
1651                 GLuint val, dep, mindep=0, mindeprot=0, minval=0, minvalrot=0;
1652                 int a;
1653
1654                 /* we compare the hits in buffer, but value centers highest */
1655                 /* we also store the rotation hits separate (because of arcs) and return hits on other widgets if there are */
1656
1657                 for(a=0; a<hits; a++) {
1658                         dep= buffer[4*a + 1];
1659                         val= buffer[4*a + 3];
1660
1661                         if(val==MAN_TRANS_C) return MAN_TRANS_C;
1662                         else if(val==MAN_SCALE_C) return MAN_SCALE_C;
1663                         else {
1664                                 if(val & MAN_ROT_C) {
1665                                         if(minvalrot==0 || dep<mindeprot) {
1666                                                 mindeprot= dep;
1667                                                 minvalrot= val;
1668                                         }
1669                                 }
1670                                 else {
1671                                         if(minval==0 || dep<mindep) {
1672                                                 mindep= dep;
1673                                                 minval= val;
1674                                         }
1675                                 }
1676                         }
1677                 }
1678
1679                 if(minval)
1680                         return minval;
1681                 else
1682                         return minvalrot;
1683         }
1684         return 0;
1685 }
1686
1687 /* return 0; nothing happened */
1688 int BIF_do_manipulator(bContext *C, struct wmEvent *event, wmOperator *op)
1689 {
1690         ScrArea *sa= CTX_wm_area(C);
1691         View3D *v3d= sa->spacedata.first;
1692         ARegion *ar= CTX_wm_region(C);
1693         int constraint_axis[3] = {0, 0, 0};
1694         int val;
1695         int shift = event->shift;
1696
1697         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0;
1698         if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0;
1699
1700         // find the hotspots first test narrow hotspot
1701         val= manipulator_selectbuf(sa, ar, event->mval, 0.5f*(float)U.tw_hotspot);
1702         if(val) {
1703
1704                 // drawflags still global, for drawing call above
1705                 drawflags= manipulator_selectbuf(sa, ar, event->mval, 0.2f*(float)U.tw_hotspot);
1706                 if(drawflags==0) drawflags= val;
1707
1708                 if (drawflags & MAN_TRANS_C) {
1709                         switch(drawflags) {
1710                         case MAN_TRANS_C:
1711                                 break;
1712                         case MAN_TRANS_X:
1713                                 if(shift) {
1714                                         constraint_axis[1] = 1;
1715                                         constraint_axis[2] = 1;
1716                                 }
1717                                 else
1718                                         constraint_axis[0] = 1;
1719                                 break;
1720                         case MAN_TRANS_Y:
1721                                 if(shift) {
1722                                         constraint_axis[0] = 1;
1723                                         constraint_axis[2] = 1;
1724                                 }
1725                                 else
1726                                         constraint_axis[1] = 1;
1727                                 break;
1728                         case MAN_TRANS_Z:
1729                                 if(shift) {
1730                                         constraint_axis[0] = 1;
1731                                         constraint_axis[1] = 1;
1732                                 }
1733                                 else
1734                                         constraint_axis[2] = 1;
1735                                 break;
1736                         }
1737                         RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
1738                         WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_DEFAULT, op->ptr);
1739                 }
1740                 else if (drawflags & MAN_SCALE_C) {
1741                         switch(drawflags) {
1742                         case MAN_SCALE_X:
1743                                 if(shift) {
1744                                         constraint_axis[1] = 1;
1745                                         constraint_axis[2] = 1;
1746                                 }
1747                                 else
1748                                         constraint_axis[0] = 1;
1749                                 break;
1750                         case MAN_SCALE_Y:
1751                                 if(shift) {
1752                                         constraint_axis[0] = 1;
1753                                         constraint_axis[2] = 1;
1754                                 }
1755                                 else
1756                                         constraint_axis[1] = 1;
1757                                 break;
1758                         case MAN_SCALE_Z:
1759                                 if(shift) {
1760                                         constraint_axis[0] = 1;
1761                                         constraint_axis[1] = 1;
1762                                 }
1763                                 else
1764                                         constraint_axis[2] = 1;
1765                                 break;
1766                         }
1767                         RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
1768                         WM_operator_name_call(C, "TFM_OT_resize", WM_OP_INVOKE_DEFAULT, op->ptr);
1769                 }
1770                 else if (drawflags == MAN_ROT_T) { /* trackball need special case, init is different */
1771                         WM_operator_name_call(C, "TFM_OT_trackball", WM_OP_INVOKE_DEFAULT, op->ptr);
1772                 }
1773                 else if (drawflags & MAN_ROT_C) {
1774                         switch(drawflags) {
1775                         case MAN_ROT_X:
1776                                 constraint_axis[0] = 1;
1777                                 break;
1778                         case MAN_ROT_Y:
1779                                 constraint_axis[1] = 1;
1780                                 break;
1781                         case MAN_ROT_Z:
1782                                 constraint_axis[2] = 1;
1783                                 break;
1784                         }
1785                         RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
1786                         WM_operator_name_call(C, "TFM_OT_rotate", WM_OP_INVOKE_DEFAULT, op->ptr);
1787                 }
1788         }
1789         /* after transform, restore drawflags */
1790         drawflags= 0xFFFF;
1791
1792         return val;
1793 }
1794