4 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
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. The Blender
10 * Foundation also sells licenses for use in proprietary software under
11 * the Blender License. See http://www.blender.org/BL/ for information
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * The Original Code is Copyright (C) 2005 Blender Foundation
24 * All rights reserved.
26 * The Original Code is: all of this file.
28 * Contributor(s): none yet.
30 * ***** END GPL/BL DUAL LICENSE BLOCK *****
47 #include "MEM_guardedalloc.h"
49 #include "DNA_armature_types.h"
50 #include "DNA_curve_types.h"
51 #include "DNA_lattice_types.h"
52 #include "DNA_mesh_types.h"
53 #include "DNA_meta_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_screen_types.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_space_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_view3d_types.h"
61 #include "BKE_armature.h"
62 #include "BKE_global.h"
63 #include "BKE_lattice.h"
64 #include "BKE_object.h"
65 #include "BKE_utildefines.h"
67 #include "BLI_arithb.h"
68 #include "BLI_editVert.h"
70 #include "BIF_editarmature.h"
72 #include "BIF_mywindow.h"
73 #include "BIF_resources.h"
74 #include "BIF_screen.h"
75 #include "BIF_space.h"
76 #include "BIF_transform.h"
80 #include "BDR_drawobject.h"
83 #include "transform.h"
84 #include "transform_generics.h"
86 /* return codes for select, and drawing flags */
100 #define MAN_SCALE_X 256
101 #define MAN_SCALE_Y 512
102 #define MAN_SCALE_Z 1024
103 #define MAN_SCALE_C 1792
109 #define MAN_MOVECOL 2
111 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING */
112 extern TransInfo Trans;
115 static int is_mat4_flipped(float mat[][4])
119 Crossf(vec, mat[0], mat[1]);
120 if( Inpf(vec, mat[2]) < 0.0 ) return 1;
124 /* transform widget center calc helper for below */
125 static void calc_tw_center(float *co)
127 float *twcent= G.scene->twcent;
128 float *min= G.scene->twmin;
129 float *max= G.scene->twmax;
131 DO_MINMAX(co, min, max);
132 VecAddf(twcent, twcent, co);
136 static void stats_pose(ListBase *lb, float *normal, float *plane)
139 float vec[3], mat[4][4];
141 for(bone= lb->first; bone; bone= bone->next) {
142 if (bone->flag & BONE_SELECTED) {
143 /* We don't let IK children get "grabbed" */
144 /* ALERT! abusive global Trans here */
145 if ( (Trans.mode!=TFM_TRANSLATION) || (bone->flag & BONE_IK_TOPARENT)==0 ) {
147 get_bone_root_pos (bone, vec, 1);
150 where_is_bone(G.obpose, bone);
151 get_objectspace_bone_matrix(bone, mat, 1, 1); // points in negative Y o_O
153 VecAddf(normal, normal, mat[2]);
154 VecAddf(plane, plane, mat[1]);
156 return; // see above function
159 stats_pose(&bone->childbase, normal, plane);
164 /* centroid, boundbox, of selection */
165 /* returns total items selected */
166 static int calc_manipulator(ScrArea *sa)
168 extern ListBase editNurb;
169 View3D *v3d= sa->spacedata.first;
172 float normal[3]={0.0, 0.0, 0.0};
173 float plane[3]={0.0, 0.0, 0.0};
176 /* transform widget matrix */
179 /* transform widget centroid/center */
180 G.scene->twcent[0]= G.scene->twcent[1]= G.scene->twcent[2]= 0.0f;
181 INIT_MINMAX(G.scene->twmin, G.scene->twmax);
186 if(G.obedit->type==OB_MESH) {
187 EditMesh *em = G.editMesh;
190 for(eve= em->verts.first; eve; eve= eve->next) {
191 if(eve->f & SELECT) {
193 calc_tw_center(eve->co);
196 if(v3d->twmode == V3D_MANIP_NORMAL) {
199 for(efa= em->faces.first; efa; efa= efa->next) {
200 if(efa->f & SELECT) {
201 VecAddf(normal, normal, efa->n);
202 VecSubf(vec, efa->v2->co, efa->v1->co);
203 VecAddf(plane, plane, vec);
208 else if (G.obedit->type==OB_ARMATURE){
210 for (ebo=G.edbo.first;ebo;ebo=ebo->next){
212 // If this is an IK child and it's parent is being moved, don't count as selected
213 if ((ebo->flag & BONE_IK_TOPARENT)&& (ebo->flag & BONE_ROOTSEL) && ebo->parent && (ebo->parent->flag & BONE_TIPSEL));
215 if (ebo->flag & BONE_TIPSEL) {
216 calc_tw_center(ebo->tail);
219 if (ebo->flag & BONE_ROOTSEL) {
220 calc_tw_center(ebo->head);
226 else if ELEM3(G.obedit->type, OB_CURVE, OB_SURF, OB_FONT) {
233 if((nu->type & 7)==CU_BEZIER) {
238 calc_tw_center(bezt->vec[0]);
242 calc_tw_center(bezt->vec[1]);
246 calc_tw_center(bezt->vec[2]);
254 a= nu->pntsu*nu->pntsv;
257 calc_tw_center(bp->vec);
266 else if(G.obedit->type==OB_MBALL) {
268 extern ListBase editelems; /* go away ! */
273 if(ml->flag & SELECT) {
274 calc_tw_center(&ml->x);
280 else if(G.obedit->type==OB_LATTICE) {
284 a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
287 calc_tw_center(bp->vec);
294 /* selection center */
296 VecMulf(G.scene->twcent, 1.0f/(float)totsel); // centroid!
297 Mat4MulVecfl(G.obedit->obmat, G.scene->twcent);
298 Mat4MulVecfl(G.obedit->obmat, G.scene->twmin);
299 Mat4MulVecfl(G.obedit->obmat, G.scene->twmax);
303 bArmature *arm= G.obpose->data;
306 Trans.mode= TFM_ROTATION; // mislead counting bones... bah
309 count_bone_select(&arm->bonebase, &totsel);
311 /* recursive get stats */
312 stats_pose(&arm->bonebase, normal, plane);
314 //VecMulf(normal, -1.0);
315 VecMulf(plane, -1.0);
317 VecMulf(G.scene->twcent, 1.0f/(float)totsel); // centroid!
318 Mat4MulVecfl(G.obpose->obmat, G.scene->twcent);
319 Mat4MulVecfl(G.obpose->obmat, G.scene->twmin);
320 Mat4MulVecfl(G.obpose->obmat, G.scene->twmax);
323 else if(G.f & (G_FACESELECT + G_VERTEXPAINT + G_TEXTUREPAINT +G_WEIGHTPAINT)) {
328 /* we need the one selected object, if its not active */
330 if(ob && !(ob->flag & SELECT)) ob= NULL;
332 base= (G.scene->base.first);
334 if(v3d->lay & base->lay) {
336 if(base->flag & SELECT) {
337 if(ob==NULL) ob= base->object;
338 calc_tw_center(base->object->obmat[3]);
345 /* selection center */
347 VecMulf(G.scene->twcent, 1.0f/(float)totsel); // centroid!
351 /* global, local or normal orientation? */
354 switch(v3d->twmode) {
355 case V3D_MANIP_GLOBAL:
358 case V3D_MANIP_NORMAL:
359 if(G.obedit || G.obpose) {
360 if(normal[0]!=0.0 || normal[1]!=0.0 || normal[2]!=0.0) {
365 VECCOPY(mat[2], normal);
366 Crossf(mat[0], normal, plane);
367 Crossf(mat[1], mat[2], mat[0]);
369 Mat4MulMat43(v3d->twmat, ob->obmat, mat);
370 Mat4Ortho(v3d->twmat);
375 /* no break we define 'normal' as 'local' in Object mode */
376 case V3D_MANIP_LOCAL:
377 if(totsel==1 || v3d->around==V3D_LOCAL || G.obedit || G.obpose) {
378 Mat4CpyMat4(v3d->twmat, ob->obmat);
379 Mat4Ortho(v3d->twmat);
388 /* ******************** DRAWING STUFFIES *********** */
390 /* radring = radius of donut rings
391 radhole = radius hole
392 start = starting segment (based on nrings)
394 nsides = amount of points in ring
395 nrigns = amount of rings
397 static void partial_donut(float radring, float radhole, int start, int end, int nsides, int nrings)
399 float theta, phi, theta1;
400 float cos_theta, sin_theta;
401 float cos_theta1, sin_theta1;
402 float ring_delta, side_delta;
405 ring_delta= 2.0f*(float)M_PI/(float)nrings;
406 side_delta= 2.0f*(float)M_PI/(float)nsides;
408 theta= (float)M_PI+0.5f*ring_delta;
409 cos_theta= (float)cos(theta);
410 sin_theta= (float)sin(theta);
412 for(i= nrings - 1; i >= 0; i--) {
413 theta1= theta + ring_delta;
414 cos_theta1= (float)cos(theta1);
415 sin_theta1= (float)sin(theta1);
417 if(i==start) { // cap
419 glNormal3f(-sin_theta1, -cos_theta1, 0.0);
421 for(j= nsides; j >= 0; j--) {
422 float cos_phi, sin_phi, dist;
425 cos_phi= (float)cos(phi);
426 sin_phi= (float)sin(phi);
427 dist= radhole + radring * cos_phi;
429 glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi);
433 if(i>=start && i<=end) {
434 glBegin(GL_QUAD_STRIP);
436 for(j= nsides; j >= 0; j--) {
437 float cos_phi, sin_phi, dist;
440 cos_phi= (float)cos(phi);
441 sin_phi= (float)sin(phi);
442 dist= radhole + radring * cos_phi;
444 glNormal3f(cos_theta1 * cos_phi, -sin_theta1 * cos_phi, sin_phi);
445 glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi);
446 glNormal3f(cos_theta * cos_phi, -sin_theta * cos_phi, sin_phi);
447 glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi);
454 glNormal3f(sin_theta, cos_theta, 0.0);
456 for(j= nsides; j >= 0; j--) {
457 float cos_phi, sin_phi, dist;
460 cos_phi= (float)cos(phi);
461 sin_phi= (float)sin(phi);
462 dist= radhole + radring * cos_phi;
464 glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi);
471 cos_theta= cos_theta1;
472 sin_theta= sin_theta1;
476 /* three colors can be set;
478 moving: in transform theme color
479 else the red/green/blue
481 static void manipulator_setcolor(char axis, int colcode)
485 vec[3]= 0.7f; // alpha set on 0.5, can be glEnabled or not
487 if(colcode==MAN_GREY) {
488 if(axis > 'Z') glColor4ub(0, 0, 0, 70);
490 vec[0]= vec[1]= vec[2]= 1.0f; vec[3]= 0.3f;
491 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
494 else if(colcode==MAN_MOVECOL) {
495 if(axis > 'Z') BIF_ThemeColor(TH_TRANSFORM);
497 BIF_GetThemeColor3fv(TH_TRANSFORM, vec);
498 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
504 glColor3ub(255, 0, 100);
507 glColor3ub(100, 255, 100);
510 glColor3ub(50, 50, 225);
513 vec[2]= vec[1]= 0.0f; vec[0]= 1.0f;
514 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
517 vec[0]= vec[2]= 0.0f; vec[1]= 1.0f;
518 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
521 vec[0]= vec[1]= 0.0f; vec[2]= 1.0f;
522 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
525 BIF_GetThemeColor3fv(TH_TRANSFORM, vec);
526 if(G.vd->twmode == V3D_MANIP_LOCAL) {vec[0]+= 0.25f; vec[1]+=0.25f; vec[2]+=0.25f;}
527 else if(G.vd->twmode == V3D_MANIP_NORMAL) {vec[0]-= 0.2f; vec[1]-=0.2f; vec[2]-=0.2f;}
528 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, vec);
534 /* viewmatrix should have been set OK, also no shademode! */
535 static void draw_manipulator_axes(int colcode, int flagx, int flagy, int flagz)
540 manipulator_setcolor('x', colcode);
542 glVertex3f(0.0, 0.0, 0.0);
543 glVertex3f(1.0, 0.0, 0.0);
547 manipulator_setcolor('y', colcode);
549 glVertex3f(0.0, 0.0, 0.0);
550 glVertex3f(0.0, 1.0, 0.0);
554 manipulator_setcolor('z', colcode);
556 glVertex3f(0.0, 0.0, 0.0);
557 glVertex3f(0.0, 0.0, 1.0);
562 /* only called while G.moving */
563 static void draw_manipulator_rotate_ghost(float mat[][4], int drawflags)
565 GLUquadricObj *qobj= gluNewQuadric();
566 float size, phi, vec[3], matt[4][4], cross[3];
568 glDisable(GL_DEPTH_TEST);
569 gluQuadricDrawStyle(qobj, GLU_FILL);
571 glColor4ub(0,0,0,64);
572 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
575 /* we need both [4][4] transforms, Trans.mat seems to be premul, not post for mat[][4] */
576 Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
577 Mat4MulMat34(matt, Trans.mat, mat);
579 /* Screen aligned view rot circle */
580 if(drawflags & MAN_ROT_V) {
583 /* prepare for screen aligned draw */
584 VECCOPY(vec, mat[0]);
585 size= Normalise(vec);
587 glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
589 /* sets view screen aligned */
590 glRotatef( -360.0f*saacos(G.vd->viewquat[0])/(float)M_PI, G.vd->viewquat[1], G.vd->viewquat[2], G.vd->viewquat[3]);
592 vec[0]= (float)(Trans.imval[0] - Trans.center2d[0]);
593 vec[1]= (float)(Trans.imval[1] - Trans.center2d[1]);
597 startphi= saacos( vec[1] );
598 if(vec[0]<0.0) startphi= -startphi;
600 phi= (float)fmod(-180.0*Trans.val/M_PI, 360.0);
601 if(phi > 180.0) phi-= 360.0;
602 else if(phi<-180.0) phi+= 360.0;
604 gluPartialDisk(qobj, 0.0, size, 32, 1, 180.0*startphi/M_PI, phi);
610 mymultmatrix(mat); // aligns with original widget
613 if(drawflags & MAN_ROT_Z) {
614 VECCOPY(vec, mat[0]); // use x axis to detect rotation
617 phi= saacos( Inpf(vec, matt[0]) );
619 Crossf(cross, vec, matt[0]); // results in z vector
620 if(Inpf(cross, mat[2]) > 0.0) phi= -phi;
621 gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 90.0, 180.0*phi/M_PI);
625 if(drawflags & MAN_ROT_X) {
626 VECCOPY(vec, mat[1]); // use y axis to detect rotation
629 phi= saacos( Inpf(vec, matt[1]) );
631 Crossf(cross, vec, matt[1]); // results in x vector
632 if(Inpf(cross, mat[0]) > 0.0) phi= -phi;
633 glRotatef(90.0, 0.0, 1.0, 0.0);
634 gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 0.0, 180.0*phi/M_PI);
635 glRotatef(-90.0, 0.0, 1.0, 0.0);
639 if(drawflags & MAN_ROT_Y) {
640 VECCOPY(vec, mat[2]); // use z axis to detect rotation
643 phi= saacos( Inpf(vec, matt[2]) );
645 Crossf(cross, vec, matt[2]); // results in y vector
646 if(Inpf(cross, mat[1]) > 0.0) phi= -phi;
647 glRotatef(-90.0, 1.0, 0.0, 0.0);
648 gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 180.0, 180.0*phi/M_PI);
649 glRotatef(90.0, 1.0, 0.0, 0.0);
654 myloadmatrix(G.vd->viewmat);
657 static void draw_manipulator_rotate(float mat[][4], int moving, int drawflags, int combo)
659 GLUquadricObj *qobj= gluNewQuadric();
661 float size, vec[3], unitmat[4][4];
662 float cywid= 0.33f*0.01f*(float)U.tw_handlesize;
663 float cusize= cywid*0.65f;
667 if(moving) colcode= MAN_MOVECOL;
668 else colcode= MAN_RGB;
670 if(G.rt==3) cusize= cywid*0.3f;
672 /* when called while moving in mixed mode, do not draw when... */
673 if((drawflags & MAN_ROT_C)==0) return;
676 glDisable(GL_DEPTH_TEST);
678 gluQuadricDrawStyle(qobj, GLU_FILL);
679 gluQuadricNormals(qobj, GLU_SMOOTH);
680 glEnable(GL_CULL_FACE); // backface removal
681 glShadeModel(GL_SMOOTH);
684 /* prepare for screen aligned draw */
685 VECCOPY(vec, mat[0]);
686 size= Normalise(vec);
688 glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
691 /* clipplane makes nice handles, calc here because of multmatrix but with translate! */
692 VECCOPY(plane, G.vd->viewinv[2]);
693 plane[3]= -0.1; // clip more
694 glClipPlane(GL_CLIP_PLANE0, plane);
696 /* sets view screen aligned */
697 glRotatef( -360.0f*saacos(G.vd->viewquat[0])/(float)M_PI, G.vd->viewquat[1], G.vd->viewquat[2], G.vd->viewquat[3]);
699 /* Screen aligned help circle */
701 if((G.f & G_PICKSEL)==0) {
702 BIF_ThemeColorShade(TH_BACK, -30);
703 drawcircball(unitmat[3], size, unitmat);
706 /* Screen aligned view rot circle */
707 if(drawflags & MAN_ROT_V) {
708 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
709 BIF_ThemeColor(TH_TRANSFORM);
710 drawcircball(unitmat[3], 1.2f*size, unitmat);
714 vec[0]= (float)(Trans.imval[0] - Trans.center2d[0]);
715 vec[1]= (float)(Trans.imval[1] - Trans.center2d[1]);
718 VecMulf(vec, 1.2f*size);
720 glVertex3f(0.0f, 0.0f, 0.0f);
727 /* apply the transform delta */
730 Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
731 Mat4MulMat34(matt, Trans.mat, mat);
733 glFrontFace( is_mat4_flipped(matt)?GL_CW:GL_CCW);
736 glFrontFace( is_mat4_flipped(mat)?GL_CW:GL_CCW);
742 if(!(G.f & G_PICKSEL)) {
743 if( (combo & V3D_MANIP_SCALE)==0) {
746 if( (drawflags & MAN_ROT_X) || (moving && (drawflags & MAN_ROT_Z)) ) {
747 manipulator_setcolor('x', colcode);
748 glVertex3f(0.0, 0.0, 0.0);
749 glVertex3f(1.0, 0.0, 0.0);
751 if( (drawflags & MAN_ROT_Y) || (moving && (drawflags & MAN_ROT_X)) ) {
752 manipulator_setcolor('y', colcode);
753 glVertex3f(0.0, 0.0, 0.0);
754 glVertex3f(0.0, 1.0, 0.0);
756 if( (drawflags & MAN_ROT_Z) || (moving && (drawflags & MAN_ROT_Y)) ) {
757 manipulator_setcolor('z', colcode);
758 glVertex3f(0.0, 0.0, 0.0);
759 glVertex3f(0.0, 0.0, 1.0);
766 /* Trackball center */
767 if((drawflags & MAN_ROT_T) && (combo & V3D_MANIP_TRANSLATE)==0) {
768 float smat[3][3], imat[3][3];
771 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_T);
773 Mat3CpyMat4(smat, mat);
776 getViewVector(mat[3], offset);
777 Mat3MulVecfl(imat, offset);
778 Normalise(offset); // matrix space is such that 1.0 = size of sphere
781 BIF_ThemeColor(TH_TRANSFORM);
783 glVertex3f(0.0, 0.0, 0.0);
788 glEnable(GL_LIGHTING);
790 VECCOPY(vec, offset);
791 glTranslatef(vec[0], vec[1], vec[2]);
792 manipulator_setcolor('C', colcode);
793 gluSphere(qobj, cywid, 8, 6);
796 glTranslatef(-vec[0], -vec[1], -vec[2]);
797 glDisable(GL_LIGHTING);
800 if(arcs==0 && moving) {
802 if(arcs) glEnable(GL_CLIP_PLANE0);
805 if(drawflags & MAN_ROT_Z) {
806 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
807 manipulator_setcolor('z', colcode);
808 drawcircball(unitmat[3], 1.0, unitmat);
811 if(drawflags & MAN_ROT_X) {
812 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
813 glRotatef(90.0, 0.0, 1.0, 0.0);
814 manipulator_setcolor('x', colcode);
815 drawcircball(unitmat[3], 1.0, unitmat);
816 glRotatef(-90.0, 0.0, 1.0, 0.0);
819 if(drawflags & MAN_ROT_Y) {
820 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
821 glRotatef(-90.0, 1.0, 0.0, 0.0);
822 manipulator_setcolor('y', colcode);
823 drawcircball(unitmat[3], 1.0, unitmat);
824 glRotatef(90.0, 1.0, 0.0, 0.0);
827 if(arcs) glDisable(GL_CLIP_PLANE0);
831 glEnable(GL_LIGHTING);
832 glEnable(GL_CLIP_PLANE0);
835 if(drawflags & MAN_ROT_Z) {
836 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
837 manipulator_setcolor('Z', colcode);
838 partial_donut(cusize/3.0f, 1.0f, 0, 48, 8, 48);
841 if(drawflags & MAN_ROT_X) {
842 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
843 glRotatef(90.0, 0.0, 1.0, 0.0);
844 manipulator_setcolor('X', colcode);
845 partial_donut(cusize/3.0f, 1.0f, 0, 48, 8, 48);
846 glRotatef(-90.0, 0.0, 1.0, 0.0);
849 if(drawflags & MAN_ROT_Y) {
850 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
851 glRotatef(-90.0, 1.0, 0.0, 0.0);
852 manipulator_setcolor('Y', colcode);
853 partial_donut(cusize/3.0f, 1.0f, 0, 48, 8, 48);
854 glRotatef(90.0, 1.0, 0.0, 0.0);
857 glDisable(GL_CLIP_PLANE0);
861 glEnable(GL_LIGHTING);
863 /* Z handle on X axis */
864 if(drawflags & MAN_ROT_Z) {
866 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
867 manipulator_setcolor('Z', colcode);
870 partial_donut(cusize, 1.0, 21, 27, 8, 48);
872 /* Z handle on Y axis */
873 glRotatef(90.0, 0.0, 0.0, 1.0);
874 partial_donut(cusize, 1.0, 21, 27, 8, 48);
877 partial_donut(cusize, 1.0, 23, 25, 8, 48);
882 /* Y handle on X axis */
883 if(drawflags & MAN_ROT_Y) {
885 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
886 manipulator_setcolor('Y', colcode);
889 glRotatef(90.0, 1.0, 0.0, 0.0);
890 partial_donut(cusize, 1.0, 21, 27, 8, 48);
892 /* Y handle on Z axis */
893 glRotatef(90.0, 0.0, 0.0, 1.0);
894 partial_donut(cusize, 1.0, 21, 27, 8, 48);
897 glRotatef(90.0, 1.0, 0.0, 0.0);
898 glRotatef(90.0, 0.0, 0.0, 1.0);
899 partial_donut(cusize, 1.0, 23, 25, 8, 48);
905 /* X handle on Z axis */
906 if(drawflags & MAN_ROT_X) {
908 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
909 manipulator_setcolor('X', colcode);
912 glRotatef(-90.0, 0.0, 1.0, 0.0);
913 partial_donut(cusize, 1.0, 21, 27, 8, 48);
915 /* X handle on Y axis */
916 glRotatef(90.0, 0.0, 0.0, 1.0);
917 partial_donut(cusize, 1.0, 21, 27, 8, 48);
920 glRotatef(-90.0, 0.0, 1.0, 0.0);
921 glRotatef(90.0, 0.0, 0.0, 1.0);
922 partial_donut(cusize, 1.0, 23, 25, 8, 48);
930 myloadmatrix(G.vd->viewmat);
931 glDisable(GL_CULL_FACE);
932 glDisable(GL_LIGHTING);
934 gluDeleteQuadric(qobj);
935 if(G.zbuf) glEnable(GL_DEPTH_TEST); // shouldn't be global, tsk!
939 static void draw_manipulator_scale(float mat[][4], int moving, int drawflags, int combo, int colcode)
941 float cywid= 0.33f*0.01f*(float)U.tw_handlesize;
942 float cusize= cywid*0.75f, dz;
944 /* when called while moving in mixed mode, do not draw when... */
945 if((drawflags & MAN_SCALE_C)==0) return;
950 Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
951 Mat4MulMat34(matt, Trans.mat, mat);
953 glFrontFace( is_mat4_flipped(matt)?GL_CW:GL_CCW);
957 glFrontFace( is_mat4_flipped(mat)?GL_CW:GL_CCW);
961 if( (G.f & G_PICKSEL)==0 ) {
963 glDisable(GL_DEPTH_TEST);
965 /* in combo mode, this is always drawn as first type */
966 draw_manipulator_axes(colcode, drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z);
968 /* only has to be set when not in picking */
969 glEnable(GL_CULL_FACE); // backface removal
970 glEnable(GL_LIGHTING);
971 glShadeModel(GL_SMOOTH);
974 /* not in combo mode */
975 if( (combo & (V3D_MANIP_TRANSLATE|V3D_MANIP_ROTATE))==0) {
976 /* center cube, do not add to selection when shift is pressed (planar constraint) */
977 if( (G.f & G_PICKSEL) && (G.qual & LR_SHIFTKEY)==0) glLoadName(MAN_SCALE_C);
979 manipulator_setcolor('C', colcode);
980 drawsolidcube(cusize);
984 else dz= 1.0f-3.0f*cusize;
987 glTranslatef(0.0, 0.0, dz);
988 if(drawflags & MAN_SCALE_Z) {
989 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z);
990 manipulator_setcolor('Z', colcode);
991 drawsolidcube(cusize);
994 glTranslatef(dz, 0.0, -dz);
995 if(drawflags & MAN_SCALE_X) {
996 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_X);
997 manipulator_setcolor('X', colcode);
998 drawsolidcube(cusize);
1001 glTranslatef(-dz, dz, 0.0);
1002 if(drawflags & MAN_SCALE_Y) {
1003 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y);
1004 manipulator_setcolor('Y', colcode);
1005 drawsolidcube(cusize);
1008 glDisable(GL_CULL_FACE);
1009 glDisable(GL_LIGHTING);
1011 /* if shiftkey, center point as last, for selectbuffer order */
1012 if(G.f & G_PICKSEL) {
1013 if(G.qual & LR_SHIFTKEY) {
1014 glTranslatef(0.0, -dz, 0.0);
1015 glLoadName(MAN_SCALE_C);
1017 glVertex3f(0.0, 0.0, 0.0);
1023 myloadmatrix(G.vd->viewmat);
1025 if(G.zbuf) glEnable(GL_DEPTH_TEST); // shouldn't be global, tsk!
1026 glFrontFace(GL_CCW);
1029 static void draw_cone(GLUquadricObj *qobj, float len, float width)
1031 glTranslatef(0.0, 0.0, -0.5f*len);
1032 gluCylinder(qobj, width, 0.0, len, 8, 1);
1033 gluQuadricOrientation(qobj, GLU_INSIDE);
1034 gluDisk(qobj, 0.0, width, 8, 1);
1035 gluQuadricOrientation(qobj, GLU_OUTSIDE);
1036 glTranslatef(0.0, 0.0, 0.5f*len);
1039 static void draw_cylinder(GLUquadricObj *qobj, float len, float width)
1042 width*= 0.8f; // just for beauty
1044 glTranslatef(0.0, 0.0, -0.5f*len);
1045 gluCylinder(qobj, width, width, len, 8, 1);
1046 gluQuadricOrientation(qobj, GLU_INSIDE);
1047 gluDisk(qobj, 0.0, width, 8, 1);
1048 gluQuadricOrientation(qobj, GLU_OUTSIDE);
1049 glTranslatef(0.0, 0.0, len);
1050 gluDisk(qobj, 0.0, width, 8, 1);
1051 glTranslatef(0.0, 0.0, -0.5f*len);
1055 static void draw_manipulator_translate(float mat[][4], int moving, int drawflags, int combo, int colcode)
1057 GLUquadricObj *qobj = gluNewQuadric();
1058 float cylen= 0.01f*(float)U.tw_handlesize;
1059 float cywid= 0.33f*cylen, dz;
1061 /* when called while moving in mixed mode, do not draw when... */
1062 if((drawflags & MAN_TRANS_C)==0) return;
1064 if(moving) glTranslatef(Trans.vec[0], Trans.vec[1], Trans.vec[2]);
1068 glDisable(GL_DEPTH_TEST);
1071 if( (G.f & G_PICKSEL)==0 ) {
1073 // translate drawn as last, only axis when no combo
1074 if(combo==V3D_MANIP_TRANSLATE)
1075 draw_manipulator_axes(colcode, drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z);
1077 /* only has to be set when not in picking */
1078 gluQuadricDrawStyle(qobj, GLU_FILL);
1079 gluQuadricNormals(qobj, GLU_SMOOTH);
1080 glEnable(GL_CULL_FACE); // backface removal
1081 glFrontFace( is_mat4_flipped(mat)?GL_CW:GL_CCW);
1082 glEnable(GL_LIGHTING);
1083 glShadeModel(GL_SMOOTH);
1086 /* center sphere, do not add to selection when shift is pressed (planar constraint) */
1087 if( (G.f & G_PICKSEL) && (G.qual & LR_SHIFTKEY)==0) glLoadName(MAN_TRANS_C);
1089 manipulator_setcolor('C', colcode);
1090 gluSphere(qobj, cywid, 8, 6);
1092 /* offset in combo mode */
1093 if(combo & (V3D_MANIP_ROTATE|V3D_MANIP_SCALE)) dz= 1.0f+cylen;
1097 glTranslatef(0.0, 0.0, dz);
1098 if(drawflags & MAN_TRANS_Z) {
1099 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Z);
1100 manipulator_setcolor('Z', colcode);
1101 draw_cone(qobj, cylen, cywid);
1104 glTranslatef(dz, 0.0, -dz);
1105 if(drawflags & MAN_TRANS_X) {
1106 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_X);
1107 glRotatef(90.0, 0.0, 1.0, 0.0);
1108 manipulator_setcolor('X', colcode);
1109 draw_cone(qobj, cylen, cywid);
1110 glRotatef(-90.0, 0.0, 1.0, 0.0);
1113 glTranslatef(-dz, dz, 0.0);
1114 if(drawflags & MAN_TRANS_Y) {
1115 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Y);
1116 glRotatef(-90.0, 1.0, 0.0, 0.0);
1117 manipulator_setcolor('Y', colcode);
1118 draw_cone(qobj, cylen, cywid);
1122 glDisable(GL_CULL_FACE);
1123 glDisable(GL_LIGHTING);
1125 gluDeleteQuadric(qobj);
1126 myloadmatrix(G.vd->viewmat);
1127 glFrontFace(GL_CCW);
1129 if(G.zbuf) glEnable(GL_DEPTH_TEST); // shouldn't be global, tsk!
1133 static void draw_manipulator_rotate_cyl(float mat[][4], int moving, int drawflags, int combo, int colcode)
1135 GLUquadricObj *qobj = gluNewQuadric();
1137 float cylen= 0.01f*(float)U.tw_handlesize;
1138 float cywid= 0.33f*cylen;
1140 /* when called while moving in mixed mode, do not draw when... */
1141 if((drawflags & MAN_ROT_C)==0) return;
1143 /* prepare for screen aligned draw */
1144 VECCOPY(vec, mat[0]);
1145 size= Normalise(vec);
1147 glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
1149 /* sets view screen aligned */
1150 glRotatef( -360.0f*saacos(G.vd->viewquat[0])/(float)M_PI, G.vd->viewquat[1], G.vd->viewquat[2], G.vd->viewquat[3]);
1152 /* Screen aligned view rot circle */
1153 if(drawflags & MAN_ROT_V) {
1154 float unitmat[4][4];
1157 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
1158 BIF_ThemeColor(TH_TRANSFORM);
1159 drawcircball(unitmat[3], 1.2f*size, unitmat);
1163 vec[0]= (float)(Trans.imval[0] - Trans.center2d[0]);
1164 vec[1]= (float)(Trans.imval[1] - Trans.center2d[1]);
1167 VecMulf(vec, 1.2f*size);
1169 glVertex3f(0.0, 0.0, 0.0);
1176 /* apply the transform delta */
1179 Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
1180 if (Trans.flag & T_USES_MANIPULATOR) {
1181 Mat4MulMat34(matt, Trans.mat, mat);
1189 glFrontFace( is_mat4_flipped(mat)?GL_CW:GL_CCW);
1190 glDisable(GL_DEPTH_TEST);
1193 if( (G.f & G_PICKSEL)==0 ) {
1195 // only draw axis when combo didn't draw scale axes
1196 if((combo & V3D_MANIP_SCALE)==0)
1197 draw_manipulator_axes(colcode, drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z);
1199 /* only has to be set when not in picking */
1200 gluQuadricDrawStyle(qobj, GLU_FILL);
1201 gluQuadricNormals(qobj, GLU_SMOOTH);
1202 glEnable(GL_CULL_FACE); // backface removal
1203 glEnable(GL_LIGHTING);
1204 glShadeModel(GL_SMOOTH);
1209 if((drawflags & MAN_ROT_T) && (combo & V3D_MANIP_TRANSLATE)==0) {
1210 float smat[3][3], imat[3][3];
1213 Mat3CpyMat4(smat, mat);
1214 Mat3Inv(imat, smat);
1216 getViewVector(mat[3], offset);
1217 Mat3MulVecfl(imat, offset);
1218 Normalise(offset); // matrix space is such that 1.0 = size of sphere
1221 glDisable(GL_LIGHTING);
1222 BIF_ThemeColor(TH_TRANSFORM);
1224 glVertex3f(0.0, 0.0, 0.0);
1225 glVertex3fv(offset);
1227 glEnable(GL_LIGHTING);
1230 /* center sphere, do not add to selection when shift is pressed (planar constraint) */
1231 if( (G.f & G_PICKSEL) && (G.qual & LR_SHIFTKEY)==0) glLoadName(MAN_ROT_T);
1233 VECCOPY(vec, offset);
1234 glTranslatef(vec[0], vec[1], vec[2]);
1235 manipulator_setcolor('C', colcode);
1236 gluSphere(qobj, cywid, 8, 6);
1239 glTranslatef(-vec[0], -vec[1], -vec[2]);
1243 glTranslatef(0.0, 0.0, 1.0);
1244 if(drawflags & MAN_ROT_Z) {
1245 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
1246 manipulator_setcolor('Z', colcode);
1247 draw_cylinder(qobj, cylen, cywid);
1250 glTranslatef(1.0, 0.0, -1.0);
1251 if(drawflags & MAN_ROT_X) {
1252 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
1253 glRotatef(90.0, 0.0, 1.0, 0.0);
1254 manipulator_setcolor('X', colcode);
1255 draw_cylinder(qobj, cylen, cywid);
1256 glRotatef(-90.0, 0.0, 1.0, 0.0);
1259 glTranslatef(-1.0, 1.0, 0.0);
1260 if(drawflags & MAN_ROT_Y) {
1261 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
1262 glRotatef(-90.0, 1.0, 0.0, 0.0);
1263 manipulator_setcolor('Y', colcode);
1264 draw_cylinder(qobj, cylen, cywid);
1268 glDisable(GL_CULL_FACE);
1269 glDisable(GL_LIGHTING);
1270 glFrontFace(GL_CCW);
1272 gluDeleteQuadric(qobj);
1273 myloadmatrix(G.vd->viewmat);
1275 if(G.zbuf) glEnable(GL_DEPTH_TEST); // shouldn't be global, tsk!
1280 static float get_manipulator_drawsize(ScrArea *sa)
1282 View3D *v3d= sa->spacedata.first;
1283 float size, vec[3], len1, len2;
1285 /* size calculus, depending ortho/persp settings, like initgrabz() */
1286 size= v3d->persmat[0][3]*v3d->twmat[3][0]+ v3d->persmat[1][3]*v3d->twmat[3][1]+ v3d->persmat[2][3]*v3d->twmat[3][2]+ v3d->persmat[3][3];
1288 VECCOPY(vec, v3d->persinv[0]);
1289 len1= Normalise(vec);
1290 VECCOPY(vec, v3d->persinv[1]);
1291 len2= Normalise(vec);
1293 size*= (0.01f*(float)U.tw_size)*(len1>len2?len1:len2);
1294 if(U.tw_flag & U_TW_ABSOLUTE) {
1295 /* correct for relative window size */
1296 if(sa->winx > sa->winy) size*= 1000.0f/(float)sa->winx;
1297 else size*= 1000.0f/(float)sa->winy;
1302 /* exported to transform_constraints.c */
1303 /* mat, vec = default orientation and location */
1304 /* type = transform type */
1305 /* axis = x, y, z, c */
1306 /* col: 0 = colored, 1 = moving, 2 = ghost */
1307 void draw_manipulator_ext(ScrArea *sa, int type, char axis, int col, float vec[3], float mat[][3])
1313 Mat4CpyMat3(mat4, mat);
1314 VECCOPY(mat4[3], vec);
1316 Mat4MulFloat3((float *)mat4, get_manipulator_drawsize(sa));
1318 glEnable(GL_BLEND); // let's do it transparent by default
1319 if(col==0) colcode= MAN_RGB;
1320 else if(col==1) colcode= MAN_MOVECOL;
1321 else colcode= MAN_GREY;
1324 if(type==TFM_ROTATION) {
1325 if(axis=='x') drawflags= MAN_ROT_X;
1326 else if(axis=='y') drawflags= MAN_ROT_Y;
1327 else if(axis=='z') drawflags= MAN_ROT_Z;
1328 else drawflags= MAN_ROT_C;
1330 draw_manipulator_rotate_cyl(mat4, col, drawflags, V3D_MANIP_ROTATE, colcode);
1332 else if(type==TFM_RESIZE) {
1333 if(axis=='x') drawflags= MAN_SCALE_X;
1334 else if(axis=='y') drawflags= MAN_SCALE_Y;
1335 else if(axis=='z') drawflags= MAN_SCALE_Z;
1336 else drawflags= MAN_SCALE_C;
1338 draw_manipulator_scale(mat4, col, drawflags, V3D_MANIP_SCALE, colcode);
1341 if(axis=='x') drawflags= MAN_TRANS_X;
1342 else if(axis=='y') drawflags= MAN_TRANS_Y;
1343 else if(axis=='z') drawflags= MAN_TRANS_Z;
1344 else drawflags= MAN_TRANS_C;
1346 draw_manipulator_translate(mat4, 0, drawflags, V3D_MANIP_TRANSLATE, colcode);
1350 glDisable(GL_BLEND);
1353 /* main call, does calc centers & orientation too */
1354 /* uses global G.moving */
1355 static int drawflags= 0xFFFF; // only for the calls below, belongs in scene...?
1356 void BIF_draw_manipulator(ScrArea *sa)
1358 View3D *v3d= sa->spacedata.first;
1361 if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return;
1362 if(G.moving && (G.moving & G_TRANSFORM_MANIP)==0) return;
1365 v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
1367 totsel= calc_manipulator(sa);
1368 if(totsel==0) return;
1370 v3d->twflag |= V3D_DRAW_MANIPULATOR;
1372 /* now we can define centre */
1373 switch(v3d->around) {
1376 v3d->twmat[3][0]= (G.scene->twmin[0] + G.scene->twmax[0])/2.0f;
1377 v3d->twmat[3][1]= (G.scene->twmin[1] + G.scene->twmax[1])/2.0f;
1378 v3d->twmat[3][2]= (G.scene->twmin[2] + G.scene->twmax[2])/2.0f;
1381 VECCOPY(v3d->twmat[3], G.scene->twcent);
1384 VECCOPY(v3d->twmat[3], G.scene->cursor);
1388 Mat4MulFloat3((float *)v3d->twmat, get_manipulator_drawsize(sa));
1391 if(v3d->twflag & V3D_DRAW_MANIPULATOR) {
1393 if(v3d->twtype & V3D_MANIP_ROTATE) {
1394 /* rotate has special ghosting draw, for pie chart */
1395 if(G.moving) draw_manipulator_rotate_ghost(v3d->twmat, drawflags);
1397 if(G.moving) glEnable(GL_BLEND);
1400 if(G.moving) draw_manipulator_rotate_cyl(v3d->twmat, 1, drawflags, v3d->twtype, MAN_MOVECOL);
1401 else draw_manipulator_rotate_cyl(v3d->twmat, 0, drawflags, v3d->twtype, MAN_RGB);
1403 else draw_manipulator_rotate(v3d->twmat, G.moving, drawflags, v3d->twtype);
1405 glDisable(GL_BLEND);
1407 if(v3d->twtype & V3D_MANIP_SCALE) {
1410 draw_manipulator_scale(v3d->twmat, 0, drawflags, v3d->twtype, MAN_GREY);
1411 draw_manipulator_scale(v3d->twmat, 1, drawflags, v3d->twtype, MAN_MOVECOL);
1412 glDisable(GL_BLEND);
1414 else draw_manipulator_scale(v3d->twmat, 0, drawflags, v3d->twtype, MAN_RGB);
1416 if(v3d->twtype & V3D_MANIP_TRANSLATE) {
1419 draw_manipulator_translate(v3d->twmat, 0, drawflags, v3d->twtype, MAN_GREY);
1420 draw_manipulator_translate(v3d->twmat, 1, drawflags, v3d->twtype, MAN_MOVECOL);
1421 glDisable(GL_BLEND);
1423 else draw_manipulator_translate(v3d->twmat, 0, drawflags, v3d->twtype, MAN_RGB);
1428 static int manipulator_selectbuf(ScrArea *sa, float hotspot)
1430 View3D *v3d= sa->spacedata.first;
1432 GLuint buffer[64]; // max 4 items per select, so large enuf
1433 short hits, mval[2];
1437 getmouseco_areawin(mval);
1438 rect.xmin= mval[0]-hotspot;
1439 rect.xmax= mval[0]+hotspot;
1440 rect.ymin= mval[1]-hotspot;
1441 rect.ymax= mval[1]+hotspot;
1443 /* get rid of overlay button matrix */
1446 setwinmatrixview3d(&rect);
1447 Mat4MulMat4(v3d->persmat, v3d->viewmat, sa->winmat);
1449 glSelectBuffer( 64, buffer);
1450 glRenderMode(GL_SELECT);
1451 glInitNames(); /* these two calls whatfor? It doesnt work otherwise */
1454 /* do the drawing */
1455 if(v3d->twtype & V3D_MANIP_ROTATE) {
1456 if(G.rt==4) draw_manipulator_rotate_cyl(v3d->twmat, 0, MAN_ROT_C, v3d->twtype, MAN_RGB);
1457 else draw_manipulator_rotate(v3d->twmat, 0, MAN_ROT_C, v3d->twtype);
1459 if(v3d->twtype & V3D_MANIP_SCALE)
1460 draw_manipulator_scale(v3d->twmat, 0, MAN_SCALE_C, v3d->twtype, MAN_RGB);
1461 if(v3d->twtype & V3D_MANIP_TRANSLATE)
1462 draw_manipulator_translate(v3d->twmat, 0, MAN_TRANS_C, v3d->twtype, MAN_RGB);
1465 hits= glRenderMode(GL_RENDER);
1468 setwinmatrixview3d(0);
1469 Mat4MulMat4(v3d->persmat, v3d->viewmat, sa->winmat);
1473 if(hits==1) return buffer[3];
1475 GLuint mindep, minval;
1478 /* we compare the hits in buffer, but value centers highest */
1482 for(a=1; a<hits; a++) {
1483 if(minval==MAN_TRANS_C || minval==MAN_SCALE_C) break;
1485 if(buffer[4*a + 3]==MAN_TRANS_C || buffer[4*a + 3]==MAN_SCALE_C || buffer[4*a + 1] < mindep) {
1486 mindep= buffer[4*a + 1];
1487 minval= buffer[4*a + 3];
1495 /* return 0; nothing happened */
1496 int BIF_do_manipulator(ScrArea *sa)
1498 View3D *v3d= sa->spacedata.first;
1501 if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0;
1502 if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0;
1504 // find the hotspots first test narrow hotspot
1505 val= manipulator_selectbuf(sa, 0.5f*(float)U.tw_hotspot);
1507 short mvalo[2], mval[2];
1509 // drawflags still global, for drawing call above
1510 drawflags= manipulator_selectbuf(sa, 0.2f*(float)U.tw_hotspot);
1511 if(drawflags==0) drawflags= val;
1513 getmouseco_areawin(mvalo);
1517 ManipulatorTransform(TFM_TRANSLATION);
1520 if(G.qual & LR_SHIFTKEY) {
1521 drawflags= MAN_TRANS_Y|MAN_TRANS_Z;
1522 BIF_setDualAxisConstraint(v3d->twmat[1], v3d->twmat[2]);
1525 BIF_setSingleAxisConstraint(v3d->twmat[0], " dX");
1526 ManipulatorTransform(TFM_TRANSLATION);
1529 if(G.qual & LR_SHIFTKEY) {
1530 drawflags= MAN_TRANS_X|MAN_TRANS_Z;
1531 BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[2]);
1534 BIF_setSingleAxisConstraint(v3d->twmat[1], " dY");
1535 ManipulatorTransform(TFM_TRANSLATION);
1538 if(G.qual & LR_SHIFTKEY) {
1539 drawflags= MAN_TRANS_X|MAN_TRANS_Y;
1540 BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[1]);
1543 BIF_setSingleAxisConstraint(v3d->twmat[2], " dZ");
1544 ManipulatorTransform(TFM_TRANSLATION);
1548 ManipulatorTransform(TFM_RESIZE);
1551 if(G.qual & LR_SHIFTKEY) {
1552 drawflags= MAN_SCALE_Y|MAN_SCALE_Z;
1553 BIF_setDualAxisConstraint(v3d->twmat[1], v3d->twmat[2]);
1556 BIF_setSingleAxisConstraint(v3d->twmat[0], " SizeX");
1557 ManipulatorTransform(TFM_RESIZE);
1560 if(G.qual & LR_SHIFTKEY) {
1561 drawflags= MAN_SCALE_X|MAN_SCALE_Z;
1562 BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[2]);
1565 BIF_setSingleAxisConstraint(v3d->twmat[1], " SizeY");
1566 ManipulatorTransform(TFM_RESIZE);
1569 if(G.qual & LR_SHIFTKEY) {
1570 drawflags= MAN_SCALE_X|MAN_SCALE_Y;
1571 BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[1]);
1574 BIF_setSingleAxisConstraint(v3d->twmat[2], " SizeZ");
1575 ManipulatorTransform(TFM_RESIZE);
1579 BIF_setSingleAxisConstraint(v3d->twmat[0], " RotX");
1580 ManipulatorTransform(TFM_ROTATION);
1583 BIF_setSingleAxisConstraint(v3d->twmat[1], " RotY");
1584 ManipulatorTransform(TFM_ROTATION);
1587 BIF_setSingleAxisConstraint(v3d->twmat[2], " RotZ");
1588 ManipulatorTransform(TFM_ROTATION);
1591 ManipulatorTransform(TFM_TRACKBALL);
1594 ManipulatorTransform(TFM_ROTATION);
1598 /* cycling orientation modus */
1599 getmouseco_areawin(mval);
1600 if(val==MAN_ROT_T || val==MAN_SCALE_C || val==MAN_TRANS_C) {
1601 if(mvalo[0]==mval[0] && mvalo[1]==mval[1]) {
1602 if(v3d->twmode==V3D_MANIP_GLOBAL)
1603 v3d->twmode= V3D_MANIP_LOCAL;
1604 else if(v3d->twmode==V3D_MANIP_LOCAL)
1605 if(G.obedit || G.obpose) v3d->twmode= V3D_MANIP_NORMAL;
1606 else v3d->twmode= V3D_MANIP_GLOBAL;
1607 else if(v3d->twmode==V3D_MANIP_NORMAL)
1608 v3d->twmode= V3D_MANIP_GLOBAL;
1614 /* after transform, restore drawflags */