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