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