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) 2001-2002 by NaN Holding BV.
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 *****
48 #include "MEM_guardedalloc.h"
50 #include "DNA_armature_types.h"
51 #include "DNA_ipo_types.h" /* some silly ipo flag */
52 #include "DNA_listBase.h"
53 #include "DNA_meshdata_types.h"
54 #include "DNA_mesh_types.h"
55 #include "DNA_object_types.h"
56 #include "DNA_scene_types.h" /* PET modes */
57 #include "DNA_screen_types.h" /* area dimensions */
58 #include "DNA_scene_types.h"
59 #include "DNA_screen_types.h"
60 #include "DNA_texture_types.h"
61 #include "DNA_userdef_types.h"
62 #include "DNA_view3d_types.h"
63 #include "DNA_space_types.h"
65 #include "BIF_editview.h" /* arrows_move_cursor */
67 #include "BIF_glutil.h"
68 #include "BIF_mywindow.h"
69 #include "BIF_resources.h"
70 #include "BIF_screen.h"
71 #include "BIF_space.h" /* undo */
72 #include "BIF_toets.h" /* persptoetsen */
73 #include "BIF_mywindow.h" /* warp_pointer */
74 #include "BIF_toolbox.h" /* notice */
75 #include "BIF_editmesh.h"
76 #include "BIF_editsima.h"
77 #include "BIF_drawimage.h" /* uvco_to_areaco_noclip */
79 #include "BKE_global.h"
80 #include "BKE_utildefines.h"
81 #include "BKE_bad_level_calls.h"/* popmenu and error */
83 #include "BDR_editobject.h" /* compatible_eul */
87 #include "BLI_arithb.h"
88 #include "BLI_blenlib.h"
89 #include "BLI_editVert.h"
91 #include "PIL_time.h" /* sleep */
97 #include "transform.h"
99 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING */
100 TransInfo Trans = {TFM_INIT, 0}; // enforce init on first usage
102 /******************************** Helper functions ************************************/
103 /* ************************** Dashed help line **************************** */
106 /* bad frontbuffer call... because it is used in transform after force_draw() */
107 static void helpline(TransInfo *t, float *vec)
109 float vecrot[3], cent[2];
112 VECCOPY(vecrot, vec);
113 if(t->flag & T_EDIT) {
115 if(ob) Mat4MulVecfl(ob->obmat, vecrot);
117 else if(t->flag & T_POSE) {
118 Object *ob=t->poseobj;
119 if(ob) Mat4MulVecfl(ob->obmat, vecrot);
122 getmouseco_areawin(mval);
123 projectFloatView(t, vecrot, cent); // no overflow in extreme cases
124 if(cent[0]!=IS_CLIPPED) {
127 glDrawBuffer(GL_FRONT);
129 BIF_ThemeColor(TH_WIRE);
132 glBegin(GL_LINE_STRIP);
139 bglFlush(); // flush display for frontbuffer
140 glDrawBuffer(GL_BACK);
143 /* ************************** INPUT FROM MOUSE *************************** */
145 float InputScaleRatio(TransInfo *t, short mval[2]) {
147 if(t->flag & T_SHIFT_MOD) {
148 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
149 dx = (float)(t->center2d[0] - t->shiftmval[0]);
150 dy = (float)(t->center2d[1] - t->shiftmval[1]);
151 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
153 dx= (float)(t->center2d[0] - mval[0]);
154 dy= (float)(t->center2d[1] - mval[1]);
155 ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
158 dx = (float)(t->center2d[0] - mval[0]);
159 dy = (float)(t->center2d[1] - mval[1]);
160 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
165 float InputHorizontalRatio(TransInfo *t, short mval[2]) {
168 pad = curarea->winx / 10;
170 if (t->flag & T_SHIFT_MOD) {
171 /* deal with Shift key by adding motion / 10 to motion before shift press */
172 y = t->shiftmval[0] + (mval[0] - t->shiftmval[0]) / 10;
177 return (float)(y - pad) / (float)(curarea->winx - 2 * pad);
180 float InputHorizontalAbsolute(TransInfo *t, short mval[2]) {
182 if(t->flag & T_SHIFT_MOD) {
183 short dx = t->shiftmval[0] + (mval[0] - t->shiftmval[0]) / 10 - t->imval[0];
184 short dy = t->shiftmval[1] + (mval[1] - t->shiftmval[1]) / 10 - t->imval[1];
185 convertViewVec(t, t->vec, dx, dy);
188 convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
190 Projf(vec, t->vec, t->viewinv[0]);
191 return Inpf(t->viewinv[0], vec) * 2.0f;
194 float InputVerticalAbsolute(TransInfo *t, short mval[2]) {
196 if(t->flag & T_SHIFT_MOD) {
197 short dx = t->shiftmval[0] + (mval[0] - t->shiftmval[0]) / 10 - t->imval[0];
198 short dy = t->shiftmval[1] + (mval[1] - t->shiftmval[1]) / 10 - t->imval[1];
199 convertViewVec(t, t->vec, dx, dy);
202 convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
204 Projf(vec, t->vec, t->viewinv[1]);
205 return Inpf(t->viewinv[1], vec) * 2.0f;
208 /* ************************** SPACE DEPENDANT CODE **************************** */
210 void setTransformViewMatrices(TransInfo *t)
212 if(t->spacetype==SPACE_VIEW3D) {
213 Mat4CpyMat4(t->viewmat, G.vd->viewmat);
214 Mat4CpyMat4(t->viewinv, G.vd->viewinv);
215 Mat4CpyMat4(t->persmat, G.vd->persmat);
216 Mat4CpyMat4(t->persinv, G.vd->persinv);
217 t->persp= G.vd->persp;
224 t->persp = 0; // ortho
227 calculateCenter2D(t);
231 void convertViewVec(TransInfo *t, float *vec, short dx, short dy)
233 if (t->spacetype==SPACE_VIEW3D) {
234 window_to_3d(vec, dx, dy);
236 else if(t->spacetype==SPACE_IMAGE) {
237 float divx, divy, aspx, aspy;
239 transform_aspect_ratio_tface_uv(&aspx, &aspy);
241 divx= G.v2d->mask.xmax-G.v2d->mask.xmin;
242 divy= G.v2d->mask.ymax-G.v2d->mask.ymin;
244 vec[0]= aspx*(G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx)/divx;
245 vec[1]= aspy*(G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/divy;
250 void projectIntView(TransInfo *t, float *vec, int *adr)
252 if (t->spacetype==SPACE_VIEW3D)
253 project_int(vec, adr);
254 else if(t->spacetype==SPACE_IMAGE) {
255 float aspx, aspy, v[2];
257 transform_aspect_ratio_tface_uv(&aspx, &aspy);
261 uvco_to_areaco_noclip(v, adr);
265 void projectFloatView(TransInfo *t, float *vec, float *adr)
267 if (t->spacetype==SPACE_VIEW3D)
268 project_float(vec, adr);
269 else if(t->spacetype==SPACE_IMAGE) {
272 projectIntView(t, vec, a);
278 void convertVecToDisplayNum(float *vec, float *num)
280 TransInfo *t= BIF_GetTransInfo();
284 if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
287 if((G.sima->flag & SI_COORDFLOATS)==0) {
289 transform_width_height_tface_uv(&width, &height);
295 transform_aspect_ratio_tface_uv(&aspx, &aspy);
301 void convertDisplayNumToVec(float *num, float *vec)
303 TransInfo *t= BIF_GetTransInfo();
307 if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
310 if((G.sima->flag & SI_COORDFLOATS)==0) {
312 transform_width_height_tface_uv(&width, &height);
318 transform_aspect_ratio_tface_uv(&aspx, &aspy);
324 static void viewRedrawForce(TransInfo *t)
326 if(t->spacetype==SPACE_VIEW3D)
328 else if(t->spacetype==SPACE_IMAGE) {
329 if(G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
334 static void viewRedrawPost(TransInfo *t)
336 if(t->spacetype==SPACE_VIEW3D) {
337 allqueue(REDRAWBUTSOBJECT, 0);
338 allqueue(REDRAWVIEW3D, 0);
340 else if(t->spacetype==SPACE_IMAGE) {
341 allqueue(REDRAWIMAGE, 0);
342 allqueue(REDRAWVIEW3D, 0);
345 scrarea_queue_headredraw(curarea);
348 /* ************************** TRANSFORMATIONS **************************** */
350 void BIF_selectOrientation() {
352 val= pupmenu("Orientation%t|Global|Local|Normal|View");
354 if(val==1) G.vd->twmode= V3D_MANIP_GLOBAL;
355 else if(val==2) G.vd->twmode= V3D_MANIP_LOCAL;
356 else if(val==3) G.vd->twmode= V3D_MANIP_NORMAL;
357 else if(val==4) G.vd->twmode= V3D_MANIP_VIEW;
361 static void view_editmove(unsigned short event)
364 /* Regular: Zoom in */
365 /* Shift: Scroll up */
366 /* Ctrl: Scroll right */
367 /* Alt-Shift: Rotate up */
368 /* Alt-Ctrl: Rotate right */
370 /* only work in 3D window for now
371 * In the end, will have to send to event to a 2D window handler instead
373 if (Trans.flag & T_2D_EDIT)
379 if( G.qual & LR_SHIFTKEY ) {
380 if( G.qual & LR_ALTKEY ) {
381 G.qual &= ~LR_SHIFTKEY;
383 G.qual |= LR_SHIFTKEY;
387 } else if( G.qual & LR_CTRLKEY ) {
388 if( G.qual & LR_ALTKEY ) {
389 G.qual &= ~LR_CTRLKEY;
391 G.qual |= LR_CTRLKEY;
395 } else if(U.uiflag & USER_WHEELZOOMDIR)
396 persptoetsen(PADMINUS);
398 persptoetsen(PADPLUSKEY);
403 if( G.qual & LR_SHIFTKEY ) {
404 if( G.qual & LR_ALTKEY ) {
405 G.qual &= ~LR_SHIFTKEY;
407 G.qual |= LR_SHIFTKEY;
411 } else if( G.qual & LR_CTRLKEY ) {
412 if( G.qual & LR_ALTKEY ) {
413 G.qual &= ~LR_CTRLKEY;
415 G.qual |= LR_CTRLKEY;
419 } else if(U.uiflag & USER_WHEELZOOMDIR)
420 persptoetsen(PADPLUSKEY);
422 persptoetsen(PADMINUS);
429 setTransformViewMatrices(&Trans);
432 void checkFirstTime() {
433 if(Trans.mode==TFM_INIT) {
434 memset(&Trans, 0, sizeof(TransInfo));
435 Trans.propsize = 1.0;
439 static char *transform_to_undostr(TransInfo *t)
442 case TFM_TRANSLATION:
454 case TFM_SHRINKFATTEN:
455 return "Shrink/Fatten";
466 case TFM_BONE_ENVELOPE:
467 return "Bone Envelope";
472 /* ************************************************* */
474 static void transformEvent(unsigned short event, short val) {
475 float mati[3][3] = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
476 char cmode = constraintModeToChar(&Trans);
480 /* enforce redraw of transform when modifiers are used */
487 /* shift is modifier for higher resolution transform, works nice to store this mouse position */
488 getmouseco_areawin(Trans.shiftmval);
489 Trans.flag |= T_SHIFT_MOD;
494 if ((Trans.spacetype==SPACE_VIEW3D) && (G.qual & LR_ALTKEY)) {
498 BIF_selectOrientation();
499 calc_manipulator_stats(curarea);
500 Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
501 warp_pointer(mval[0], mval[1]);
504 Trans.state = TRANS_CONFIRM;
510 if ((Trans.flag & T_NO_CONSTRAINT)==0) {
511 /* exception for switching to dolly, or trackball, in camera view */
512 if (Trans.flag & T_CAMERA) {
513 if (Trans.mode==TFM_TRANSLATION)
514 setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
515 else if (Trans.mode==TFM_ROTATION) {
516 restoreTransObjects(&Trans);
517 initTransModeFlags(&Trans, TFM_TRACKBALL);
518 initTrackball(&Trans);
522 Trans.flag |= T_MMB_PRESSED;
523 if (Trans.con.mode & CON_APPLY) {
524 stopConstraint(&Trans);
527 if (G.qual & LR_CTRLKEY) {
528 initSelectConstraint(&Trans, Trans.spacemtx);
531 /* bit hackish... but it prevents mmb select to print the orientation from menu */
532 strcpy(Trans.spacename, "global");
533 initSelectConstraint(&Trans, mati);
535 postSelectConstraint(&Trans);
543 Trans.state = TRANS_CANCEL;
548 Trans.state = TRANS_CONFIRM;
551 /* only switch when... */
552 if( ELEM3(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) {
553 restoreTransObjects(&Trans);
554 initTransModeFlags(&Trans, TFM_TRANSLATION);
555 initTranslation(&Trans);
560 /* only switch when... */
561 if( ELEM3(Trans.mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) {
562 restoreTransObjects(&Trans);
563 initTransModeFlags(&Trans, TFM_RESIZE);
569 /* only switch when... */
570 if( ELEM4(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
572 if (Trans.mode == TFM_ROTATION) {
573 restoreTransObjects(&Trans);
574 initTransModeFlags(&Trans, TFM_TRACKBALL);
575 initTrackball(&Trans);
578 restoreTransObjects(&Trans);
579 initTransModeFlags(&Trans, TFM_ROTATION);
580 initRotation(&Trans);
586 if (G.qual & LR_ALTKEY) {
587 Trans.flag ^= T_PROP_CONNECTED;
588 sort_trans_data_dist(&Trans);
589 calculatePropRatio(&Trans);
593 stopConstraint(&Trans);
598 if ((Trans.flag & T_NO_CONSTRAINT)==0) {
600 if (Trans.con.mode & CON_USER) {
601 stopConstraint(&Trans);
605 setUserConstraint(&Trans, (CON_AXIS0), "along %s X");
606 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
607 setUserConstraint(&Trans, (CON_AXIS1|CON_AXIS2), "locking %s X");
612 setConstraint(&Trans, mati, (CON_AXIS0), "along global X");
613 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
614 setConstraint(&Trans, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
620 if ((Trans.flag & T_NO_CONSTRAINT)==0) {
622 if (Trans.con.mode & CON_USER) {
623 stopConstraint(&Trans);
627 setUserConstraint(&Trans, (CON_AXIS1), "along %s Y");
628 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
629 setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS2), "locking %s Y");
634 setConstraint(&Trans, mati, (CON_AXIS1), "along global Y");
635 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
636 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS2), "locking global Y");
642 if ((Trans.flag & T_NO_CONSTRAINT)==0) {
644 if (Trans.con.mode & CON_USER) {
645 stopConstraint(&Trans);
649 setUserConstraint(&Trans, (CON_AXIS2), "along %s Z");
650 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
651 setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS1), "locking %s Z");
654 else if ((Trans.flag & T_2D_EDIT)==0) {
656 setConstraint(&Trans, mati, (CON_AXIS2), "along global Z");
657 else if (G.qual == LR_SHIFTKEY)
658 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
664 if (Trans.flag & T_PROP_EDIT && G.qual==LR_SHIFTKEY) {
665 G.scene->prop_mode = (G.scene->prop_mode+1)%6;
666 calculatePropRatio(&Trans);
671 if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
672 Trans.propsize*= 1.1f;
673 calculatePropRatio(&Trans);
679 if(Trans.flag & T_PROP_EDIT) {
680 Trans.propsize*= 1.1f;
681 calculatePropRatio(&Trans);
683 else view_editmove(event);
687 if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
688 Trans.propsize*= 0.90909090f;
689 calculatePropRatio(&Trans);
695 if(Trans.flag & T_PROP_EDIT) {
696 Trans.propsize*= 0.90909090f;
697 calculatePropRatio(&Trans);
699 else view_editmove(event);
703 Trans.redraw |= handleNumInput(&(Trans.num), event);
704 arrows_move_cursor(event);
708 /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still
709 after releasing modifer key */
711 if ((Trans.flag & T_NO_CONSTRAINT)==0) {
712 Trans.flag &= ~T_MMB_PRESSED;
713 postSelectConstraint(&Trans);
719 if (Trans.context & CTX_TWEAK)
720 Trans.state = TRANS_CONFIRM;
724 /* shift is modifier for higher resolution transform */
725 Trans.flag &= ~T_SHIFT_MOD;
731 void initTransform(int mode, int context) {
732 /* added initialize, for external calls to set stuff in TransInfo, like undo string */
735 Trans.state = TRANS_RUNNING;
737 Trans.context = context;
739 initTrans(&Trans); // internal data, mouse, vectors
741 if(Trans.spacetype==SPACE_VIEW3D) {
742 calc_manipulator_stats(curarea);
743 Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
746 Mat3One(Trans.spacemtx);
748 initTransModeFlags(&Trans, mode); // modal settings in struct Trans
750 createTransData(&Trans); // make TransData structs from selection
752 if (Trans.total == 0) {
757 /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
758 /* EVIL2: we gave as argument also texture space context bit... was cleared */
761 calculatePropRatio(&Trans);
762 calculateCenter(&Trans);
765 case TFM_TRANSLATION:
766 initTranslation(&Trans);
769 initRotation(&Trans);
775 initToSphere(&Trans);
783 case TFM_SHRINKFATTEN:
784 initShrinkFatten(&Trans);
790 initTrackball(&Trans);
793 initPushPull(&Trans);
799 { /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
800 bArmature *arm= Trans.poseobj->data;
801 if(arm->drawtype==ARM_ENVELOPE)
802 initBoneEnvelope(&Trans);
804 initBoneSize(&Trans);
807 case TFM_BONE_ENVELOPE:
808 initBoneEnvelope(&Trans);
815 short pmval[2] = {0, 0}, mval[2], val;
816 unsigned short event;
818 if(Trans.total==0) return; // added, can happen now! (ton)
820 // Emptying event queue
822 event= extern_qread(&val);
825 Trans.redraw = 1; /* initial draw */
827 while (Trans.state == TRANS_RUNNING) {
829 getmouseco_areawin(mval);
831 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
832 if (Trans.flag & T_MMB_PRESSED)
833 Trans.con.mode |= CON_SELECT;
840 selectConstraint(&Trans);
841 if (Trans.transform) {
842 Trans.transform(&Trans, mval); // calls recalcData()
847 /* essential for idling subloop */
848 if( qtest()==0) PIL_sleep_ms(2);
851 event= extern_qread(&val);
852 transformEvent(event, val);
857 /* handle restoring objects */
858 if(Trans.state == TRANS_CANCEL)
859 restoreTransObjects(&Trans); // calls recalcData()
864 /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
865 special_aftertrans_update(&Trans);
867 /* send events out for redraws */
868 viewRedrawPost(&Trans);
870 /* Undo as last, certainly after special_trans_update! */
871 if(Trans.state == TRANS_CANCEL) {
872 if(Trans.undostr) BIF_undo_push(Trans.undostr);
875 if(Trans.undostr) BIF_undo_push(Trans.undostr);
876 else BIF_undo_push(transform_to_undostr(&Trans));
882 /* ************************** Manipulator init and main **************************** */
884 void initManipulator(int mode)
886 Trans.state = TRANS_RUNNING;
888 Trans.context = CTX_NONE;
890 /* automatic switch to scaling bone envelopes */
891 if(mode==TFM_RESIZE && G.obedit && G.obedit->type==OB_ARMATURE) {
892 bArmature *arm= G.obedit->data;
893 if(arm->drawtype==ARM_ENVELOPE)
894 mode= TFM_BONE_ENVELOPE;
897 initTrans(&Trans); // internal data, mouse, vectors
899 initTransModeFlags(&Trans, mode); // modal settings in struct Trans
901 G.moving |= G_TRANSFORM_MANIP; // signal to draw manipuls while transform
902 createTransData(&Trans); // make TransData structs from selection
904 if (Trans.total == 0)
907 /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
908 /* EVIL2: we gave as argument also texture space context bit... was cleared */
911 calculatePropRatio(&Trans);
912 calculateCenter(&Trans);
915 case TFM_TRANSLATION:
916 initTranslation(&Trans);
919 initRotation(&Trans);
925 initTrackball(&Trans);
929 Trans.flag |= T_USES_MANIPULATOR;
932 void ManipulatorTransform()
935 short pmval[2] = {0, 0}, mval[2], val;
936 unsigned short event;
938 if (Trans.total == 0)
941 Trans.redraw = 1; /* initial draw */
943 while (Trans.state == TRANS_RUNNING) {
945 getmouseco_areawin(mval);
947 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
954 //selectConstraint(&Trans); needed?
955 if (Trans.transform) {
956 Trans.transform(&Trans, mval);
961 /* essential for idling subloop */
962 if( qtest()==0) PIL_sleep_ms(2);
965 event= extern_qread(&val);
972 /* enforce redraw of transform when modifiers are used */
975 if(val) Trans.redraw = 1;
979 /* shift is modifier for higher resolution transform, works nice to store this mouse position */
981 getmouseco_areawin(Trans.shiftmval);
982 Trans.flag |= T_SHIFT_MOD;
985 else Trans.flag &= ~T_SHIFT_MOD;
990 Trans.state = TRANS_CANCEL;
993 if(mouse_moved==0 && val==0) break;
994 // else we pass on event to next, which cancels
998 Trans.state = TRANS_CONFIRM;
1003 case WHEELDOWNMOUSE:
1005 if(Trans.flag & T_PROP_EDIT) {
1006 Trans.propsize*= 1.1f;
1007 calculatePropRatio(&Trans);
1013 if(Trans.flag & T_PROP_EDIT) {
1014 Trans.propsize*= 0.90909090f;
1015 calculatePropRatio(&Trans);
1024 if(Trans.state == TRANS_CANCEL) {
1025 restoreTransObjects(&Trans);
1028 BIF_undo_push(transform_to_undostr(&Trans));
1031 /* free data, reset vars */
1034 /* aftertrans does insert ipos and action channels, and clears base flags */
1035 special_aftertrans_update(&Trans);
1037 /* send events out for redraws */
1038 viewRedrawPost(&Trans);
1041 /* ************************** TRANSFORMATIONS **************************** */
1043 static void protectedTransBits(short protectflag, float *vec)
1045 if(protectflag & OB_LOCK_LOCX)
1047 if(protectflag & OB_LOCK_LOCY)
1049 if(protectflag & OB_LOCK_LOCZ)
1053 static void protectedSizeBits(short protectflag, float *size)
1055 if(protectflag & OB_LOCK_SCALEX)
1057 if(protectflag & OB_LOCK_SCALEY)
1059 if(protectflag & OB_LOCK_SCALEZ)
1063 static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
1065 if(protectflag & OB_LOCK_ROTX)
1067 if(protectflag & OB_LOCK_ROTY)
1069 if(protectflag & OB_LOCK_ROTZ)
1073 static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
1075 /* quaternions get limited with euler... */
1076 /* this function only does the delta rotation */
1079 float eul[3], oldeul[3], quat1[4];
1081 QUATCOPY(quat1, quat);
1082 QuatToEul(quat, eul);
1083 QuatToEul(oldquat, oldeul);
1085 if(protectflag & OB_LOCK_ROTX)
1087 if(protectflag & OB_LOCK_ROTY)
1089 if(protectflag & OB_LOCK_ROTZ)
1092 EulToQuat(eul, quat);
1093 /* quaternions flip w sign to accumulate rotations correctly */
1094 if( (quat1[0]<0.0f && quat[0]>0.0f) || (quat1[0]>0.0f && quat[0]<0.0f) ) {
1095 QuatMulf(quat, -1.0f);
1100 /* ************************** WARP *************************** */
1102 /* warp is done fully in view space */
1103 void initWarp(TransInfo *t)
1105 float max[3], min[3];
1108 calculateCenterCursor(t);
1111 t->transform = Warp;
1116 t->fac = (float)(t->center2d[0] - t->imval[0]);
1118 /* we need min/max in view space */
1119 for(i = 0; i < t->total; i++) {
1121 VECCOPY(center, t->data[i].center);
1122 Mat3MulVecfl(t->data[i].mtx, center);
1123 Mat4MulVecfl(t->viewmat, center);
1124 VecSubf(center, center, t->viewmat[3]);
1126 MinMax3(min, max, center);
1128 VECCOPY(max, center);
1129 VECCOPY(min, center);
1133 t->center[0]= (min[0]+max[0])/2.0f;
1134 t->center[1]= (min[1]+max[1])/2.0f;
1135 t->center[2]= (min[2]+max[2])/2.0f;
1137 t->val= (max[0]-min[0])/2.0f; // t->val is free variable
1141 int Warp(TransInfo *t, short mval[2])
1143 TransData *td = t->data;
1144 float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
1148 curs= give_cursor();
1150 * gcursor is the one used for helpline.
1151 * It has to be in the same space as the drawing loop
1152 * (that means it needs to be in the object's space when in edit mode and
1153 * in global space in object mode)
1155 * cursor is used for calculations.
1156 * It needs to be in view space, but we need to take object's offset
1157 * into account if in Edit mode.
1159 VECCOPY(cursor, curs);
1160 VECCOPY(gcursor, cursor);
1161 if (t->flag & T_EDIT) {
1162 VecSubf(cursor, cursor, G.obedit->obmat[3]);
1163 VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
1164 Mat3MulVecfl(t->data->smtx, gcursor);
1166 Mat4MulVecfl(t->viewmat, cursor);
1167 VecSubf(cursor, cursor, t->viewmat[3]);
1169 // amount of degrees for warp, 450 = allow to create 360 degree warp
1170 circumfac= 450.0f*(mval[1] - t->imval[1]) / (float)(curarea->winy);
1173 snapGrid(t, &circumfac);
1174 applyNumInput(&t->num, &circumfac);
1176 /* header print for NumInput */
1177 if (hasNumInput(&t->num)) {
1180 outputNumInput(&(t->num), c);
1182 sprintf(str, "Warp: %s", c);
1185 /* default header print */
1186 sprintf(str, "Warp: %.3f", circumfac);
1189 circumfac*= (float)(-M_PI/360.0);
1191 for(i = 0 ; i < t->total; i++, td++) {
1193 if (td->flag & TD_NOACTION)
1196 /* translate point to centre, rotate in such a way that outline==distance */
1198 VECCOPY(vec, td->iloc);
1199 Mat3MulVecfl(td->mtx, vec);
1200 Mat4MulVecfl(t->viewmat, vec);
1201 VecSubf(vec, vec, t->viewmat[3]);
1203 dist= vec[0]-cursor[0];
1205 phi0= (circumfac*dist/t->val); // t->val is X dimension projected boundbox
1207 vec[1]= (vec[1]-cursor[1]);
1209 co= (float)cos(phi0);
1210 si= (float)sin(phi0);
1211 loc[0]= -si*vec[1]+cursor[0];
1212 loc[1]= co*vec[1]+cursor[1];
1215 Mat4MulVecfl(t->viewinv, loc);
1216 VecSubf(loc, loc, t->viewinv[3]);
1217 Mat3MulVecfl(td->smtx, loc);
1219 VecSubf(loc, loc, td->iloc);
1220 VecMulf(loc, td->factor);
1221 VecAddf(td->loc, td->iloc, loc);
1230 helpline(t, gcursor);
1235 /* ************************** SHEAR *************************** */
1237 void initShear(TransInfo *t)
1243 t->snap[2] = t->snap[1] * 0.1f;
1244 t->transform = Shear;
1247 int Shear(TransInfo *t, short mval[2])
1249 TransData *td = t->data;
1251 float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
1256 Mat3CpyMat4(persmat, t->viewmat);
1257 Mat3Inv(persinv, persmat);
1259 value = 0.05f * InputHorizontalAbsolute(t, mval);
1261 snapGrid(t, &value);
1263 applyNumInput(&t->num, &value);
1265 /* header print for NumInput */
1266 if (hasNumInput(&t->num)) {
1269 outputNumInput(&(t->num), c);
1271 sprintf(str, "Shear: %s %s", c, t->proptext);
1274 /* default header print */
1275 sprintf(str, "Shear: %.3f %s", value, t->proptext);
1280 Mat3MulMat3(tmat, smat, persmat);
1281 Mat3MulMat3(totmat, persinv, tmat);
1283 for(i = 0 ; i < t->total; i++, td++) {
1284 if (td->flag & TD_NOACTION)
1289 Mat3MulMat3(mat3, totmat, td->mtx);
1290 Mat3MulMat3(tmat, td->smtx, mat3);
1293 Mat3CpyMat3(tmat, totmat);
1295 VecSubf(vec, td->center, t->center);
1297 Mat3MulVecfl(tmat, vec);
1299 VecAddf(vec, vec, t->center);
1300 VecSubf(vec, vec, td->center);
1302 VecMulf(vec, td->factor);
1304 VecAddf(td->loc, td->iloc, vec);
1313 helpline (t, t->center);
1318 /* ************************** RESIZE *************************** */
1320 void initResize(TransInfo *t)
1322 t->fac = (float)sqrt(
1324 ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
1326 ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
1329 if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
1335 t->snap[2] = t->snap[1] * 0.1f;
1336 t->transform = Resize;
1339 static void headerResize(TransInfo *t, float vec[3], char *str) {
1341 if (hasNumInput(&t->num)) {
1342 outputNumInput(&(t->num), tvec);
1345 sprintf(&tvec[0], "%.4f", vec[0]);
1346 sprintf(&tvec[20], "%.4f", vec[1]);
1347 sprintf(&tvec[40], "%.4f", vec[2]);
1350 if (t->con.mode & CON_APPLY) {
1351 switch(t->num.idx_max) {
1353 sprintf(str, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
1356 sprintf(str, "Scale: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1359 sprintf(str, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1363 if (t->flag & T_2D_EDIT)
1364 sprintf(str, "Scale X: %s Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1366 sprintf(str, "Scale X: %s Y: %s Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1370 #define SIGN(a) (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3)
1371 #define VECSIGNFLIP(a, b) ((SIGN(a[0]) & SIGN(b[0]))==0 || (SIGN(a[1]) & SIGN(b[1]))==0 || (SIGN(a[2]) & SIGN(b[2]))==0)
1373 /* smat is reference matrix, only scaled */
1374 static void TransMat3ToSize( float mat[][3], float smat[][3], float *size)
1378 VecCopyf(vec, mat[0]);
1379 size[0]= Normalise(vec);
1380 VecCopyf(vec, mat[1]);
1381 size[1]= Normalise(vec);
1382 VecCopyf(vec, mat[2]);
1383 size[2]= Normalise(vec);
1385 /* first tried with dotproduct... but the sign flip is crucial */
1386 if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0];
1387 if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1];
1388 if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2];
1392 static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
1393 float tmat[3][3], smat[3][3], center[3];
1396 if (t->flag & T_EDIT) {
1397 Mat3MulMat3(smat, mat, td->mtx);
1398 Mat3MulMat3(tmat, td->smtx, smat);
1401 Mat3CpyMat3(tmat, mat);
1404 if (t->con.applySize) {
1405 t->con.applySize(t, td, tmat);
1408 /* local constraint shouldn't alter center */
1409 if (t->around == V3D_LOCAL) {
1410 if (t->flag & T_OBJECT) {
1411 VECCOPY(center, td->center);
1413 else if (t->flag & T_EDIT) {
1415 if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
1416 VECCOPY(center, td->center);
1419 VECCOPY(center, t->center);
1423 VECCOPY(center, t->center);
1427 VECCOPY(center, t->center);
1433 if (t->flag & (T_OBJECT|T_TEXTURE)) {
1434 float obsizemat[3][3];
1435 // Reorient the size mat to fit the oriented object.
1436 Mat3MulMat3(obsizemat, tmat, td->axismtx);
1437 //printmatrix3("obsizemat", obsizemat);
1438 TransMat3ToSize(obsizemat, td->axismtx, fsize);
1439 //printvecf("fsize", fsize);
1442 Mat3ToSize(tmat, fsize);
1445 protectedSizeBits(td->protectflag, fsize);
1447 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
1448 /* handle ipokeys? */
1450 TransDataIpokey *tdi= td->tdi;
1451 /* calculate delta size (equal for size and dsize) */
1453 vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
1454 vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
1455 vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
1457 add_tdi_poin(tdi->sizex, tdi->oldsize, vec[0]);
1458 add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
1459 add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
1462 else if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){
1463 /* scale val and reset size */
1464 *td->val = td->ival * fsize[0] * td->factor;
1466 td->ext->size[0] = td->ext->isize[0];
1467 td->ext->size[1] = td->ext->isize[1];
1468 td->ext->size[2] = td->ext->isize[2];
1471 /* Reset val if SINGLESIZE but using a constraint */
1472 if (td->flag & TD_SINGLESIZE)
1473 *td->val = td->ival;
1475 td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
1476 td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
1477 td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
1481 /* For individual element center, Editmode need to use iloc */
1482 if (t->flag & T_POINTS)
1483 VecSubf(vec, td->iloc, center);
1485 VecSubf(vec, td->center, center);
1487 Mat3MulVecfl(tmat, vec);
1489 VecAddf(vec, vec, center);
1490 if (t->flag & T_POINTS)
1491 VecSubf(vec, vec, td->iloc);
1493 VecSubf(vec, vec, td->center);
1495 VecMulf(vec, td->factor);
1497 if (t->flag & T_OBJECT) {
1498 Mat3MulVecfl(td->smtx, vec);
1501 protectedTransBits(td->protectflag, vec);
1504 TransDataIpokey *tdi= td->tdi;
1505 add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
1506 add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
1507 add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
1509 else VecAddf(td->loc, td->iloc, vec);
1512 int Resize(TransInfo *t, short mval[2])
1515 float size[3], mat[3][3];
1520 /* for manipulator, center handle, the scaling can't be done relative to center */
1521 if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
1522 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
1525 ratio = InputScaleRatio(t, mval);
1527 /* flip scale, but not for manipulator center handle */
1528 if ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) +
1529 (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
1533 size[0] = size[1] = size[2] = ratio;
1537 if (hasNumInput(&t->num)) {
1538 applyNumInput(&t->num, size);
1539 constraintNumInput(t, size);
1542 SizeToMat3(size, mat);
1544 if (t->con.applySize) {
1545 t->con.applySize(t, NULL, mat);
1548 Mat3CpyMat3(t->mat, mat); // used in manipulator
1550 headerResize(t, size, str);
1552 for(i = 0, td=t->data; i < t->total; i++, td++) {
1553 if (td->flag & TD_NOACTION)
1556 ElementResize(t, td, mat);
1559 /* evil hack - redo resize if cliiping needeed */
1560 if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
1561 SizeToMat3(size, mat);
1563 if (t->con.applySize)
1564 t->con.applySize(t, NULL, mat);
1566 for(i = 0, td=t->data; i < t->total; i++, td++)
1567 ElementResize(t, td, mat);
1576 if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
1581 /* ************************** TOSPHERE *************************** */
1583 void initToSphere(TransInfo *t)
1585 TransData *td = t->data;
1588 // Calculate average radius
1589 for(i = 0 ; i < t->total; i++, td++) {
1590 t->val += VecLenf(t->center, td->iloc);
1593 t->val /= (float)t->total;
1599 t->snap[2] = t->snap[1] * 0.1f;
1600 t->transform = ToSphere;
1605 int ToSphere(TransInfo *t, short mval[2])
1608 float ratio, radius;
1611 TransData *td = t->data;
1613 ratio = InputHorizontalRatio(t, mval);
1615 snapGrid(t, &ratio);
1617 applyNumInput(&t->num, &ratio);
1624 /* header print for NumInput */
1625 if (hasNumInput(&t->num)) {
1628 outputNumInput(&(t->num), c);
1630 sprintf(str, "To Sphere: %s %s", c, t->proptext);
1633 /* default header print */
1634 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
1638 for(i = 0 ; i < t->total; i++, td++) {
1640 if (td->flag & TD_NOACTION)
1643 VecSubf(vec, td->iloc, t->center);
1645 radius = Normalise(vec);
1647 tratio = ratio * td->factor;
1649 VecMulf(vec, radius * (1.0f - tratio) + t->val * tratio);
1651 VecAddf(td->loc, t->center, vec);
1663 /* ************************** ROTATION *************************** */
1666 void initRotation(TransInfo *t)
1671 t->snap[1] = (float)((5.0/180)*M_PI);
1672 t->snap[2] = t->snap[1] * 0.2f;
1674 t->transform = Rotation;
1677 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
1678 float vec[3], totmat[3][3], smat[3][3];
1679 float eul[3], fmat[3][3], quat[4];
1681 if (t->flag & T_POINTS) {
1682 Mat3MulMat3(totmat, mat, td->mtx);
1683 Mat3MulMat3(smat, td->smtx, totmat);
1685 VecSubf(vec, td->iloc, t->center);
1686 Mat3MulVecfl(smat, vec);
1688 VecAddf(td->loc, vec, t->center);
1690 if(td->flag & TD_USEQUAT) {
1691 Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1692 Mat3ToQuat(fmat, quat); // Actual transform
1693 QuatMul(td->ext->quat, quat, td->ext->iquat);
1699 VecSubf(vec, td->center, t->center);
1700 Mat3MulVecfl(mat, vec);
1701 VecAddf(vec, vec, t->center);
1702 /* vec now is the location where the object has to be */
1703 VecSubf(vec, vec, td->center);
1704 Mat3MulVecfl(td->smtx, vec);
1706 protectedTransBits(td->protectflag, vec);
1709 TransDataIpokey *tdi= td->tdi;
1710 add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
1711 add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
1712 add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
1714 else VecAddf(td->loc, td->iloc, vec);
1718 if(td->flag & TD_USEQUAT) {
1719 Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1720 Mat3ToQuat(fmat, quat); // Actual transform
1722 QuatMul(td->ext->quat, quat, td->ext->iquat);
1723 /* this function works on end result */
1724 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
1726 else if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
1729 /* are there ipo keys? */
1731 TransDataIpokey *tdi= td->tdi;
1734 /* calculate the total rotatation in eulers */
1735 VecAddf(eul, td->ext->irot, td->ext->drot);
1736 EulToMat3(eul, obmat);
1737 /* mat = transform, obmat = object rotation */
1738 Mat3MulMat3(fmat, mat, obmat);
1739 Mat3ToEul(fmat, eul);
1740 compatible_eul(eul, td->ext->irot);
1742 /* correct back for delta rot */
1743 if(tdi->flag & TOB_IPODROT) {
1744 VecSubf(rot, eul, td->ext->irot);
1747 VecSubf(rot, eul, td->ext->drot);
1750 VecMulf(rot, (float)(9.0/M_PI_2));
1751 VecSubf(rot, rot, tdi->oldrot);
1753 protectedRotateBits(td->protectflag, rot, tdi->oldrot);
1755 add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
1756 add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
1757 add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
1760 Mat3MulMat3(totmat, mat, td->mtx);
1761 Mat3MulMat3(smat, td->smtx, totmat);
1763 /* calculate the total rotatation in eulers */
1764 VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
1765 EulToMat3(eul, obmat);
1766 /* mat = transform, obmat = object rotation */
1767 Mat3MulMat3(fmat, smat, obmat);
1768 Mat3ToEul(fmat, eul);
1769 compatible_eul(eul, td->ext->irot);
1771 /* correct back for delta rot */
1772 VecSubf(eul, eul, td->ext->drot);
1775 protectedRotateBits(td->protectflag, eul, td->ext->irot);
1776 VECCOPY(td->ext->rot, eul);
1782 static void applyRotation(TransInfo *t, float angle, float axis[3])
1784 TransData *td = t->data;
1785 float mat[3][3], center[3];
1788 /* saving original center */
1789 if (t->around == V3D_LOCAL) {
1790 VECCOPY(center, t->center);
1793 VecRotToMat3(axis, angle, mat);
1795 for(i = 0 ; i < t->total; i++, td++) {
1797 if (td->flag & TD_NOACTION)
1800 /* local constraint shouldn't alter center */
1801 if (t->around == V3D_LOCAL) {
1802 if (t->flag & (T_OBJECT|T_POSE)) {
1803 VECCOPY(t->center, td->center);
1806 if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
1807 VECCOPY(t->center, td->center);
1812 if (t->con.applyRot) {
1813 t->con.applyRot(t, td, axis);
1814 VecRotToMat3(axis, angle * td->factor, mat);
1816 else if (t->flag & T_PROP_EDIT) {
1817 VecRotToMat3(axis, angle * td->factor, mat);
1820 ElementRotation(t, td, mat);
1823 /* restoring original center */
1824 if (t->around == V3D_LOCAL) {
1825 VECCOPY(t->center, center);
1829 int Rotation(TransInfo *t, short mval[2])
1831 TransData *td = t->data;
1836 int dx2 = t->center2d[0] - mval[0];
1837 int dy2 = t->center2d[1] - mval[1];
1838 double B = sqrt(dx2*dx2+dy2*dy2);
1840 int dx1 = t->center2d[0] - t->imval[0];
1841 int dy1 = t->center2d[1] - t->imval[1];
1842 double A = sqrt(dx1*dx1+dy1*dy1);
1844 int dx3 = mval[0] - t->imval[0];
1845 int dy3 = mval[1] - t->imval[1];
1846 /* use doubles here, to make sure a "1.0" (no rotation) doesnt become 9.999999e-01, which gives 0.02 for acos */
1847 double deler= ((double)((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3) ))
1848 / (2.0 * (A*B?A*B:1.0));
1849 /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
1856 VECCOPY(axis, t->viewinv[2]);
1857 VecMulf(axis, -1.0f);
1860 dphi = saacos((float)deler);
1861 if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
1863 if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
1864 else t->fac += dphi;
1867 clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
1868 if (t->fac >= 2 * M_PI)
1870 else if (t->fac <= -2 * M_PI)
1871 t->fac -= -2 * M_PI;
1876 snapGrid(t, &final);
1878 t->imval[0] = mval[0];
1879 t->imval[1] = mval[1];
1881 if (t->con.applyRot) {
1882 t->con.applyRot(t, NULL, axis);
1885 if (hasNumInput(&t->num)) {
1888 applyNumInput(&t->num, &final);
1890 outputNumInput(&(t->num), c);
1892 sprintf(str, "Rot: %s %s", &c[0], t->proptext);
1894 final *= (float)(M_PI / 180.0);
1897 sprintf(str, "Rot: %.2f%s %s", 180.0*final/M_PI, t->con.text, t->proptext);
1900 VecRotToMat3(axis, final * td->factor, mat);
1902 t->val = final; // used in manipulator
1903 Mat3CpyMat3(t->mat, mat); // used in manipulator
1905 applyRotation(t, final, axis);
1913 if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
1919 /* ************************** TRACKBALL *************************** */
1921 void initTrackball(TransInfo *t)
1926 t->snap[1] = (float)((5.0/180)*M_PI);
1927 t->snap[2] = t->snap[1] * 0.2f;
1929 t->transform = Trackball;
1931 t->flag |= T_NO_CONSTRAINT; /* making sure the flag is always set */
1934 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
1936 TransData *td = t->data;
1937 float mat[3][3], smat[3][3], totmat[3][3];
1940 VecRotToMat3(axis1, angles[0], smat);
1941 VecRotToMat3(axis2, angles[1], totmat);
1943 Mat3MulMat3(mat, smat, totmat);
1945 for(i = 0 ; i < t->total; i++, td++) {
1946 if (td->flag & TD_NOACTION)
1949 if (t->around == V3D_LOCAL) {
1950 if (t->flag & T_OBJECT)
1951 VECCOPY(t->center, td->center); // not supported in editmode yet
1954 if (t->flag & T_PROP_EDIT) {
1955 VecRotToMat3(axis1, td->factor * angles[0], smat);
1956 VecRotToMat3(axis2, td->factor * angles[1], totmat);
1958 Mat3MulMat3(mat, smat, totmat);
1961 ElementRotation(t, td, mat);
1965 int Trackball(TransInfo *t, short mval[2])
1968 float axis1[3], axis2[3];
1969 float mat[3][3], totmat[3][3], smat[3][3];
1972 VECCOPY(axis1, t->persinv[0]);
1973 VECCOPY(axis2, t->persinv[1]);
1977 /* factore has to become setting or so */
1978 phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
1979 phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
1981 //if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
1982 //else t->fac += dphi;
1986 if (hasNumInput(&t->num)) {
1989 applyNumInput(&t->num, phi);
1991 outputNumInput(&(t->num), c);
1993 sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
1995 phi[0] *= (float)(M_PI / 180.0);
1996 phi[1] *= (float)(M_PI / 180.0);
1999 sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
2002 VecRotToMat3(axis1, phi[0], smat);
2003 VecRotToMat3(axis2, phi[1], totmat);
2005 Mat3MulMat3(mat, smat, totmat);
2007 Mat3CpyMat3(t->mat, mat); // used in manipulator
2009 applyTrackball(t, axis1, axis2, phi);
2017 if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2022 /* ************************** TRANSLATION *************************** */
2024 void initTranslation(TransInfo *t)
2026 t->idx_max = (t->flag & T_2D_EDIT)? 1: 2;
2027 t->num.idx_max = t->idx_max;
2028 t->transform = Translation;
2030 if(t->spacetype == SPACE_VIEW3D) {
2031 /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
2032 if(t->flag & (T_EDIT|T_POSE)) {
2033 Object *ob= G.obedit?G.obedit:t->poseobj;
2036 VECCOPY(vec, t->center);
2037 Mat4MulVecfl(ob->obmat, vec);
2038 initgrabz(vec[0], vec[1], vec[2]);
2040 else initgrabz(t->center[0], t->center[1], t->center[2]);
2043 t->snap[1] = G.vd->gridview * 1.0f;
2044 t->snap[2] = t->snap[1] * 0.1f;
2046 else if(t->spacetype == SPACE_IMAGE) {
2048 t->snap[1] = 0.125f;
2049 t->snap[2] = 0.0625f;
2053 t->snap[1] = t->snap[2] = 1.0f;
2057 static void headerTranslation(TransInfo *t, float vec[3], char *str) {
2063 convertVecToDisplayNum(vec, dvec);
2065 if (hasNumInput(&t->num)) {
2066 outputNumInput(&(t->num), tvec);
2067 dist = VecLength(t->num.val);
2070 dist = VecLength(vec);
2071 sprintf(&tvec[0], "%.4f", dvec[0]);
2072 sprintf(&tvec[20], "%.4f", dvec[1]);
2073 sprintf(&tvec[40], "%.4f", dvec[2]);
2076 if( dist > 1e10 || dist < -1e10 ) /* prevent string buffer overflow */
2077 sprintf(distvec, "%.4e", dist);
2079 sprintf(distvec, "%.4f", dist);
2081 if (t->con.mode & CON_APPLY) {
2082 switch(t->num.idx_max) {
2084 sprintf(str, "D: %s (%s)%s %s", &tvec[0], distvec, t->con.text, t->proptext);
2087 sprintf(str, "D: %s D: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
2090 sprintf(str, "D: %s D: %s D: %s (%s)%s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext);
2094 if(t->flag & T_2D_EDIT)
2095 sprintf(str, "Dx: %s Dy: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
2097 sprintf(str, "Dx: %s Dy: %s Dz: %s (%s)%s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext);
2101 static void applyTranslation(TransInfo *t, float vec[3]) {
2102 TransData *td = t->data;
2106 for(i = 0 ; i < t->total; i++, td++) {
2107 if (td->flag & TD_NOACTION)
2110 if (t->con.applyVec) {
2112 t->con.applyVec(t, td, vec, tvec, pvec);
2118 Mat3MulVecfl(td->smtx, tvec);
2119 VecMulf(tvec, td->factor);
2121 protectedTransBits(td->protectflag, tvec);
2123 /* transdata ipokey */
2125 TransDataIpokey *tdi= td->tdi;
2126 add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
2127 add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
2128 add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
2130 else VecAddf(td->loc, td->iloc, tvec);
2134 /* uses t->vec to store actual translation in */
2135 int Translation(TransInfo *t, short mval[2])
2140 if(t->flag & T_SHIFT_MOD) {
2142 /* calculate the main translation and the precise one separate */
2143 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
2144 VecMulf(dvec, 0.1f);
2145 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
2146 VecAddf(t->vec, t->vec, dvec);
2148 else convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2150 if (t->con.mode & CON_APPLY) {
2151 float pvec[3] = {0.0f, 0.0f, 0.0f};
2152 t->con.applyVec(t, NULL, t->vec, tvec, pvec);
2153 VECCOPY(t->vec, tvec);
2154 headerTranslation(t, pvec, str);
2157 snapGrid(t, t->vec);
2158 applyNumInput(&t->num, t->vec);
2159 headerTranslation(t, t->vec, str);
2162 applyTranslation(t, t->vec);
2164 /* evil hack - redo translation if cliiping needeed */
2165 if (t->flag & T_CLIP_UV && clipUVTransform(t, t->vec, 0))
2166 applyTranslation(t, t->vec);
2177 /* ************************** SHRINK/FATTEN *************************** */
2179 void initShrinkFatten(TransInfo *t)
2181 if (G.obedit==NULL || G.obedit->type != OB_MESH) {
2182 initTransModeFlags(t, TFM_RESIZE);
2191 t->snap[2] = t->snap[1] * 0.1f;
2192 t->transform = ShrinkFatten;
2197 int ShrinkFatten(TransInfo *t, short mval[2])
2203 TransData *td = t->data;
2205 distance = -InputVerticalAbsolute(t, mval);
2207 snapGrid(t, &distance);
2209 applyNumInput(&t->num, &distance);
2211 /* header print for NumInput */
2212 if (hasNumInput(&t->num)) {
2215 outputNumInput(&(t->num), c);
2217 sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
2220 /* default header print */
2221 sprintf(str, "Shrink/Fatten: %.4f %s", distance, t->proptext);
2225 for(i = 0 ; i < t->total; i++, td++) {
2226 if (td->flag & TD_NOACTION)
2229 VECCOPY(vec, td->axismtx[2]);
2230 VecMulf(vec, distance);
2231 VecMulf(vec, td->factor);
2233 VecAddf(td->loc, td->iloc, vec);
2245 /* ************************** TILT *************************** */
2247 void initTilt(TransInfo *t)
2252 t->snap[1] = (float)((5.0/180)*M_PI);
2253 t->snap[2] = t->snap[1] * 0.2f;
2255 t->transform = Tilt;
2260 int Tilt(TransInfo *t, short mval[2])
2262 TransData *td = t->data;
2268 int dx2 = t->center2d[0] - mval[0];
2269 int dy2 = t->center2d[1] - mval[1];
2270 float B = (float)sqrt(dx2*dx2+dy2*dy2);
2272 int dx1 = t->center2d[0] - t->imval[0];
2273 int dy1 = t->center2d[1] - t->imval[1];
2274 float A = (float)sqrt(dx1*dx1+dy1*dy1);
2276 int dx3 = mval[0] - t->imval[0];
2277 int dy3 = mval[1] - t->imval[1];
2279 float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
2284 dphi = saacos(deler);
2285 if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
2287 if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2288 else t->fac += dphi;
2292 snapGrid(t, &final);
2294 t->imval[0] = mval[0];
2295 t->imval[1] = mval[1];
2297 if (hasNumInput(&t->num)) {
2300 applyNumInput(&t->num, &final);
2302 outputNumInput(&(t->num), c);
2304 sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
2306 final *= (float)(M_PI / 180.0);
2309 sprintf(str, "Tilt: %.2f %s", 180.0*final/M_PI, t->proptext);
2312 for(i = 0 ; i < t->total; i++, td++) {
2313 if (td->flag & TD_NOACTION)
2317 *td->val = td->ival + final * td->factor;
2327 helpline (t, t->center);
2332 /* ************************** PUSH/PULL *************************** */
2334 void initPushPull(TransInfo *t)
2340 t->snap[2] = t->snap[1] * 0.1f;
2341 t->transform = PushPull;
2346 int PushPull(TransInfo *t, short mval[2])
2348 float vec[3], axis[3];
2352 TransData *td = t->data;
2354 distance = InputVerticalAbsolute(t, mval);
2356 snapGrid(t, &distance);
2358 applyNumInput(&t->num, &distance);
2360 /* header print for NumInput */
2361 if (hasNumInput(&t->num)) {
2364 outputNumInput(&(t->num), c);
2366 sprintf(str, "Push/Pull: %s%s %s", c, t->con.text, t->proptext);
2369 /* default header print */
2370 sprintf(str, "Push/Pull: %.4f%s %s", distance, t->con.text, t->proptext);
2373 if (t->con.applyRot && t->con.mode & CON_APPLY) {
2374 t->con.applyRot(t, NULL, axis);
2377 for(i = 0 ; i < t->total; i++, td++) {
2378 if (td->flag & TD_NOACTION)
2381 VecSubf(vec, t->center, td->center);
2382 if (t->con.applyRot && t->con.mode & CON_APPLY) {
2383 t->con.applyRot(t, td, axis);
2384 if (isLockConstraint(t)) {
2386 Projf(dvec, vec, axis);
2387 VecSubf(vec, vec, dvec);
2390 Projf(vec, vec, axis);
2394 VecMulf(vec, distance);
2395 VecMulf(vec, td->factor);
2397 VecAddf(td->loc, td->iloc, vec);
2409 /* ************************** CREASE *************************** */
2411 void initCrease(TransInfo *t)
2417 t->snap[2] = t->snap[1] * 0.1f;
2418 t->transform = Crease;
2419 t->fac = (float)sqrt(
2421 ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
2423 ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
2426 if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
2429 int Crease(TransInfo *t, short mval[2])
2431 TransData *td = t->data;
2437 if(t->flag & T_SHIFT_MOD) {
2438 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2439 float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2440 float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2441 crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
2443 dx= (float)(t->center2d[0] - mval[0]);
2444 dy= (float)(t->center2d[1] - mval[1]);
2445 crease+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -crease);
2449 float dx= (float)(t->center2d[0] - mval[0]);
2450 float dy= (float)(t->center2d[1] - mval[1]);
2451 crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
2455 if (crease > 1.0f) crease = 1.0f;
2457 snapGrid(t, &crease);
2459 applyNumInput(&t->num, &crease);
2461 /* header print for NumInput */
2462 if (hasNumInput(&t->num)) {
2465 outputNumInput(&(t->num), c);
2468 sprintf(str, "Crease: +%s %s", c, t->proptext);
2470 sprintf(str, "Crease: %s %s", c, t->proptext);
2473 /* default header print */
2475 sprintf(str, "Crease: +%.3f %s", crease, t->proptext);
2477 sprintf(str, "Crease: %.3f %s", crease, t->proptext);
2480 for(i = 0 ; i < t->total; i++, td++) {
2481 if (td->flag & TD_NOACTION)
2485 *td->val = td->ival + crease * td->factor;
2486 if (*td->val < 0.0f) *td->val = 0.0f;
2487 if (*td->val > 1.0f) *td->val = 1.0f;
2497 helpline (t, t->center);
2502 /* ************************** MIRROR *************************** */
2504 void Mirror(short mode)
2507 float mati[3][3], matview[3][3], mat[3][3];
2511 Trans.context = CTX_NO_PET;
2513 initTrans(&Trans); // internal data, mouse, vectors
2516 Mat3CpyMat4(matview, Trans.viewinv); // t->viewinv was set in initTrans
2519 initTransModeFlags(&Trans, TFM_MIRROR); // modal settings in struct Trans
2521 createTransData(&Trans); // make TransData structs from selection
2523 calculatePropRatio(&Trans);
2524 calculateCenter(&Trans);
2528 if (Trans.total == 0) {
2533 size[0] = size[1] = size[2] = 1.0f;
2539 setConstraint(&Trans, mati, (CON_AXIS0), "");
2543 setConstraint(&Trans, mati, (CON_AXIS1), "");
2547 setConstraint(&Trans, mati, (CON_AXIS2), "");
2551 setLocalConstraint(&Trans, (CON_AXIS0), "");
2555 setLocalConstraint(&Trans, (CON_AXIS1), "");
2559 setLocalConstraint(&Trans, (CON_AXIS2), "");
2563 setConstraint(&Trans, matview, (CON_AXIS0), "");
2567 setConstraint(&Trans, matview, (CON_AXIS1), "");
2571 setConstraint(&Trans, matview, (CON_AXIS2), "");
2577 SizeToMat3(size, mat);
2579 if (Trans.con.applySize) {
2580 Trans.con.applySize(&Trans, NULL, mat);
2583 for(i = 0 ; i < Trans.total; i++, td++) {
2584 if (td->flag & TD_NOACTION)
2587 ElementResize(&Trans, td, mat);
2592 BIF_undo_push("Mirror");
2594 /* free data, reset vars */
2597 /* send events out for redraws */
2598 viewRedrawPost(&Trans);
2601 /* ******************** EditBone (B-bone) width scaling *************** */
2603 static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
2605 float tmat[3][3], smat[3][3], oldy;
2606 float sizemat[3][3];
2608 Mat3MulMat3(smat, mat, td->mtx);
2609 Mat3MulMat3(tmat, td->smtx, smat);
2611 if (t->con.applySize) {
2612 t->con.applySize(t, td, tmat);
2615 /* we've tucked the scale in loc */
2617 SizeToMat3(td->iloc, sizemat);
2618 Mat3MulMat3(tmat, tmat, sizemat);
2619 Mat3ToSize(tmat, td->loc);
2624 int BoneSize(TransInfo *t, short mval[2])
2626 TransData *td = t->data;
2627 float size[3], mat[3][3];
2632 /* for manipulator, center handle, the scaling can't be done relative to center */
2633 if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
2634 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
2638 if(t->flag & T_SHIFT_MOD) {
2639 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2640 float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2641 float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2642 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2644 dx= (float)(t->center2d[0] - mval[0]);
2645 dy= (float)(t->center2d[1] - mval[1]);
2646 ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
2650 float dx= (float)(t->center2d[0] - mval[0]);
2651 float dy= (float)(t->center2d[1] - mval[1]);
2652 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2655 /* flip scale, but not for manipulator center handle */
2656 if ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) +
2657 (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
2661 size[0] = size[1] = size[2] = ratio;
2665 if (hasNumInput(&t->num)) {
2666 applyNumInput(&t->num, size);
2667 constraintNumInput(t, size);
2670 SizeToMat3(size, mat);
2672 if (t->con.applySize) {
2673 t->con.applySize(t, NULL, mat);
2676 Mat3CpyMat3(t->mat, mat); // used in manipulator
2678 headerResize(t, size, str);
2680 for(i = 0 ; i < t->total; i++, td++) {
2681 if (td->flag & TD_NOACTION)
2684 ElementBoneSize(t, td, mat);
2693 if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2698 void initBoneSize(TransInfo *t)
2704 t->snap[2] = t->snap[1] * 0.1f;
2705 t->transform = BoneSize;
2706 t->fac = (float)sqrt( (
2707 ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
2709 ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
2712 if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
2715 /* ******************** EditBone envelope *************** */
2717 int BoneEnvelope(TransInfo *t, short mval[2])
2719 TransData *td = t->data;
2724 if(t->flag & T_SHIFT_MOD) {
2725 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2726 float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2727 float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2728 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2730 dx= (float)(t->center2d[0] - mval[0]);
2731 dy= (float)(t->center2d[1] - mval[1]);
2732 ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
2736 float dx= (float)(t->center2d[0] - mval[0]);
2737 float dy= (float)(t->center2d[1] - mval[1]);
2738 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2741 snapGrid(t, &ratio);
2743 applyNumInput(&t->num, &ratio);
2745 /* header print for NumInput */
2746 if (hasNumInput(&t->num)) {
2749 outputNumInput(&(t->num), c);
2750 sprintf(str, "Envelope: %s", c);
2753 sprintf(str, "Envelope: %3f", ratio);
2756 for(i = 0 ; i < t->total; i++, td++) {
2757 if (td->flag & TD_NOACTION)
2760 if(td->val) *td->val= td->ival*ratio;
2769 if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2774 void initBoneEnvelope(TransInfo *t)
2780 t->snap[2] = t->snap[1] * 0.1f;
2781 t->transform = BoneEnvelope;
2782 t->fac = (float)sqrt( (
2783 ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
2785 ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
2788 if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
2791 /* ************************************ */
2793 void BIF_TransformSetUndo(char *str)