making the new transform methods work on Os X
[blender.git] / source / blender / src / transform.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 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
12  * about this.
13  *
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.
18  *
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.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <math.h>
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #ifndef WIN32
43 #include <unistd.h>
44 #else
45 #include <io.h>
46 #endif
47
48 #include "MEM_guardedalloc.h"
49
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"
64
65 #include "BIF_editview.h"               /* arrows_move_cursor   */
66 #include "BIF_gl.h"
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 */
78
79 #include "BKE_global.h"
80 #include "BKE_utildefines.h"
81 #include "BKE_bad_level_calls.h"/* popmenu and error    */
82
83 #include "BSE_view.h"
84
85 #include "BLI_arithb.h"
86 #include "BLI_blenlib.h"
87 #include "BLI_editVert.h"
88
89 #include "PIL_time.h"                   /* sleep                                */
90
91 #include "blendef.h"
92
93 #include "mydevice.h"
94
95 #include "transform.h"
96
97 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING  */
98 TransInfo Trans = {TFM_INIT, 0};        // enforce init on first usage
99
100 /******************************** Helper functions ************************************/
101
102 /* GLOBAL Wrapper Fonctions */
103
104 void BIF_drawSnap()
105 {
106         drawSnapping(&Trans);
107 }
108
109 /* ************************** Dashed help line **************************** */
110
111
112 /* bad frontbuffer call... because it is used in transform after force_draw() */
113 static void helpline(TransInfo *t, float *vec)
114 {
115         float vecrot[3], cent[2];
116         short mval[2];
117         
118         VECCOPY(vecrot, vec);
119         if(t->flag & T_EDIT) {
120                 Object *ob=G.obedit;
121                 if(ob) Mat4MulVecfl(ob->obmat, vecrot);
122         }
123         else if(t->flag & T_POSE) {
124                 Object *ob=t->poseobj;
125                 if(ob) Mat4MulVecfl(ob->obmat, vecrot);
126         }
127         
128         getmouseco_areawin(mval);
129         projectFloatView(t, vecrot, cent);      // no overflow in extreme cases
130         if(cent[0]!=IS_CLIPPED) {
131                 persp(PERSP_WIN);
132                 
133                 glDrawBuffer(GL_FRONT);
134                 
135                 BIF_ThemeColor(TH_WIRE);
136                 
137                 setlinestyle(3);
138                 glBegin(GL_LINE_STRIP); 
139                 glVertex2sv(mval); 
140                 glVertex2fv(cent); 
141                 glEnd();
142                 setlinestyle(0);
143                 
144                 persp(PERSP_VIEW);
145                 bglFlush(); // flush display for frontbuffer
146                 glDrawBuffer(GL_BACK);
147         }
148 }
149 /* ************************** INPUT FROM MOUSE *************************** */
150
151 float InputScaleRatio(TransInfo *t, short mval[2]) {
152         float ratio, dx, dy;
153         if(t->flag & T_SHIFT_MOD) {
154                 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
155                 dx = (float)(t->center2d[0] - t->shiftmval[0]);
156                 dy = (float)(t->center2d[1] - t->shiftmval[1]);
157                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
158                 
159                 dx= (float)(t->center2d[0] - mval[0]);
160                 dy= (float)(t->center2d[1] - mval[1]);
161                 ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
162         }
163         else {
164                 dx = (float)(t->center2d[0] - mval[0]);
165                 dy = (float)(t->center2d[1] - mval[1]);
166                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
167         }
168         return ratio;
169 }
170
171 float InputHorizontalRatio(TransInfo *t, short mval[2]) {
172         float x, pad;
173
174         pad = curarea->winx / 10;
175
176         if (t->flag & T_SHIFT_MOD) {
177                 /* deal with Shift key by adding motion / 10 to motion before shift press */
178                 x = t->shiftmval[0] + (float)(mval[0] - t->shiftmval[0]) / 10.0f;
179         }
180         else {
181                 x = mval[0];
182         }
183         return (x - pad) / (curarea->winx - 2 * pad);
184 }
185
186 float InputHorizontalAbsolute(TransInfo *t, short mval[2]) {
187         float vec[3];
188         if(t->flag & T_SHIFT_MOD) {
189                 float dvec[3];
190                 /* calculate the main translation and the precise one separate */
191                 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
192                 VecMulf(dvec, 0.1f);
193                 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
194                 VecAddf(t->vec, t->vec, dvec);
195         }
196         else {
197                 convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
198         }
199         Projf(vec, t->vec, t->viewinv[0]);
200         return Inpf(t->viewinv[0], vec) * 2.0f;
201 }
202
203 float InputVerticalRatio(TransInfo *t, short mval[2]) {
204         float y, pad;
205
206         pad = curarea->winy / 10;
207
208         if (t->flag & T_SHIFT_MOD) {
209                 /* deal with Shift key by adding motion / 10 to motion before shift press */
210                 y = t->shiftmval[1] + (float)(mval[1] - t->shiftmval[1]) / 10.0f;
211         }
212         else {
213                 y = mval[0];
214         }
215         return (y - pad) / (curarea->winy - 2 * pad);
216 }
217
218 float InputVerticalAbsolute(TransInfo *t, short mval[2]) {
219         float vec[3];
220         if(t->flag & T_SHIFT_MOD) {
221                 float dvec[3];
222                 /* calculate the main translation and the precise one separate */
223                 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
224                 VecMulf(dvec, 0.1f);
225                 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
226                 VecAddf(t->vec, t->vec, dvec);
227         }
228         else {
229                 convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
230         }
231         Projf(vec, t->vec, t->viewinv[1]);
232         return Inpf(t->viewinv[1], vec) * 2.0f;
233 }
234
235 /* ************************** SPACE DEPENDANT CODE **************************** */
236
237 void setTransformViewMatrices(TransInfo *t)
238 {
239         if(t->spacetype==SPACE_VIEW3D) {
240                 Mat4CpyMat4(t->viewmat, G.vd->viewmat);
241                 Mat4CpyMat4(t->viewinv, G.vd->viewinv);
242                 Mat4CpyMat4(t->persmat, G.vd->persmat);
243                 Mat4CpyMat4(t->persinv, G.vd->persinv);
244                 t->persp= G.vd->persp;
245         }
246         else {
247                 Mat4One(t->viewmat);
248                 Mat4One(t->viewinv);
249                 Mat4One(t->persmat);
250                 Mat4One(t->persinv);
251                 t->persp = 0; // ortho
252         }
253         
254         calculateCenter2D(t);
255         
256 }
257
258 void convertViewVec(TransInfo *t, float *vec, short dx, short dy)
259 {
260         if (t->spacetype==SPACE_VIEW3D) {
261                 window_to_3d(vec, dx, dy);
262         }
263         else if(t->spacetype==SPACE_IMAGE) {
264                 float divx, divy, aspx, aspy;
265
266                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
267
268                 divx= G.v2d->mask.xmax-G.v2d->mask.xmin;
269                 divy= G.v2d->mask.ymax-G.v2d->mask.ymin;
270
271                 vec[0]= aspx*(G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx)/divx;
272                 vec[1]= aspy*(G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/divy;
273                 vec[2]= 0.0f;
274         }
275 }
276
277 void projectIntView(TransInfo *t, float *vec, int *adr)
278 {
279         if (t->spacetype==SPACE_VIEW3D)
280                 project_int(vec, adr);
281         else if(t->spacetype==SPACE_IMAGE) {
282                 float aspx, aspy, v[2];
283
284                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
285                 v[0]= vec[0]/aspx;
286                 v[1]= vec[1]/aspy;
287
288                 uvco_to_areaco_noclip(v, adr);
289         }
290 }
291
292 void projectFloatView(TransInfo *t, float *vec, float *adr)
293 {
294         if (t->spacetype==SPACE_VIEW3D)
295                 project_float(vec, adr);
296         else if(t->spacetype==SPACE_IMAGE) {
297                 int a[2];
298
299                 projectIntView(t, vec, a);
300                 adr[0]= a[0];
301                 adr[1]= a[1];
302         }
303 }
304
305 void convertVecToDisplayNum(float *vec, float *num)
306 {
307         TransInfo *t= BIF_GetTransInfo();
308
309         VECCOPY(num, vec);
310
311         if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
312                 float aspx, aspy;
313
314                 if((G.sima->flag & SI_COORDFLOATS)==0) {
315                         int width, height;
316                         transform_width_height_tface_uv(&width, &height);
317
318                         num[0] *= width;
319                         num[1] *= height;
320                 }
321
322                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
323                 num[0] /= aspx;
324                 num[1] /= aspy;
325         }
326 }
327
328 void convertDisplayNumToVec(float *num, float *vec)
329 {
330         TransInfo *t= BIF_GetTransInfo();
331
332         VECCOPY(vec, num);
333
334         if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
335                 float aspx, aspy;
336
337                 if((G.sima->flag & SI_COORDFLOATS)==0) {
338                         int width, height;
339                         transform_width_height_tface_uv(&width, &height);
340
341                         vec[0] /= width;
342                         vec[1] /= height;
343                 }
344
345                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
346                 vec[0] *= aspx;
347                 vec[1] *= aspy;
348         }
349 }
350
351 static void viewRedrawForce(TransInfo *t)
352 {
353         if(t->spacetype==SPACE_VIEW3D)
354                 force_draw(0);
355         else if(t->spacetype==SPACE_IMAGE) {
356                 if(G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
357                 else force_draw(0);
358         }
359 }
360
361 static void viewRedrawPost(TransInfo *t)
362 {
363         if(t->spacetype==SPACE_VIEW3D) {
364                 allqueue(REDRAWBUTSOBJECT, 0);
365                 allqueue(REDRAWVIEW3D, 0);
366         }
367         else if(t->spacetype==SPACE_IMAGE) {
368                 allqueue(REDRAWIMAGE, 0);
369                 allqueue(REDRAWVIEW3D, 0);
370         }
371
372         scrarea_queue_headredraw(curarea);
373 }
374
375 /* ************************** TRANSFORMATIONS **************************** */
376
377 void BIF_selectOrientation() {
378         short val;
379         val= pupmenu("Orientation%t|Global|Local|Normal|View");
380         if(val>0) {
381                 if(val==1) G.vd->twmode= V3D_MANIP_GLOBAL;
382                 else if(val==2) G.vd->twmode= V3D_MANIP_LOCAL;
383                 else if(val==3) G.vd->twmode= V3D_MANIP_NORMAL;
384                 else if(val==4) G.vd->twmode= V3D_MANIP_VIEW;
385         }
386 }
387
388 static void view_editmove(unsigned short event)
389 {
390         int refresh = 0;
391         /* Regular:   Zoom in */
392         /* Shift:     Scroll up */
393         /* Ctrl:      Scroll right */
394         /* Alt-Shift: Rotate up */
395         /* Alt-Ctrl:  Rotate right */
396         
397         /* only work in 3D window for now
398          * In the end, will have to send to event to a 2D window handler instead
399          */
400         if (Trans.flag & T_2D_EDIT)
401                 return;
402         
403         switch(event) {
404                 case WHEELUPMOUSE:
405                         
406                         if( G.qual & LR_SHIFTKEY ) {
407                                 if( G.qual & LR_ALTKEY ) { 
408                                         G.qual &= ~LR_SHIFTKEY;
409                                         persptoetsen(PAD2);
410                                         G.qual |= LR_SHIFTKEY;
411                                 } else {
412                                         persptoetsen(PAD2);
413                                 }
414                         } else if( G.qual & LR_CTRLKEY ) {
415                                 if( G.qual & LR_ALTKEY ) { 
416                                         G.qual &= ~LR_CTRLKEY;
417                                         persptoetsen(PAD4);
418                                         G.qual |= LR_CTRLKEY;
419                                 } else {
420                                         persptoetsen(PAD4);
421                                 }
422                         } else if(U.uiflag & USER_WHEELZOOMDIR) 
423                                 persptoetsen(PADMINUS);
424                         else
425                                 persptoetsen(PADPLUSKEY);
426                         
427                         refresh = 1;
428                         break;
429                 case WHEELDOWNMOUSE:
430                         if( G.qual & LR_SHIFTKEY ) {
431                                 if( G.qual & LR_ALTKEY ) { 
432                                         G.qual &= ~LR_SHIFTKEY;
433                                         persptoetsen(PAD8);
434                                         G.qual |= LR_SHIFTKEY;
435                                 } else {
436                                         persptoetsen(PAD8);
437                                 }
438                         } else if( G.qual & LR_CTRLKEY ) {
439                                 if( G.qual & LR_ALTKEY ) { 
440                                         G.qual &= ~LR_CTRLKEY;
441                                         persptoetsen(PAD6);
442                                         G.qual |= LR_CTRLKEY;
443                                 } else {
444                                         persptoetsen(PAD6);
445                                 }
446                         } else if(U.uiflag & USER_WHEELZOOMDIR) 
447                                 persptoetsen(PADPLUSKEY);
448                         else
449                                 persptoetsen(PADMINUS);
450                         
451                         refresh = 1;
452                         break;
453         }
454
455         if (refresh)
456                 setTransformViewMatrices(&Trans);
457 }
458
459 void checkFirstTime() {
460         if(Trans.mode==TFM_INIT) {
461                 memset(&Trans, 0, sizeof(TransInfo));
462                 Trans.propsize = 1.0;
463         }
464 }
465
466 static char *transform_to_undostr(TransInfo *t)
467 {
468         switch (t->mode) {
469                 case TFM_TRANSLATION:
470                         return "Translate";
471                 case TFM_ROTATION:
472                         return "Rotate";
473                 case TFM_RESIZE:
474                         return "Scale";
475                 case TFM_TOSPHERE:
476                         return "To Sphere";
477                 case TFM_SHEAR:
478                         return "Shear";
479                 case TFM_WARP:
480                         return "Warp";
481                 case TFM_SHRINKFATTEN:
482                         return "Shrink/Fatten";
483                 case TFM_TILT:
484                         return "Tilt";
485                 case TFM_TRACKBALL:
486                         return "Trackball";
487                 case TFM_PUSHPULL:
488                         return "Push/Pull";
489                 case TFM_CREASE:
490                         return "Crease";
491                 case TFM_BONESIZE:
492                         return "Bone Width";
493                 case TFM_BONE_ENVELOPE:
494                         return "Bone Envelope";
495         }
496         return "Transform";
497 }
498
499 /* ************************************************* */
500
501 static void transformEvent(unsigned short event, short val) {
502         float mati[3][3] = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
503         char cmode = constraintModeToChar(&Trans);
504
505         if (val) {
506                 switch (event){
507                 /* enforce redraw of transform when modifiers are used */
508                 case LEFTCTRLKEY:
509                 case RIGHTCTRLKEY:
510                         Trans.redraw = 1;
511                         break;
512                 case LEFTSHIFTKEY:
513                 case RIGHTSHIFTKEY:
514                         /* shift is modifier for higher resolution transform, works nice to store this mouse position */
515                         getmouseco_areawin(Trans.shiftmval);
516                         Trans.flag |= T_SHIFT_MOD;
517                         Trans.redraw = 1;
518                         break;
519
520                 case SPACEKEY:
521                         if ((Trans.spacetype==SPACE_VIEW3D) && (G.qual & LR_ALTKEY)) {
522                                 short mval[2];
523
524                                 getmouseco_sc(mval);
525                                 BIF_selectOrientation();
526                                 calc_manipulator_stats(curarea);
527                                 Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
528                                 warp_pointer(mval[0], mval[1]);
529                         }
530                         else {
531                                 Trans.state = TRANS_CONFIRM;
532                         }
533                         break;
534
535                         
536                 case MIDDLEMOUSE:
537                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
538                                 /* exception for switching to dolly, or trackball, in camera view */
539                                 if (Trans.flag & T_CAMERA) {
540                                         if (Trans.mode==TFM_TRANSLATION)
541                                                 setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
542                                         else if (Trans.mode==TFM_ROTATION) {
543                                                 restoreTransObjects(&Trans);
544                                                 initTrackball(&Trans);
545                                         }
546                                 }
547                                 else {
548                                         Trans.flag |= T_MMB_PRESSED;
549                                         if (Trans.con.mode & CON_APPLY) {
550                                                 stopConstraint(&Trans);
551                                         }
552                                         else {
553                                                 if (G.qual & LR_CTRLKEY) {
554                                                         initSelectConstraint(&Trans, Trans.spacemtx);
555                                                 }
556                                                 else {
557                                                         /* bit hackish... but it prevents mmb select to print the orientation from menu */
558                                                         strcpy(Trans.spacename, "global");
559                                                         initSelectConstraint(&Trans, mati);
560                                                 }
561                                                 postSelectConstraint(&Trans);
562                                         }
563                                 }
564                                 Trans.redraw = 1;
565                         }
566                         break;
567                 case ESCKEY:
568                 case RIGHTMOUSE:
569                         Trans.state = TRANS_CANCEL;
570                         break;
571                 case LEFTMOUSE:
572                 case PADENTER:
573                 case RETKEY:
574                         Trans.state = TRANS_CONFIRM;
575                         break;
576                 case GKEY:
577                         /* only switch when... */
578                         if( ELEM3(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { 
579                                 restoreTransObjects(&Trans);
580                                 initTranslation(&Trans);
581                                 Trans.redraw = 1;
582                         }
583                         break;
584                 case SKEY:
585                         /* only switch when... */
586                         if( ELEM3(Trans.mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { 
587                                 restoreTransObjects(&Trans);
588                                 initResize(&Trans);
589                                 Trans.redraw = 1;
590                         }
591                         break;
592                 case RKEY:
593                         /* only switch when... */
594                         if( ELEM4(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { 
595                                 
596                                 if (Trans.mode == TFM_ROTATION) {
597                                         restoreTransObjects(&Trans);
598                                         initTrackball(&Trans);
599                                 }
600                                 else {
601                                         restoreTransObjects(&Trans);
602                                         initRotation(&Trans);
603                                 }
604                                 Trans.redraw = 1;
605                         }
606                         break;
607                 case CKEY:
608                         if (G.qual & LR_ALTKEY) {
609                                 Trans.flag ^= T_PROP_CONNECTED;
610                                 sort_trans_data_dist(&Trans);
611                                 calculatePropRatio(&Trans);
612                                 Trans.redraw= 1;
613                         }
614                         else {
615                                 stopConstraint(&Trans);
616                                 Trans.redraw = 1;
617                         }
618                         break;
619                 case XKEY:
620                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
621                                 if (cmode == 'X') {
622                                         if (Trans.con.mode & CON_USER) {
623                                                 stopConstraint(&Trans);
624                                         }
625                                         else {
626                                                 if (G.qual == 0)
627                                                         setUserConstraint(&Trans, (CON_AXIS0), "along %s X");
628                                                 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
629                                                         setUserConstraint(&Trans, (CON_AXIS1|CON_AXIS2), "locking %s X");
630                                         }
631                                 }
632                                 else {
633                                         if (G.qual == 0)
634                                                 setConstraint(&Trans, mati, (CON_AXIS0), "along global X");
635                                         else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
636                                                 setConstraint(&Trans, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
637                                 }
638                                 Trans.redraw = 1;
639                         }
640                         break;
641                 case YKEY:
642                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
643                                 if (cmode == 'Y') {
644                                         if (Trans.con.mode & CON_USER) {
645                                                 stopConstraint(&Trans);
646                                         }
647                                         else {
648                                                 if (G.qual == 0)
649                                                         setUserConstraint(&Trans, (CON_AXIS1), "along %s Y");
650                                                 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
651                                                         setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS2), "locking %s Y");
652                                         }
653                                 }
654                                 else {
655                                         if (G.qual == 0)
656                                                 setConstraint(&Trans, mati, (CON_AXIS1), "along global Y");
657                                         else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
658                                                 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS2), "locking global Y");
659                                 }
660                                 Trans.redraw = 1;
661                         }
662                         break;
663                 case ZKEY:
664                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
665                                 if (cmode == 'Z') {
666                                         if (Trans.con.mode & CON_USER) {
667                                                 stopConstraint(&Trans);
668                                         }
669                                         else {
670                                                 if (G.qual == 0)
671                                                         setUserConstraint(&Trans, (CON_AXIS2), "along %s Z");
672                                                 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
673                                                         setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS1), "locking %s Z");
674                                         }
675                                 }
676                                 else if ((Trans.flag & T_2D_EDIT)==0) {
677                                         if (G.qual == 0)
678                                                 setConstraint(&Trans, mati, (CON_AXIS2), "along global Z");
679                                         else if (G.qual == LR_SHIFTKEY)
680                                                 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
681                                 }
682                                 Trans.redraw = 1;
683                         }
684                         break;
685                 case OKEY:
686                         if (Trans.flag & T_PROP_EDIT && G.qual==LR_SHIFTKEY) {
687                                 G.scene->prop_mode = (G.scene->prop_mode+1)%6;
688                                 calculatePropRatio(&Trans);
689                                 Trans.redraw= 1;
690                         }
691                         break;
692                 case PADPLUSKEY:
693                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
694                                 Trans.propsize*= 1.1f;
695                                 calculatePropRatio(&Trans);
696                         }
697                         Trans.redraw= 1;
698                         break;
699                 case PAGEUPKEY:
700                 case WHEELDOWNMOUSE:
701                         if(Trans.flag & T_PROP_EDIT) {
702                                 Trans.propsize*= 1.1f;
703                                 calculatePropRatio(&Trans);
704                         }
705                         else view_editmove(event);
706                         Trans.redraw= 1;
707                         break;
708                 case PADMINUS:
709                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
710                                 Trans.propsize*= 0.90909090f;
711                                 calculatePropRatio(&Trans);
712                         }
713                         Trans.redraw= 1;
714                         break;
715                 case PAGEDOWNKEY:
716                 case WHEELUPMOUSE:
717                         if(Trans.flag & T_PROP_EDIT) {
718                                 Trans.propsize*= 0.90909090f;
719                                 calculatePropRatio(&Trans);
720                         }
721                         else view_editmove(event);
722                         Trans.redraw= 1;
723                         break;
724 //              case NDOFMOTION:
725 //            viewmoveNDOF(1);
726   //         break;
727                 }
728                 
729                 // Numerical input events
730                 Trans.redraw |= handleNumInput(&(Trans.num), event);
731                 
732                 // NDof input events
733                 switch(handleNDofInput(&(Trans.ndof), event, val))
734                 {
735                         case NDOF_CONFIRM:
736                                 if ((Trans.context & CTX_NDOF) == 0)
737                                 {
738                                         /* Confirm on normal transform only */
739                                         Trans.state = TRANS_CONFIRM;
740                                 }
741                                 break;
742                         case NDOF_CANCEL:
743                                 if (Trans.context & CTX_NDOF)
744                                 {
745                                         /* Cancel on pure NDOF transform */
746                                         Trans.state = TRANS_CANCEL; 
747                                 }
748                                 else
749                                 {
750                                         /* Otherwise, just redraw, NDof input was cancelled */
751                                         Trans.redraw = 1;
752                                 }
753                                 break;
754                         case NDOF_NOMOVE:
755                                 if (Trans.context & CTX_NDOF)
756                                 {
757                                         /* Confirm on pure NDOF transform */
758                                         Trans.state = TRANS_CONFIRM;
759                                 }
760                                 break;
761                         case NDOF_REFRESH:
762                                 Trans.redraw = 1;
763                                 break;
764                         
765                 }
766                 
767                 // Snapping events
768                 Trans.redraw |= handleSnapping(&Trans, event);
769                 
770                 arrows_move_cursor(event);
771         }
772         else {
773                 switch (event){
774                 /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still 
775                    after releasing modifer key */
776                 case MIDDLEMOUSE:
777                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
778                                 Trans.flag &= ~T_MMB_PRESSED;
779                                 postSelectConstraint(&Trans);
780                                 Trans.redraw = 1;
781                         }
782                         break;
783                 case LEFTMOUSE:
784                 case RIGHTMOUSE:
785                         if (Trans.context & CTX_TWEAK)
786                                 Trans.state = TRANS_CONFIRM;
787                         break;
788                 case LEFTSHIFTKEY:
789                 case RIGHTSHIFTKEY:
790                         /* shift is modifier for higher resolution transform */
791                         Trans.flag &= ~T_SHIFT_MOD;
792                         break;
793                 }
794         }
795         
796         // Per transform event, if present
797         if (Trans.handleEvent)
798                 Trans.redraw |= Trans.handleEvent(&Trans, event, val);
799 }
800
801 int calculateTransformCenter(int centerMode, float *vec)
802 {
803         int success = 1;
804         checkFirstTime();
805
806         Trans.state = TRANS_RUNNING;
807
808         Trans.context = CTX_NONE;
809         
810         Trans.mode = TFM_DUMMY;
811
812         initTrans(&Trans);                                      // internal data, mouse, vectors
813
814         createTransData(&Trans);                        // make TransData structs from selection
815
816         Trans.around = centerMode;                      // override userdefined mode
817
818         if (Trans.total == 0) {
819                 success = 0;
820         }
821         else {
822                 success = 1;
823                 
824                 calculateCenter(&Trans);
825         
826                 // Copy center from constraint center. Transform center can be local    
827                 VECCOPY(vec, Trans.con.center);
828         }
829
830         postTrans(&Trans);
831
832         /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
833         special_aftertrans_update(&Trans);
834         
835         return success;
836 }
837
838 void initTransform(int mode, int context) {
839         /* added initialize, for external calls to set stuff in TransInfo, like undo string */
840         checkFirstTime();
841
842         Trans.state = TRANS_RUNNING;
843
844         Trans.context = context;
845         
846         Trans.mode = mode;
847
848         initTrans(&Trans);                                      // internal data, mouse, vectors
849
850         if(Trans.spacetype==SPACE_VIEW3D) {
851                 calc_manipulator_stats(curarea);
852                 Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
853         }
854         else
855                 Mat3One(Trans.spacemtx);
856
857         createTransData(&Trans);                        // make TransData structs from selection
858
859         initSnapping(&Trans); // Initialize snapping data AFTER mode flags
860
861         if (Trans.total == 0) {
862                 postTrans(&Trans);
863                 return;
864         }
865
866         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
867         /* EVIL2: we gave as argument also texture space context bit... was cleared */
868         mode = Trans.mode;
869         
870         calculatePropRatio(&Trans);
871         calculateCenter(&Trans);
872
873         switch (mode) {
874         case TFM_TRANSLATION:
875                 initTranslation(&Trans);
876                 break;
877         case TFM_ROTATION:
878                 initRotation(&Trans);
879                 break;
880         case TFM_RESIZE:
881                 initResize(&Trans);
882                 break;
883         case TFM_TOSPHERE:
884                 initToSphere(&Trans);
885                 break;
886         case TFM_SHEAR:
887                 initShear(&Trans);
888                 break;
889         case TFM_WARP:
890                 initWarp(&Trans);
891                 break;
892         case TFM_SHRINKFATTEN:
893                 initShrinkFatten(&Trans);
894                 break;
895         case TFM_TILT:
896                 initTilt(&Trans);
897                 break;
898         case TFM_CURVE_SHRINKFATTEN:
899                 initCurveShrinkFatten(&Trans);
900                 break;
901         case TFM_TRACKBALL:
902                 initTrackball(&Trans);
903                 break;
904         case TFM_PUSHPULL:
905                 initPushPull(&Trans);
906                 break;
907         case TFM_CREASE:
908                 initCrease(&Trans);
909                 break;
910         case TFM_BONESIZE:
911                 {       /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
912                         bArmature *arm= Trans.poseobj->data;
913                         if(arm->drawtype==ARM_ENVELOPE)
914                                 initBoneEnvelope(&Trans);
915                         else
916                                 initBoneSize(&Trans);
917                 }
918                 break;
919         case TFM_BONE_ENVELOPE:
920                 initBoneEnvelope(&Trans);
921                 break;
922         case TFM_BONE_ROLL:
923                 initBoneRoll(&Trans);
924                 break;
925         }
926 }
927
928 void Transform() 
929 {
930         short pmval[2] = {0, 0}, mval[2], val;
931         unsigned short event;
932
933         if(Trans.total==0) return;      // added, can happen now! (ton)
934         
935         // Emptying event queue
936         while( qtest() ) {
937                 event= extern_qread(&val);
938         }
939
940         Trans.redraw = 1; /* initial draw */
941
942         while (Trans.state == TRANS_RUNNING) {
943
944                 getmouseco_areawin(mval);
945                 
946                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
947                         if (Trans.flag & T_MMB_PRESSED)
948                                 Trans.con.mode |= CON_SELECT;
949                         Trans.redraw = 1;
950                 }
951                 if (Trans.redraw) {
952                         pmval[0] = mval[0];
953                         pmval[1] = mval[1];
954
955                         selectConstraint(&Trans);
956                         if (Trans.transform) {
957                                 Trans.transform(&Trans, mval);  // calls recalcData()
958                         }
959                         Trans.redraw = 0;
960                 }
961                 
962                 /* essential for idling subloop */
963                 if( qtest()==0) PIL_sleep_ms(2);
964
965                 while( qtest() ) {
966                         event= extern_qread(&val);
967                         transformEvent(event, val);
968                 }
969         }
970         
971         
972         /* handle restoring objects */
973         if(Trans.state == TRANS_CANCEL)
974                 restoreTransObjects(&Trans);    // calls recalcData()
975         
976         /* free data */
977         postTrans(&Trans);
978
979         /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
980         special_aftertrans_update(&Trans);
981
982         /* send events out for redraws */
983         viewRedrawPost(&Trans);
984
985         /*  Undo as last, certainly after special_trans_update! */
986         if(Trans.state == TRANS_CANCEL) {
987                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
988         }
989         else {
990                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
991                 else BIF_undo_push(transform_to_undostr(&Trans));
992         }
993         Trans.undostr= NULL;
994         
995 }
996
997 /* ************************** Manipulator init and main **************************** */
998
999 void initManipulator(int mode)
1000 {
1001         Trans.state = TRANS_RUNNING;
1002
1003         Trans.context = CTX_NONE;
1004         
1005         Trans.mode = mode;
1006         
1007         /* automatic switch to scaling bone envelopes */
1008         if(mode==TFM_RESIZE && G.obedit && G.obedit->type==OB_ARMATURE) {
1009                 bArmature *arm= G.obedit->data;
1010                 if(arm->drawtype==ARM_ENVELOPE)
1011                         mode= TFM_BONE_ENVELOPE;
1012         }
1013
1014         initTrans(&Trans);                                      // internal data, mouse, vectors
1015
1016         G.moving |= G_TRANSFORM_MANIP;          // signal to draw manipuls while transform
1017         createTransData(&Trans);                        // make TransData structs from selection
1018
1019         if (Trans.total == 0)
1020                 return;
1021
1022         initSnapping(&Trans); // Initialize snapping data AFTER mode flags
1023
1024         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1025         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1026         mode = Trans.mode;
1027         
1028         calculatePropRatio(&Trans);
1029         calculateCenter(&Trans);
1030
1031         switch (mode) {
1032         case TFM_TRANSLATION:
1033                 initTranslation(&Trans);
1034                 break;
1035         case TFM_ROTATION:
1036                 initRotation(&Trans);
1037                 break;
1038         case TFM_RESIZE:
1039                 initResize(&Trans);
1040                 break;
1041         case TFM_TRACKBALL:
1042                 initTrackball(&Trans);
1043                 break;
1044         }
1045
1046         Trans.flag |= T_USES_MANIPULATOR;
1047 }
1048
1049 void ManipulatorTransform() 
1050 {
1051         int mouse_moved = 0;
1052         short pmval[2] = {0, 0}, mval[2], val;
1053         unsigned short event;
1054
1055         if (Trans.total == 0)
1056                 return;
1057
1058         Trans.redraw = 1; /* initial draw */
1059
1060         while (Trans.state == TRANS_RUNNING) {
1061                 
1062                 getmouseco_areawin(mval);
1063                 
1064                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1065                         Trans.redraw = 1;
1066                 }
1067                 if (Trans.redraw) {
1068                         pmval[0] = mval[0];
1069                         pmval[1] = mval[1];
1070
1071                         //selectConstraint(&Trans);  needed?
1072                         if (Trans.transform) {
1073                                 Trans.transform(&Trans, mval);
1074                         }
1075                         Trans.redraw = 0;
1076                 }
1077                 
1078                 /* essential for idling subloop */
1079                 if( qtest()==0) PIL_sleep_ms(2);
1080
1081                 while( qtest() ) {
1082                         event= extern_qread(&val);
1083
1084                         switch (event){
1085                         case MOUSEX:
1086                         case MOUSEY:
1087                                 mouse_moved = 1;
1088                                 break;
1089                         /* enforce redraw of transform when modifiers are used */
1090                         case LEFTCTRLKEY:
1091                         case RIGHTCTRLKEY:
1092                                 if(val) Trans.redraw = 1;
1093                                 break;
1094                         case LEFTSHIFTKEY:
1095                         case RIGHTSHIFTKEY:
1096                                 /* shift is modifier for higher resolution transform, works nice to store this mouse position */
1097                                 if(val) {
1098                                         getmouseco_areawin(Trans.shiftmval);
1099                                         Trans.flag |= T_SHIFT_MOD;
1100                                         Trans.redraw = 1;
1101                                 }
1102                                 else Trans.flag &= ~T_SHIFT_MOD; 
1103                                 break;
1104                                 
1105                         case ESCKEY:
1106                         case RIGHTMOUSE:
1107                                 Trans.state = TRANS_CANCEL;
1108                                 break;
1109                         case LEFTMOUSE:
1110                                 if(mouse_moved==0 && val==0) break;
1111                                 // else we pass on event to next, which cancels
1112                         case SPACEKEY:
1113                         case PADENTER:
1114                         case RETKEY:
1115                                 Trans.state = TRANS_CONFIRM;
1116                                 break;
1117    //         case NDOFMOTION:
1118      //           viewmoveNDOF(1);
1119      //           break;
1120                         }
1121                         if(val) {
1122                                 switch(event) {
1123                                 case WHEELDOWNMOUSE:
1124                                 case PADPLUSKEY:
1125                                         if(Trans.flag & T_PROP_EDIT) {
1126                                                 Trans.propsize*= 1.1f;
1127                                                 calculatePropRatio(&Trans);
1128                                                 Trans.redraw= 1;
1129                                         }
1130                                         break;
1131                                 case WHEELUPMOUSE:
1132                                 case PADMINUS:
1133                                         if(Trans.flag & T_PROP_EDIT) {
1134                                                 Trans.propsize*= 0.90909090f;
1135                                                 calculatePropRatio(&Trans);
1136                                                 Trans.redraw= 1;
1137                                         }
1138                                         break;
1139                                 }                       
1140                         }
1141                 }
1142         }
1143         
1144         if(Trans.state == TRANS_CANCEL) {
1145                 restoreTransObjects(&Trans);
1146         }
1147         
1148         /* free data, reset vars */
1149         postTrans(&Trans);
1150         
1151         /* aftertrans does insert ipos and action channels, and clears base flags */
1152         special_aftertrans_update(&Trans);
1153         
1154         /* send events out for redraws */
1155         viewRedrawPost(&Trans);
1156
1157         if(Trans.state != TRANS_CANCEL) {
1158                 BIF_undo_push(transform_to_undostr(&Trans));
1159         }
1160         
1161 }
1162
1163 /* ************************** TRANSFORMATIONS **************************** */
1164
1165 static void protectedTransBits(short protectflag, float *vec)
1166 {
1167         if(protectflag & OB_LOCK_LOCX)
1168                 vec[0]= 0.0f;
1169         if(protectflag & OB_LOCK_LOCY)
1170                 vec[1]= 0.0f;
1171         if(protectflag & OB_LOCK_LOCZ)
1172                 vec[2]= 0.0f;
1173 }
1174
1175 static void protectedSizeBits(short protectflag, float *size)
1176 {
1177         if(protectflag & OB_LOCK_SCALEX)
1178                 size[0]= 1.0f;
1179         if(protectflag & OB_LOCK_SCALEY)
1180                 size[1]= 1.0f;
1181         if(protectflag & OB_LOCK_SCALEZ)
1182                 size[2]= 1.0f;
1183 }
1184
1185 static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
1186 {
1187         if(protectflag & OB_LOCK_ROTX)
1188                 eul[0]= oldeul[0];
1189         if(protectflag & OB_LOCK_ROTY)
1190                 eul[1]= oldeul[1];
1191         if(protectflag & OB_LOCK_ROTZ)
1192                 eul[2]= oldeul[2];
1193 }
1194
1195 static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
1196 {
1197         /* quaternions get limited with euler... */
1198         /* this function only does the delta rotation */
1199         
1200         if(protectflag) {
1201                 float eul[3], oldeul[3], quat1[4];
1202                 
1203                 QUATCOPY(quat1, quat);
1204                 QuatToEul(quat, eul);
1205                 QuatToEul(oldquat, oldeul);
1206                 
1207                 if(protectflag & OB_LOCK_ROTX)
1208                         eul[0]= oldeul[0];
1209                 if(protectflag & OB_LOCK_ROTY)
1210                         eul[1]= oldeul[1];
1211                 if(protectflag & OB_LOCK_ROTZ)
1212                         eul[2]= oldeul[2];
1213                 
1214                 EulToQuat(eul, quat);
1215                 /* quaternions flip w sign to accumulate rotations correctly */
1216                 if( (quat1[0]<0.0f && quat[0]>0.0f) || (quat1[0]>0.0f && quat[0]<0.0f) ) {
1217                         QuatMulf(quat, -1.0f);
1218                 }
1219         }
1220 }
1221
1222 /* ************************** WARP *************************** */
1223
1224 void initWarp(TransInfo *t) 
1225 {
1226         float max[3], min[3];
1227         int i;
1228         
1229         t->mode = TFM_WARP;
1230         t->transform = Warp;
1231         
1232         t->idx_max = 0;
1233         t->num.idx_max = 0;
1234         t->snap[0] = 0.0f;
1235         t->snap[1] = 5.0f;
1236         t->snap[2] = 1.0f;
1237         
1238         t->flag |= T_NO_CONSTRAINT;
1239
1240 /* warp is done fully in view space */
1241         calculateCenterCursor(t);
1242         t->fac = (float)(t->center2d[0] - t->imval[0]);
1243         
1244         /* we need min/max in view space */
1245         for(i = 0; i < t->total; i++) {
1246                 float center[3];
1247                 VECCOPY(center, t->data[i].center);
1248                 Mat3MulVecfl(t->data[i].mtx, center);
1249                 Mat4MulVecfl(t->viewmat, center);
1250                 VecSubf(center, center, t->viewmat[3]);
1251                 if (i)
1252                         MinMax3(min, max, center);
1253                 else {
1254                         VECCOPY(max, center);
1255                         VECCOPY(min, center);
1256                 }
1257         }
1258
1259         t->center[0]= (min[0]+max[0])/2.0f;
1260         t->center[1]= (min[1]+max[1])/2.0f;
1261         t->center[2]= (min[2]+max[2])/2.0f;
1262         
1263         t->val= (max[0]-min[0])/2.0f;   // t->val is free variable
1264 }
1265
1266 int Warp(TransInfo *t, short mval[2])
1267 {
1268         TransData *td = t->data;
1269         float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
1270         int i;
1271         char str[50];
1272         
1273         curs= give_cursor();
1274         /*
1275          * gcursor is the one used for helpline.
1276          * It has to be in the same space as the drawing loop
1277          * (that means it needs to be in the object's space when in edit mode and
1278          *  in global space in object mode)
1279          *
1280          * cursor is used for calculations.
1281          * It needs to be in view space, but we need to take object's offset
1282          * into account if in Edit mode.
1283          */
1284         VECCOPY(cursor, curs);
1285         VECCOPY(gcursor, cursor);       
1286         if (t->flag & T_EDIT) {
1287                 VecSubf(cursor, cursor, G.obedit->obmat[3]);
1288                 VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
1289                 Mat3MulVecfl(t->data->smtx, gcursor);
1290         }
1291         Mat4MulVecfl(t->viewmat, cursor);
1292         VecSubf(cursor, cursor, t->viewmat[3]);
1293
1294         // amount of degrees for warp
1295         circumfac= 360.0f * InputHorizontalRatio(t, mval);
1296
1297         snapGrid(t, &circumfac);
1298         applyNumInput(&t->num, &circumfac);
1299         
1300         /* header print for NumInput */
1301         if (hasNumInput(&t->num)) {
1302                 char c[20];
1303                 
1304                 outputNumInput(&(t->num), c);
1305                 
1306                 sprintf(str, "Warp: %s", c);
1307         }
1308         else {
1309                 /* default header print */
1310                 sprintf(str, "Warp: %.3f", circumfac);
1311         }
1312         
1313         circumfac*= (float)(-M_PI/360.0);
1314         
1315         for(i = 0 ; i < t->total; i++, td++) {
1316                 float loc[3];
1317                 if (td->flag & TD_NOACTION)
1318                         break;
1319
1320                 /* translate point to center, rotate in such a way that outline==distance */
1321                 
1322                 VECCOPY(vec, td->iloc);
1323                 Mat3MulVecfl(td->mtx, vec);
1324                 Mat4MulVecfl(t->viewmat, vec);
1325                 VecSubf(vec, vec, t->viewmat[3]);
1326                 
1327                 dist= vec[0]-cursor[0];
1328
1329                 phi0= (circumfac*dist/t->val);  // t->val is X dimension projected boundbox
1330                 
1331                 vec[1]= (vec[1]-cursor[1]);
1332                 
1333                 co= (float)cos(phi0);
1334                 si= (float)sin(phi0);
1335                 loc[0]= -si*vec[1]+cursor[0];
1336                 loc[1]= co*vec[1]+cursor[1];
1337                 loc[2]= vec[2];
1338                 
1339                 Mat4MulVecfl(t->viewinv, loc);
1340                 VecSubf(loc, loc, t->viewinv[3]);
1341                 Mat3MulVecfl(td->smtx, loc);
1342
1343                 VecSubf(loc, loc, td->iloc);
1344                 VecMulf(loc, td->factor);
1345                 VecAddf(td->loc, td->iloc, loc);
1346         }
1347
1348         recalcData(t);
1349         
1350         headerprint(str);
1351         
1352         viewRedrawForce(t);
1353         
1354         helpline(t, gcursor);
1355         
1356         return 1;
1357 }
1358
1359 /* ************************** SHEAR *************************** */
1360
1361 void initShear(TransInfo *t) 
1362 {
1363         t->mode = TFM_SHEAR;
1364         t->transform = Shear;
1365         t->handleEvent = handleEventShear;
1366         
1367         t->idx_max = 0;
1368         t->num.idx_max = 0;
1369         t->snap[0] = 0.0f;
1370         t->snap[1] = 0.1f;
1371         t->snap[2] = t->snap[1] * 0.1f;
1372         
1373         t->flag |= T_NO_CONSTRAINT;
1374 }
1375
1376 int handleEventShear(TransInfo *t, unsigned short event, short val)
1377 {
1378         int status = 0;
1379         
1380         if (event == MIDDLEMOUSE && val)
1381         {
1382                 // Use customData pointer to signal Shear direction
1383                 if      (t->customData == 0)
1384                         t->customData = (void*)1;
1385                 else
1386                         t->customData = 0;
1387                         
1388                 status = 1;
1389         }
1390         
1391         return status;
1392 }
1393
1394
1395 int Shear(TransInfo *t, short mval[2]) 
1396 {
1397         TransData *td = t->data;
1398         float vec[3];
1399         float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
1400         float value;
1401         int i;
1402         char str[50];
1403
1404         Mat3CpyMat4(persmat, t->viewmat);
1405         Mat3Inv(persinv, persmat);
1406
1407         // Custom data signals shear direction
1408         if (t->customData == 0)
1409                 value = 0.05f * InputHorizontalAbsolute(t, mval);
1410         else
1411                 value = 0.05f * InputVerticalAbsolute(t, mval);
1412
1413         snapGrid(t, &value);
1414
1415         applyNumInput(&t->num, &value);
1416
1417         /* header print for NumInput */
1418         if (hasNumInput(&t->num)) {
1419                 char c[20];
1420
1421                 outputNumInput(&(t->num), c);
1422
1423                 sprintf(str, "Shear: %s %s", c, t->proptext);
1424         }
1425         else {
1426                 /* default header print */
1427                 sprintf(str, "Shear: %.3f %s", value, t->proptext);
1428         }
1429         
1430         Mat3One(smat);
1431         
1432         // Custom data signals shear direction
1433         if (t->customData == 0)
1434                 smat[1][0] = value;
1435         else
1436                 smat[0][1] = value;
1437         
1438         Mat3MulMat3(tmat, smat, persmat);
1439         Mat3MulMat3(totmat, persinv, tmat);
1440         
1441         for(i = 0 ; i < t->total; i++, td++) {
1442                 if (td->flag & TD_NOACTION)
1443                         break;
1444
1445                 if (G.obedit) {
1446                         float mat3[3][3];
1447                         Mat3MulMat3(mat3, totmat, td->mtx);
1448                         Mat3MulMat3(tmat, td->smtx, mat3);
1449                 }
1450                 else {
1451                         Mat3CpyMat3(tmat, totmat);
1452                 }
1453                 VecSubf(vec, td->center, t->center);
1454
1455                 Mat3MulVecfl(tmat, vec);
1456
1457                 VecAddf(vec, vec, t->center);
1458                 VecSubf(vec, vec, td->center);
1459
1460                 VecMulf(vec, td->factor);
1461
1462                 VecAddf(td->loc, td->iloc, vec);
1463         }
1464
1465         recalcData(t);
1466
1467         headerprint(str);
1468
1469         viewRedrawForce(t);
1470
1471         helpline (t, t->center);
1472
1473         return 1;
1474 }
1475
1476 /* ************************** RESIZE *************************** */
1477
1478 void initResize(TransInfo *t) 
1479 {
1480         t->mode = TFM_RESIZE;
1481         t->transform = Resize;
1482         
1483         t->flag |= T_NULL_ONE;
1484         t->num.flag |= NUM_NULL_ONE;
1485         t->num.flag |= NUM_AFFECT_ALL;
1486         if (!G.obedit) {
1487                 t->flag |= T_NO_ZERO;
1488                 t->num.flag |= NUM_NO_ZERO;
1489         }
1490         
1491         t->idx_max = 2;
1492         t->num.idx_max = 2;
1493         t->snap[0] = 0.0f;
1494         t->snap[1] = 0.1f;
1495         t->snap[2] = t->snap[1] * 0.1f;
1496
1497         t->fac = (float)sqrt(
1498                 (
1499                         ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
1500                 +
1501                         ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
1502                 ) );
1503
1504         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
1505 }
1506
1507 static void headerResize(TransInfo *t, float vec[3], char *str) {
1508         char tvec[60];
1509         if (hasNumInput(&t->num)) {
1510                 outputNumInput(&(t->num), tvec);
1511         }
1512         else {
1513                 sprintf(&tvec[0], "%.4f", vec[0]);
1514                 sprintf(&tvec[20], "%.4f", vec[1]);
1515                 sprintf(&tvec[40], "%.4f", vec[2]);
1516         }
1517
1518         if (t->con.mode & CON_APPLY) {
1519                 switch(t->num.idx_max) {
1520                 case 0:
1521                         sprintf(str, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
1522                         break;
1523                 case 1:
1524                         sprintf(str, "Scale: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1525                         break;
1526                 case 2:
1527                         sprintf(str, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1528                 }
1529         }
1530         else {
1531                 if (t->flag & T_2D_EDIT)
1532                         sprintf(str, "Scale X: %s   Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1533                 else
1534                         sprintf(str, "Scale X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1535         }
1536 }
1537
1538 #define SIGN(a)         (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3)
1539 #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)
1540
1541 /* smat is reference matrix, only scaled */
1542 static void TransMat3ToSize( float mat[][3], float smat[][3], float *size)
1543 {
1544         float vec[3];
1545         
1546         VecCopyf(vec, mat[0]);
1547         size[0]= Normalize(vec);
1548         VecCopyf(vec, mat[1]);
1549         size[1]= Normalize(vec);
1550         VecCopyf(vec, mat[2]);
1551         size[2]= Normalize(vec);
1552         
1553         /* first tried with dotproduct... but the sign flip is crucial */
1554         if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0]; 
1555         if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1]; 
1556         if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2]; 
1557 }
1558
1559
1560 static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
1561         float tmat[3][3], smat[3][3], center[3];
1562         float vec[3];
1563
1564         if (t->flag & T_EDIT) {
1565                 Mat3MulMat3(smat, mat, td->mtx);
1566                 Mat3MulMat3(tmat, td->smtx, smat);
1567         }
1568         else {
1569                 Mat3CpyMat3(tmat, mat);
1570         }
1571
1572         if (t->con.applySize) {
1573                 t->con.applySize(t, td, tmat);
1574         }
1575
1576         /* local constraint shouldn't alter center */
1577         if (t->around == V3D_LOCAL) {
1578                 if (t->flag & T_OBJECT) {
1579                         VECCOPY(center, td->center);
1580                 }
1581                 else if (t->flag & T_EDIT) {
1582                         
1583                         if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
1584                                 VECCOPY(center, td->center);
1585                         }
1586                         else {
1587                                 VECCOPY(center, t->center);
1588                         }
1589                 }
1590                 else {
1591                         VECCOPY(center, t->center);
1592                 }
1593         }
1594         else {
1595                 VECCOPY(center, t->center);
1596         }
1597
1598         if (td->ext) {
1599                 float fsize[3];
1600
1601                 if (t->flag & (T_OBJECT|T_TEXTURE)) {
1602                         float obsizemat[3][3];
1603                         // Reorient the size mat to fit the oriented object.
1604                         Mat3MulMat3(obsizemat, tmat, td->axismtx);
1605                         //printmatrix3("obsizemat", obsizemat);
1606                         TransMat3ToSize(obsizemat, td->axismtx, fsize);
1607                         //printvecf("fsize", fsize);
1608                 }
1609                 else {
1610                         Mat3ToSize(tmat, fsize);
1611                 }
1612                 
1613                 protectedSizeBits(td->protectflag, fsize);
1614                 
1615                 if ((t->flag & T_V3D_ALIGN)==0) {       // align mode doesn't rotate objects itself
1616                         /* handle ipokeys? */
1617                         if(td->tdi) {
1618                                 TransDataIpokey *tdi= td->tdi;
1619                                 /* calculate delta size (equal for size and dsize) */
1620                                 
1621                                 vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
1622                                 vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
1623                                 vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
1624                                 
1625                                 add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
1626                                 add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
1627                                 add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
1628                                 
1629                         }
1630                         else if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){
1631                                 /* scale val and reset size */
1632                                 *td->val = td->ival * fsize[0] * td->factor;
1633
1634                                 td->ext->size[0] = td->ext->isize[0];
1635                                 td->ext->size[1] = td->ext->isize[1];
1636                                 td->ext->size[2] = td->ext->isize[2];
1637                         }
1638                         else {
1639                                 /* Reset val if SINGLESIZE but using a constraint */
1640                                 if (td->flag & TD_SINGLESIZE)
1641                                         *td->val = td->ival;
1642
1643                                 td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
1644                                 td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
1645                                 td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
1646                         }
1647                 }
1648         }
1649         /* For individual element center, Editmode need to use iloc */
1650         if (t->flag & T_POINTS)
1651                 VecSubf(vec, td->iloc, center);
1652         else
1653                 VecSubf(vec, td->center, center);
1654
1655         Mat3MulVecfl(tmat, vec);
1656
1657         VecAddf(vec, vec, center);
1658         if (t->flag & T_POINTS)
1659                 VecSubf(vec, vec, td->iloc);
1660         else
1661                 VecSubf(vec, vec, td->center);
1662
1663         VecMulf(vec, td->factor);
1664
1665         if (t->flag & T_OBJECT) {
1666                 Mat3MulVecfl(td->smtx, vec);
1667         }
1668
1669         protectedTransBits(td->protectflag, vec);
1670
1671         if(td->tdi) {
1672                 TransDataIpokey *tdi= td->tdi;
1673                 add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
1674                 add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
1675                 add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
1676         }
1677         else VecAddf(td->loc, td->iloc, vec);
1678 }
1679
1680 int Resize(TransInfo *t, short mval[2]) 
1681 {
1682         TransData *td;
1683         float size[3], mat[3][3];
1684         float ratio;
1685         int i;
1686         char str[200];
1687
1688         /* for manipulator, center handle, the scaling can't be done relative to center */
1689         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
1690                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
1691         }
1692         else {
1693                 ratio = InputScaleRatio(t, mval);
1694                 
1695                 /* flip scale, but not for manipulator center handle */
1696                 if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
1697                          (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
1698                                 ratio *= -1.0f;
1699         }
1700         
1701         size[0] = size[1] = size[2] = ratio;
1702
1703         snapGrid(t, size);
1704
1705         if (hasNumInput(&t->num)) {
1706                 applyNumInput(&t->num, size);
1707                 constraintNumInput(t, size);
1708         }
1709
1710         SizeToMat3(size, mat);
1711
1712         if (t->con.applySize) {
1713                 t->con.applySize(t, NULL, mat);
1714         }
1715
1716         Mat3CpyMat3(t->mat, mat);       // used in manipulator
1717         
1718         headerResize(t, size, str);
1719
1720         for(i = 0, td=t->data; i < t->total; i++, td++) {
1721                 if (td->flag & TD_NOACTION)
1722                         break;
1723                 
1724                 ElementResize(t, td, mat);
1725         }
1726
1727         /* evil hack - redo resize if cliiping needeed */
1728         if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
1729                 SizeToMat3(size, mat);
1730
1731                 if (t->con.applySize)
1732                         t->con.applySize(t, NULL, mat);
1733
1734                 for(i = 0, td=t->data; i < t->total; i++, td++)
1735                         ElementResize(t, td, mat);
1736         }
1737
1738         recalcData(t);
1739
1740         headerprint(str);
1741
1742         viewRedrawForce(t);
1743
1744         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
1745
1746         return 1;
1747 }
1748
1749 /* ************************** TOSPHERE *************************** */
1750
1751 void initToSphere(TransInfo *t) 
1752 {
1753         TransData *td = t->data;
1754         int i;
1755
1756         t->mode = TFM_TOSPHERE;
1757         t->transform = ToSphere;
1758
1759         t->idx_max = 0;
1760         t->num.idx_max = 0;
1761         t->snap[0] = 0.0f;
1762         t->snap[1] = 0.1f;
1763         t->snap[2] = t->snap[1] * 0.1f;
1764         
1765         t->num.flag |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
1766         t->flag |= T_NO_CONSTRAINT;
1767
1768         // Calculate average radius
1769         for(i = 0 ; i < t->total; i++, td++) {
1770                 t->val += VecLenf(t->center, td->iloc);
1771         }
1772
1773         t->val /= (float)t->total;
1774 }
1775
1776 int ToSphere(TransInfo *t, short mval[2]) 
1777 {
1778         float vec[3];
1779         float ratio, radius;
1780         int i;
1781         char str[64];
1782         TransData *td = t->data;
1783
1784         ratio = InputHorizontalRatio(t, mval);
1785
1786         snapGrid(t, &ratio);
1787
1788         applyNumInput(&t->num, &ratio);
1789
1790         if (ratio < 0)
1791                 ratio = 0.0f;
1792         else if (ratio > 1)
1793                 ratio = 1.0f;
1794
1795         /* header print for NumInput */
1796         if (hasNumInput(&t->num)) {
1797                 char c[20];
1798
1799                 outputNumInput(&(t->num), c);
1800
1801                 sprintf(str, "To Sphere: %s %s", c, t->proptext);
1802         }
1803         else {
1804                 /* default header print */
1805                 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
1806         }
1807         
1808         
1809         for(i = 0 ; i < t->total; i++, td++) {
1810                 float tratio;
1811                 if (td->flag & TD_NOACTION)
1812                         break;
1813
1814                 VecSubf(vec, td->iloc, t->center);
1815
1816                 radius = Normalize(vec);
1817
1818                 tratio = ratio * td->factor;
1819
1820                 VecMulf(vec, radius * (1.0f - tratio) + t->val * tratio);
1821
1822                 VecAddf(td->loc, t->center, vec);
1823         }
1824
1825         recalcData(t);
1826
1827         headerprint(str);
1828
1829         viewRedrawForce(t);
1830
1831         return 1;
1832 }
1833
1834 /* ************************** ROTATION *************************** */
1835
1836
1837 void initRotation(TransInfo *t) 
1838 {
1839         t->mode = TFM_ROTATION;
1840         t->transform = Rotation;
1841         
1842         t->ndof.axis = 16;
1843         /* Scale down and flip input for rotation */
1844         t->ndof.factor[0] = -0.2f;
1845         
1846         t->idx_max = 0;
1847         t->num.idx_max = 0;
1848         t->snap[0] = 0.0f;
1849         t->snap[1] = (float)((5.0/180)*M_PI);
1850         t->snap[2] = t->snap[1] * 0.2f;
1851         t->fac = 0;
1852 }
1853
1854 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
1855         float vec[3], totmat[3][3], smat[3][3];
1856         float eul[3], fmat[3][3], quat[4];
1857
1858         if (t->flag & T_POINTS) {
1859                 Mat3MulMat3(totmat, mat, td->mtx);
1860                 Mat3MulMat3(smat, td->smtx, totmat);
1861                 
1862                 VecSubf(vec, td->iloc, t->center);
1863                 Mat3MulVecfl(smat, vec);
1864                 
1865                 VecAddf(td->loc, vec, t->center);
1866
1867                 if(td->flag & TD_USEQUAT) {
1868                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1869                         Mat3ToQuat(fmat, quat); // Actual transform
1870                         QuatMul(td->ext->quat, quat, td->ext->iquat);
1871                 }
1872         }
1873         /**
1874          * HACK WARNING
1875          * 
1876          * This is some VERY ugly special case to deal with pose mode.
1877          * 
1878          * The problem is that mtx and smtx include each bone orientation.
1879          * 
1880          * That is needed to rotate each bone properly, HOWEVER, to calculate
1881          * the translation component, we only need the actual armature object's
1882          * matrix (and inverse). That is not all though. Once the proper translation
1883          * has been computed, it has to be converted back into the bone's space.
1884          */
1885         else if (t->flag & T_POSE) {
1886                 float pmtx[3][3], imtx[3][3];
1887
1888                 // Extract and invert armature object matrix            
1889                 Mat3CpyMat4(pmtx, t->poseobj->obmat);
1890                 Mat3Inv(imtx, pmtx);
1891                 
1892                 VecSubf(vec, td->center, t->center);
1893                 
1894                 Mat3MulVecfl(pmtx, vec);        // To Global space
1895                 Mat3MulVecfl(mat, vec);         // Applying rotation
1896                 Mat3MulVecfl(imtx, vec);        // To Local space
1897
1898                 VecAddf(vec, vec, t->center);
1899                 /* vec now is the location where the object has to be */
1900                 
1901                 VecSubf(vec, vec, td->center); // Translation needed from the initial location
1902                 
1903                 Mat3MulVecfl(pmtx, vec);        // To Global space
1904                 Mat3MulVecfl(td->smtx, vec);// To Pose space
1905
1906                 protectedTransBits(td->protectflag, vec);
1907
1908                 VecAddf(td->loc, td->iloc, vec);
1909                 
1910                 /* rotation */
1911                 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
1912                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1913
1914                         Mat3ToQuat(fmat, quat); // Actual transform
1915                         
1916                         QuatMul(td->ext->quat, quat, td->ext->iquat);
1917                         /* this function works on end result */
1918                         protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
1919                 }
1920         }
1921         else {
1922                 /* translation */
1923                 
1924                 VecSubf(vec, td->center, t->center);
1925                 Mat3MulVecfl(mat, vec);
1926                 VecAddf(vec, vec, t->center);
1927                 /* vec now is the location where the object has to be */
1928                 VecSubf(vec, vec, td->center);
1929                 Mat3MulVecfl(td->smtx, vec);
1930
1931                 protectedTransBits(td->protectflag, vec);
1932
1933                 if(td->tdi) {
1934                         TransDataIpokey *tdi= td->tdi;
1935                         add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
1936                         add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
1937                         add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
1938                 }
1939                 else VecAddf(td->loc, td->iloc, vec);
1940
1941                 /* rotation */
1942                 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
1943                 
1944                         if(td->flag & TD_USEQUAT) {
1945                                 Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1946                                 Mat3ToQuat(fmat, quat); // Actual transform
1947                                 
1948                                 QuatMul(td->ext->quat, quat, td->ext->iquat);
1949                                 /* this function works on end result */
1950                                 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
1951                         }
1952                         else {
1953                                 float obmat[3][3];
1954                                 
1955                                 /* are there ipo keys? */
1956                                 if(td->tdi) {
1957                                         TransDataIpokey *tdi= td->tdi;
1958                                         float rot[3];
1959                                         
1960                                         /* calculate the total rotatation in eulers */
1961                                         VecAddf(eul, td->ext->irot, td->ext->drot);
1962                                         EulToMat3(eul, obmat);
1963                                         /* mat = transform, obmat = object rotation */
1964                                         Mat3MulMat3(fmat, mat, obmat);
1965                                         
1966                                         Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
1967                                         
1968                                         /* correct back for delta rot */
1969                                         if(tdi->flag & TOB_IPODROT) {
1970                                                 VecSubf(rot, eul, td->ext->irot);
1971                                         }
1972                                         else {
1973                                                 VecSubf(rot, eul, td->ext->drot);
1974                                         }
1975                                         
1976                                         VecMulf(rot, (float)(9.0/M_PI_2));
1977                                         VecSubf(rot, rot, tdi->oldrot);
1978                                         
1979                                         protectedRotateBits(td->protectflag, rot, tdi->oldrot);
1980                                         
1981                                         add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
1982                                         add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
1983                                         add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
1984                                 }
1985                                 else {
1986                                         Mat3MulMat3(totmat, mat, td->mtx);
1987                                         Mat3MulMat3(smat, td->smtx, totmat);
1988                                         
1989                                         /* calculate the total rotatation in eulers */
1990                                         VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
1991                                         EulToMat3(eul, obmat);
1992                                         /* mat = transform, obmat = object rotation */
1993                                         Mat3MulMat3(fmat, smat, obmat);
1994                                         
1995                                         Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
1996                                         
1997                                         /* correct back for delta rot */
1998                                         VecSubf(eul, eul, td->ext->drot);
1999                                         
2000                                         /* and apply */
2001                                         protectedRotateBits(td->protectflag, eul, td->ext->irot);
2002                                         VECCOPY(td->ext->rot, eul);
2003                                 }
2004                         }
2005                 }
2006         }
2007 }
2008
2009 static void applyRotation(TransInfo *t, float angle, float axis[3]) 
2010 {
2011         TransData *td = t->data;
2012         float mat[3][3], center[3];
2013         int i;
2014
2015         /* saving original center */
2016         if (t->around == V3D_LOCAL) {
2017                 VECCOPY(center, t->center);
2018         }
2019
2020         VecRotToMat3(axis, angle, mat);
2021         
2022         for(i = 0 ; i < t->total; i++, td++) {
2023
2024                 if (td->flag & TD_NOACTION)
2025                         break;
2026                 
2027                 /* local constraint shouldn't alter center */
2028                 if (t->around == V3D_LOCAL) {
2029                         if (t->flag & (T_OBJECT|T_POSE)) {
2030                                 VECCOPY(t->center, td->center);
2031                         }
2032                         else {
2033                                 if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
2034                                         VECCOPY(t->center, td->center);
2035                                 }
2036                         }
2037                 }
2038                 
2039                 if (t->con.applyRot) {
2040                         t->con.applyRot(t, td, axis);
2041                         VecRotToMat3(axis, angle * td->factor, mat);
2042                 }
2043                 else if (t->flag & T_PROP_EDIT) {
2044                         VecRotToMat3(axis, angle * td->factor, mat);
2045                 }
2046
2047                 ElementRotation(t, td, mat);
2048         }
2049
2050         /* restoring original center */
2051         if (t->around == V3D_LOCAL) {
2052                 VECCOPY(t->center, center);
2053         }
2054 }
2055
2056 int Rotation(TransInfo *t, short mval[2]) 
2057 {
2058         char str[64];
2059
2060         float final;
2061
2062         int dx2 = t->center2d[0] - mval[0];
2063         int dy2 = t->center2d[1] - mval[1];
2064         double B = sqrt(dx2*dx2+dy2*dy2);
2065
2066         int dx1 = t->center2d[0] - t->imval[0];
2067         int dy1 = t->center2d[1] - t->imval[1];
2068         double A = sqrt(dx1*dx1+dy1*dy1);
2069
2070         int dx3 = mval[0] - t->imval[0];
2071         int dy3 = mval[1] - t->imval[1];
2072                 /* use doubles here, to make sure a "1.0" (no rotation) doesnt become 9.999999e-01, which gives 0.02 for acos */
2073         double deler= ((double)((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3) ))
2074                 / (2.0 * (A*B?A*B:1.0));
2075         /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
2076
2077         float dphi;
2078
2079         float axis[3];
2080         float mat[3][3];
2081
2082         VECCOPY(axis, t->viewinv[2]);
2083         VecMulf(axis, -1.0f);
2084         Normalize(axis);
2085
2086         dphi = saacos((float)deler);
2087         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
2088
2089         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2090         else t->fac += dphi;
2091
2092         /*
2093         clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
2094         if (t->fac >= 2 * M_PI)
2095                 t->fac -= 2 * M_PI;
2096         else if (t->fac <= -2 * M_PI)
2097                 t->fac -= -2 * M_PI;
2098         */
2099
2100         final = t->fac;
2101
2102         applyNDofInput(&t->ndof, &final);
2103         
2104         snapGrid(t, &final);
2105
2106         t->imval[0] = mval[0];
2107         t->imval[1] = mval[1];
2108
2109         if (t->con.applyRot) {
2110                 t->con.applyRot(t, NULL, axis);
2111         }
2112         
2113         applySnapping(t, &final);
2114
2115         if (hasNumInput(&t->num)) {
2116                 char c[20];
2117
2118                 applyNumInput(&t->num, &final);
2119
2120                 outputNumInput(&(t->num), c);
2121
2122                 sprintf(str, "Rot: %s %s", &c[0], t->proptext);
2123
2124                 /* Clamp between -180 and 180 */
2125                 while (final >= 180.0)
2126                         final -= 360.0;
2127                 
2128                 while (final <= -180.0)
2129                         final += 360.0;
2130
2131                 final *= (float)(M_PI / 180.0);
2132         }
2133         else {
2134                 sprintf(str, "Rot: %.2f%s %s", 180.0*final/M_PI, t->con.text, t->proptext);
2135         }
2136
2137         VecRotToMat3(axis, final, mat);
2138
2139         t->val = final;                         // used in manipulator
2140         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2141         
2142         applyRotation(t, final, axis);
2143         
2144         recalcData(t);
2145
2146         headerprint(str);
2147
2148         viewRedrawForce(t);
2149
2150         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2151
2152         return 1;
2153 }
2154
2155
2156 /* ************************** TRACKBALL *************************** */
2157
2158 void initTrackball(TransInfo *t) 
2159 {
2160         t->mode = TFM_TRACKBALL;
2161         t->transform = Trackball;
2162         
2163         t->ndof.axis = 40;
2164         /* Scale down input for rotation */
2165         t->ndof.factor[0] = 0.2f;
2166         t->ndof.factor[1] = 0.2f;
2167
2168         t->idx_max = 1;
2169         t->num.idx_max = 1;
2170         t->snap[0] = 0.0f;
2171         t->snap[1] = (float)((5.0/180)*M_PI);
2172         t->snap[2] = t->snap[1] * 0.2f;
2173         t->fac = 0;
2174         
2175         t->flag |= T_NO_CONSTRAINT;
2176 }
2177
2178 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
2179 {
2180         TransData *td = t->data;
2181         float mat[3][3], smat[3][3], totmat[3][3];
2182         int i;
2183
2184         VecRotToMat3(axis1, angles[0], smat);
2185         VecRotToMat3(axis2, angles[1], totmat);
2186         
2187         Mat3MulMat3(mat, smat, totmat);
2188
2189         for(i = 0 ; i < t->total; i++, td++) {
2190                 if (td->flag & TD_NOACTION)
2191                         break;
2192                 
2193                 if (t->around == V3D_LOCAL) {
2194                         if (t->flag & T_OBJECT)
2195                                 VECCOPY(t->center, td->center); // not supported in editmode yet
2196                 }
2197                 
2198                 if (t->flag & T_PROP_EDIT) {
2199                         VecRotToMat3(axis1, td->factor * angles[0], smat);
2200                         VecRotToMat3(axis2, td->factor * angles[1], totmat);
2201                         
2202                         Mat3MulMat3(mat, smat, totmat);
2203                 }
2204
2205                 ElementRotation(t, td, mat);
2206         }
2207 }
2208
2209 int Trackball(TransInfo *t, short mval[2]) 
2210 {
2211         char str[128];
2212         float axis1[3], axis2[3];
2213         float mat[3][3], totmat[3][3], smat[3][3];
2214         float phi[2];
2215         
2216         VECCOPY(axis1, t->persinv[0]);
2217         VECCOPY(axis2, t->persinv[1]);
2218         Normalize(axis1);
2219         Normalize(axis2);
2220         
2221         /* factore has to become setting or so */
2222         phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
2223         phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
2224         
2225         //if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2226         //else t->fac += dphi;
2227         
2228         applyNDofInput(&t->ndof, phi);
2229         
2230         snapGrid(t, phi);
2231         
2232         if (hasNumInput(&t->num)) {
2233                 char c[40];
2234                 
2235                 applyNumInput(&t->num, phi);
2236                 
2237                 outputNumInput(&(t->num), c);
2238                 
2239                 sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
2240                 
2241                 phi[0] *= (float)(M_PI / 180.0);
2242                 phi[1] *= (float)(M_PI / 180.0);
2243         }
2244         else {
2245                 sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
2246         }
2247         
2248         VecRotToMat3(axis1, phi[0], smat);
2249         VecRotToMat3(axis2, phi[1], totmat);
2250         
2251         Mat3MulMat3(mat, smat, totmat);
2252         
2253         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2254         
2255         applyTrackball(t, axis1, axis2, phi);
2256         
2257         recalcData(t);
2258         
2259         headerprint(str);
2260         
2261         viewRedrawForce(t);
2262         
2263         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2264         
2265         return 1;
2266 }
2267
2268 /* ************************** TRANSLATION *************************** */
2269         
2270 void initTranslation(TransInfo *t) 
2271 {
2272         t->mode = TFM_TRANSLATION;
2273         t->transform = Translation;
2274
2275         t->idx_max = (t->flag & T_2D_EDIT)? 1: 2;
2276         t->num.flag = 0;
2277         t->num.idx_max = t->idx_max;
2278         
2279         t->ndof.axis = 7;
2280
2281         if(t->spacetype == SPACE_VIEW3D) {
2282                 /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
2283                 if(t->flag & (T_EDIT|T_POSE)) {
2284                         Object *ob= G.obedit?G.obedit:t->poseobj;
2285                         float vec[3];
2286                         
2287                         VECCOPY(vec, t->center);
2288                         Mat4MulVecfl(ob->obmat, vec);
2289                         initgrabz(vec[0], vec[1], vec[2]);
2290                 }
2291                 else {
2292                         initgrabz(t->center[0], t->center[1], t->center[2]);
2293                 } 
2294
2295                 t->snap[0] = 0.0f;
2296                 t->snap[1] = G.vd->gridview * 1.0f;
2297                 t->snap[2] = t->snap[1] * 0.1f;
2298         }
2299         else if(t->spacetype == SPACE_IMAGE) {
2300                 t->snap[0] = 0.0f;
2301                 t->snap[1] = 0.125f;
2302                 t->snap[2] = 0.0625f;
2303         }
2304         else {
2305                 t->snap[0] = 0.0f;
2306                 t->snap[1] = t->snap[2] = 1.0f;
2307         }
2308 }
2309
2310 static void headerTranslation(TransInfo *t, float vec[3], char *str) {
2311         char tvec[60];
2312         char distvec[20];
2313         float dvec[3];
2314         float dist;
2315         
2316         convertVecToDisplayNum(vec, dvec);
2317
2318         if (hasNumInput(&t->num)) {
2319                 outputNumInput(&(t->num), tvec);
2320                 dist = VecLength(t->num.val);
2321         }
2322         else {
2323                 dist = VecLength(vec);
2324                 sprintf(&tvec[0], "%.4f", dvec[0]);
2325                 sprintf(&tvec[20], "%.4f", dvec[1]);
2326                 sprintf(&tvec[40], "%.4f", dvec[2]);
2327         }
2328
2329         if( dist > 1e10 || dist < -1e10 )       /* prevent string buffer overflow */
2330                 sprintf(distvec, "%.4e", dist);
2331         else
2332                 sprintf(distvec, "%.4f", dist);
2333
2334         if (t->con.mode & CON_APPLY) {
2335                 switch(t->num.idx_max) {
2336                 case 0:
2337                         sprintf(str, "D: %s (%s)%s %s", &tvec[0], distvec, t->con.text, t->proptext);
2338                         break;
2339                 case 1:
2340                         sprintf(str, "D: %s   D: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
2341                         break;
2342                 case 2:
2343                         sprintf(str, "D: %s   D: %s  D: %s (%s)%s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext);
2344                 }
2345         }
2346         else {
2347                 if(t->flag & T_2D_EDIT)
2348                         sprintf(str, "Dx: %s   Dy: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
2349                 else
2350                         sprintf(str, "Dx: %s   Dy: %s  Dz: %s (%s)%s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext);
2351         }
2352 }
2353
2354 static void applyTranslation(TransInfo *t, float vec[3]) {
2355         TransData *td = t->data;
2356         float tvec[3];
2357         int i;
2358
2359         for(i = 0 ; i < t->total; i++, td++) {
2360                 if (td->flag & TD_NOACTION)
2361                         break;
2362
2363                 if (t->con.applyVec) {
2364                         float pvec[3];
2365                         t->con.applyVec(t, td, vec, tvec, pvec);
2366                 }
2367                 else {
2368                         VECCOPY(tvec, vec);
2369                 }
2370
2371                 Mat3MulVecfl(td->smtx, tvec);
2372                 VecMulf(tvec, td->factor);
2373                 
2374                 protectedTransBits(td->protectflag, tvec);
2375                 
2376                 /* transdata ipokey */
2377                 if(td->tdi) {
2378                         TransDataIpokey *tdi= td->tdi;
2379                         add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
2380                         add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
2381                         add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
2382                 }
2383                 else VecAddf(td->loc, td->iloc, tvec);
2384         }
2385 }
2386
2387 /* uses t->vec to store actual translation in */
2388 int Translation(TransInfo *t, short mval[2]) 
2389 {
2390         float tvec[3];
2391         char str[200];
2392         
2393         if(t->flag & T_SHIFT_MOD) {
2394                 float dvec[3];
2395                 /* calculate the main translation and the precise one separate */
2396                 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
2397                 VecMulf(dvec, 0.1f);
2398                 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
2399                 VecAddf(t->vec, t->vec, dvec);
2400         }
2401         else convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2402
2403         if (t->con.mode & CON_APPLY) {
2404                 float pvec[3] = {0.0f, 0.0f, 0.0f};
2405                 applySnapping(t, t->vec);
2406                 t->con.applyVec(t, NULL, t->vec, tvec, pvec);
2407                 VECCOPY(t->vec, tvec);
2408                 headerTranslation(t, pvec, str);
2409         }
2410         else {
2411                 applyNDofInput(&t->ndof, t->vec);
2412                 snapGrid(t, t->vec);
2413                 applyNumInput(&t->num, t->vec);
2414                 applySnapping(t, t->vec);
2415                 headerTranslation(t, t->vec, str);
2416         }
2417         
2418         applyTranslation(t, t->vec);
2419
2420         /* evil hack - redo translation if cliiping needeed */
2421         if (t->flag & T_CLIP_UV && clipUVTransform(t, t->vec, 0))
2422                 applyTranslation(t, t->vec);
2423
2424         recalcData(t);
2425
2426         headerprint(str);
2427         
2428         viewRedrawForce(t);
2429
2430         drawSnapping(t);
2431
2432         return 1;
2433 }
2434
2435 /* ************************** SHRINK/FATTEN *************************** */
2436
2437 void initShrinkFatten(TransInfo *t) 
2438 {
2439         // If not in mesh edit mode, fallback to Resize
2440         if (G.obedit==NULL || G.obedit->type != OB_MESH) {
2441                 initResize(t);
2442         }
2443         else {
2444                 t->mode = TFM_SHRINKFATTEN;
2445                 t->transform = ShrinkFatten;
2446         
2447                 t->idx_max = 0;
2448                 t->num.idx_max = 0;
2449                 t->snap[0] = 0.0f;
2450                 t->snap[1] = 1.0f;
2451                 t->snap[2] = t->snap[1] * 0.1f;
2452                 
2453                 t->flag |= T_NO_CONSTRAINT;
2454         }
2455 }
2456
2457
2458
2459 int ShrinkFatten(TransInfo *t, short mval[2]) 
2460 {
2461         float vec[3];
2462         float distance;
2463         int i;
2464         char str[64];
2465         TransData *td = t->data;
2466
2467         distance = -InputVerticalAbsolute(t, mval);
2468
2469         snapGrid(t, &distance);
2470
2471         applyNumInput(&t->num, &distance);
2472
2473         /* header print for NumInput */
2474         if (hasNumInput(&t->num)) {
2475                 char c[20];
2476
2477                 outputNumInput(&(t->num), c);
2478
2479                 sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
2480         }
2481         else {
2482                 /* default header print */
2483                 sprintf(str, "Shrink/Fatten: %.4f %s", distance, t->proptext);
2484         }
2485         
2486         
2487         for(i = 0 ; i < t->total; i++, td++) {
2488                 if (td->flag & TD_NOACTION)
2489                         break;
2490
2491                 VECCOPY(vec, td->axismtx[2]);
2492                 VecMulf(vec, distance);
2493                 VecMulf(vec, td->factor);
2494
2495                 VecAddf(td->loc, td->iloc, vec);
2496         }
2497
2498         recalcData(t);
2499
2500         headerprint(str);
2501
2502         viewRedrawForce(t);
2503
2504         return 1;
2505 }
2506
2507 /* ************************** TILT *************************** */
2508
2509 void initTilt(TransInfo *t) 
2510 {
2511         t->mode = TFM_TILT;
2512         t->transform = Tilt;
2513
2514         t->ndof.axis = 16;
2515         /* Scale down and flip input for rotation */
2516         t->ndof.factor[0] = -0.2f;
2517
2518         t->idx_max = 0;
2519         t->num.idx_max = 0;
2520         t->snap[0] = 0.0f;
2521         t->snap[1] = (float)((5.0/180)*M_PI);
2522         t->snap[2] = t->snap[1] * 0.2f;
2523         t->fac = 0;
2524         
2525         t->flag |= T_NO_CONSTRAINT;
2526 }
2527
2528
2529
2530 int Tilt(TransInfo *t, short mval[2]) 
2531 {
2532         TransData *td = t->data;
2533         int i;
2534         char str[50];
2535
2536         float final;
2537
2538         int dx2 = t->center2d[0] - mval[0];
2539         int dy2 = t->center2d[1] - mval[1];
2540         float B = (float)sqrt(dx2*dx2+dy2*dy2);
2541
2542         int dx1 = t->center2d[0] - t->imval[0];
2543         int dy1 = t->center2d[1] - t->imval[1];
2544         float A = (float)sqrt(dx1*dx1+dy1*dy1);
2545
2546         int dx3 = mval[0] - t->imval[0];
2547         int dy3 = mval[1] - t->imval[1];
2548
2549         float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
2550                 / (2 * A * B);
2551
2552         float dphi;
2553
2554         dphi = saacos(deler);
2555         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
2556
2557         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2558         else t->fac += dphi;
2559
2560         final = t->fac;
2561         
2562         applyNDofInput(&t->ndof, &final);
2563
2564         snapGrid(t, &final);
2565
2566         t->imval[0] = mval[0];
2567         t->imval[1] = mval[1];
2568
2569         if (hasNumInput(&t->num)) {
2570                 char c[20];
2571
2572                 applyNumInput(&t->num, &final);
2573
2574                 outputNumInput(&(t->num), c);
2575
2576                 sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
2577
2578                 final *= (float)(M_PI / 180.0);
2579         }
2580         else {
2581                 sprintf(str, "Tilt: %.2f %s", 180.0*final/M_PI, t->proptext);
2582         }
2583
2584         for(i = 0 ; i < t->total; i++, td++) {
2585                 if (td->flag & TD_NOACTION)
2586                         break;
2587
2588                 if (td->val) {
2589                         *td->val = td->ival + final * td->factor;
2590                 }
2591         }
2592
2593         recalcData(t);
2594
2595         headerprint(str);
2596
2597         viewRedrawForce(t);
2598
2599         helpline (t, t->center);
2600
2601         return 1;
2602 }
2603
2604
2605 /* ******************** Curve Shrink/Fatten *************** */
2606
2607 int CurveShrinkFatten(TransInfo *t, short mval[2]) 
2608 {
2609         TransData *td = t->data;
2610         float ratio;
2611         int i;
2612         char str[50];
2613         
2614         if(t->flag & T_SHIFT_MOD) {
2615                 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2616                 float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2617                 float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2618                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2619                 
2620                 dx= (float)(t->center2d[0] - mval[0]);
2621                 dy= (float)(t->center2d[1] - mval[1]);
2622                 ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
2623                 
2624         }
2625         else {
2626                 float dx= (float)(t->center2d[0] - mval[0]);
2627                 float dy= (float)(t->center2d[1] - mval[1]);
2628                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2629         }
2630         
2631         snapGrid(t, &ratio);
2632         
2633         applyNumInput(&t->num, &ratio);
2634         
2635         /* header print for NumInput */
2636         if (hasNumInput(&t->num)) {
2637                 char c[20];
2638                 
2639                 outputNumInput(&(t->num), c);
2640                 sprintf(str, "Shrink/Fatten: %s", c);
2641         }
2642         else {
2643                 sprintf(str, "Shrink/Fatten: %3f", ratio);
2644         }
2645         
2646         for(i = 0 ; i < t->total; i++, td++) {
2647                 if (td->flag & TD_NOACTION)
2648                         break;
2649                 
2650                 if(td->val) {
2651                         //*td->val= ratio;
2652                         *td->val= td->ival*ratio;
2653                         if (*td->val <= 0.0f) *td->val = 0.0001f;
2654                 }
2655         }
2656         
2657         recalcData(t);
2658         
2659         headerprint(str);
2660         
2661         viewRedrawForce(t);
2662         
2663         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2664         
2665         return 1;
2666 }
2667
2668 void initCurveShrinkFatten(TransInfo *t)
2669 {
2670         t->mode = TFM_CURVE_SHRINKFATTEN;
2671         t->transform = CurveShrinkFatten;
2672         
2673         t->idx_max = 0;
2674         t->num.idx_max = 0;
2675         t->snap[0] = 0.0f;
2676         t->snap[1] = 0.1f;
2677         t->snap[2] = t->snap[1] * 0.1f;
2678         
2679         t->flag |= T_NO_CONSTRAINT;
2680
2681         t->fac = (float)sqrt( (
2682                    ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
2683                    +
2684                    ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
2685                    ) );
2686 }
2687
2688 /* ************************** PUSH/PULL *************************** */
2689
2690 void initPushPull(TransInfo *t) 
2691 {
2692         t->mode = TFM_PUSHPULL;
2693         t->transform = PushPull;
2694         
2695         t->ndof.axis = 4;
2696         /* Flip direction */
2697         t->ndof.factor[0] = -1.0f;
2698
2699         t->idx_max = 0;
2700         t->num.idx_max = 0;
2701         t->snap[0] = 0.0f;
2702         t->snap[1] = 1.0f;
2703         t->snap[2] = t->snap[1] * 0.1f;
2704 }
2705
2706
2707 int PushPull(TransInfo *t, short mval[2]) 
2708 {
2709         float vec[3], axis[3];
2710         float distance;
2711         int i;
2712         char str[128];
2713         TransData *td = t->data;
2714
2715         distance = InputVerticalAbsolute(t, mval);
2716         
2717         applyNDofInput(&t->ndof, &distance);
2718
2719         snapGrid(t, &distance);
2720
2721         applyNumInput(&t->num, &distance);
2722
2723         /* header print for NumInput */
2724         if (hasNumInput(&t->num)) {
2725                 char c[20];
2726
2727                 outputNumInput(&(t->num), c);
2728
2729                 sprintf(str, "Push/Pull: %s%s %s", c, t->con.text, t->proptext);
2730         }
2731         else {
2732                 /* default header print */
2733                 sprintf(str, "Push/Pull: %.4f%s %s", distance, t->con.text, t->proptext);
2734         }
2735         
2736         if (t->con.applyRot && t->con.mode & CON_APPLY) {
2737                 t->con.applyRot(t, NULL, axis);
2738         }
2739         
2740         for(i = 0 ; i < t->total; i++, td++) {
2741                 if (td->flag & TD_NOACTION)
2742                         break;
2743
2744                 VecSubf(vec, t->center, td->center);
2745                 if (t->con.applyRot && t->con.mode & CON_APPLY) {
2746                         t->con.applyRot(t, td, axis);
2747                         if (isLockConstraint(t)) {
2748                                 float dvec[3];
2749                                 Projf(dvec, vec, axis);
2750                                 VecSubf(vec, vec, dvec);
2751                         }
2752                         else {
2753                                 Projf(vec, vec, axis);
2754                         }
2755                 }
2756                 Normalize(vec);
2757                 VecMulf(vec, distance);
2758                 VecMulf(vec, td->factor);
2759
2760                 VecAddf(td->loc, td->iloc, vec);
2761         }
2762
2763         recalcData(t);
2764
2765         headerprint(str);
2766
2767         viewRedrawForce(t);
2768
2769         return 1;
2770 }
2771
2772 /* ************************** CREASE *************************** */
2773
2774 void initCrease(TransInfo *t) 
2775 {
2776         t->mode = TFM_CREASE;
2777         t->transform = Crease;
2778         
2779         t->idx_max = 0;
2780         t->num.idx_max = 0;
2781         t->snap[0] = 0.0f;
2782         t->snap[1] = 0.1f;
2783         t->snap[2] = t->snap[1] * 0.1f;
2784         
2785         t->flag |= T_NO_CONSTRAINT;
2786
2787         t->fac = (float)sqrt(
2788                 (
2789                         ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
2790                 +
2791                         ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
2792                 ) );
2793
2794         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2795 }
2796
2797 int Crease(TransInfo *t, short mval[2]) 
2798 {
2799         TransData *td = t->data;
2800         float crease;
2801         int i;
2802         char str[50];
2803
2804                 
2805         if(t->flag & T_SHIFT_MOD) {
2806                 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2807                 float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2808                 float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2809                 crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
2810                 
2811                 dx= (float)(t->center2d[0] - mval[0]);
2812                 dy= (float)(t->center2d[1] - mval[1]);
2813                 crease+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -crease);
2814                 
2815         }
2816         else {
2817                 float dx= (float)(t->center2d[0] - mval[0]);
2818                 float dy= (float)(t->center2d[1] - mval[1]);
2819                 crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
2820         }
2821
2822         crease -= 1.0f;
2823         if (crease > 1.0f) crease = 1.0f;
2824
2825         snapGrid(t, &crease);
2826
2827         applyNumInput(&t->num, &crease);
2828
2829         /* header print for NumInput */
2830         if (hasNumInput(&t->num)) {
2831                 char c[20];
2832
2833                 outputNumInput(&(t->num), c);
2834
2835                 if (crease >= 0.0f)
2836                         sprintf(str, "Crease: +%s %s", c, t->proptext);
2837                 else
2838                         sprintf(str, "Crease: %s %s", c, t->proptext);
2839         }
2840         else {
2841                 /* default header print */
2842                 if (crease >= 0.0f)
2843                         sprintf(str, "Crease: +%.3f %s", crease, t->proptext);
2844                 else
2845                         sprintf(str, "Crease: %.3f %s", crease, t->proptext);
2846         }
2847         
2848         for(i = 0 ; i < t->total; i++, td++) {
2849                 if (td->flag & TD_NOACTION)
2850                         break;
2851
2852                 if (td->val) {
2853                         *td->val = td->ival + crease * td->factor;
2854                         if (*td->val < 0.0f) *td->val = 0.0f;
2855                         if (*td->val > 1.0f) *td->val = 1.0f;
2856                 }
2857         }
2858
2859         recalcData(t);
2860
2861         headerprint(str);
2862
2863         viewRedrawForce(t);
2864
2865         helpline (t, t->center);
2866
2867         return 1;
2868 }
2869
2870 /* ******************** EditBone (B-bone) width scaling *************** */
2871
2872 void initBoneSize(TransInfo *t)
2873 {
2874         t->mode = TFM_BONESIZE;
2875         t->transform = BoneSize;
2876         
2877         t->idx_max = 0;
2878         t->num.idx_max = 0;
2879         t->snap[0] = 0.0f;
2880         t->snap[1] = 0.1f;
2881         t->snap[2] = t->snap[1] * 0.1f;
2882
2883         t->flag |= T_NO_CONSTRAINT;
2884
2885         t->fac = (float)sqrt( (
2886                                            ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
2887                                            +
2888                                            ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
2889                                            ) );
2890         
2891         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2892 }
2893
2894 static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3]) 
2895 {
2896         float tmat[3][3], smat[3][3], oldy;
2897         float sizemat[3][3];
2898         
2899         Mat3MulMat3(smat, mat, td->mtx);
2900         Mat3MulMat3(tmat, td->smtx, smat);
2901         
2902         if (t->con.applySize) {
2903                 t->con.applySize(t, td, tmat);
2904         }
2905         
2906         /* we've tucked the scale in loc */
2907         oldy= td->iloc[1];
2908         SizeToMat3(td->iloc, sizemat);
2909         Mat3MulMat3(tmat, tmat, sizemat);
2910         Mat3ToSize(tmat, td->loc);
2911         td->loc[1]= oldy;
2912 }
2913
2914 int BoneSize(TransInfo *t, short mval[2]) 
2915 {
2916         TransData *td = t->data;
2917         float size[3], mat[3][3];
2918         float ratio;
2919         int i;
2920         char str[50];
2921         
2922         /* for manipulator, center handle, the scaling can't be done relative to center */
2923         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
2924                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
2925         }
2926         else {
2927                 
2928                 if(t->flag & T_SHIFT_MOD) {
2929                         /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2930                         float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2931                         float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2932                         ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2933                         
2934                         dx= (float)(t->center2d[0] - mval[0]);
2935                         dy= (float)(t->center2d[1] - mval[1]);
2936                         ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
2937                         
2938                 }
2939                 else {
2940                         float dx= (float)(t->center2d[0] - mval[0]);
2941                         float dy= (float)(t->center2d[1] - mval[1]);
2942                         ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2943                 }
2944                 
2945                 /* flip scale, but not for manipulator center handle */
2946                 if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
2947                          (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
2948                         ratio *= -1.0f;
2949         }
2950         
2951         size[0] = size[1] = size[2] = ratio;
2952         
2953         snapGrid(t, size);
2954         
2955         if (hasNumInput(&t->num)) {
2956                 applyNumInput(&t->num, size);
2957                 constraintNumInput(t, size);
2958         }
2959         
2960         SizeToMat3(size, mat);
2961         
2962         if (t->con.applySize) {
2963                 t->con.applySize(t, NULL, mat);
2964         }
2965         
2966         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2967         
2968         headerResize(t, size, str);
2969         
2970         for(i = 0 ; i < t->total; i++, td++) {
2971                 if (td->flag & TD_NOACTION)
2972                         break;
2973                 
2974                 ElementBoneSize(t, td, mat);
2975         }
2976         
2977         recalcData(t);
2978         
2979         headerprint(str);
2980         
2981         viewRedrawForce(t);
2982         
2983         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2984         
2985         return 1;
2986 }
2987
2988
2989 /* ******************** EditBone envelope *************** */
2990
2991 void initBoneEnvelope(TransInfo *t)
2992 {
2993         t->mode = TFM_BONE_ENVELOPE;
2994         t->transform = BoneEnvelope;
2995         
2996         t->idx_max = 0;
2997         t->num.idx_max = 0;
2998         t->snap[0] = 0.0f;
2999         t->snap[1] = 0.1f;
3000         t->snap[2] = t->snap[1] * 0.1f;
3001
3002         t->flag |= T_NO_CONSTRAINT;
3003
3004         t->fac = (float)sqrt( (
3005                                                    ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
3006                                                    +
3007                                                    ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
3008                                                    ) );
3009         
3010         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
3011 }
3012
3013 int BoneEnvelope(TransInfo *t, short mval[2]) 
3014 {
3015         TransData *td = t->data;
3016         float ratio;
3017         int i;
3018         char str[50];
3019         
3020         if(t->flag & T_SHIFT_MOD) {
3021                 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
3022                 float dx= (float)(t->center2d[0] - t->shiftmval[0]);
3023                 float dy= (float)(t->center2d[1] - t->shiftmval[1]);
3024                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
3025                 
3026                 dx= (float)(t->center2d[0] - mval[0]);
3027                 dy= (float)(t->center2d[1] - mval[1]);
3028                 ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
3029                 
3030         }
3031         else {
3032                 float dx= (float)(t->center2d[0] - mval[0]);
3033                 float dy= (float)(t->center2d[1] - mval[1]);
3034                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
3035         }
3036         
3037         snapGrid(t, &ratio);
3038         
3039         applyNumInput(&t->num, &ratio);
3040         
3041         /* header print for NumInput */
3042         if (hasNumInput(&t->num)) {
3043                 char c[20];
3044                 
3045                 outputNumInput(&(t->num), c);
3046                 sprintf(str, "Envelope: %s", c);
3047         }
3048         else {
3049                 sprintf(str, "Envelope: %3f", ratio);
3050         }
3051         
3052         for(i = 0 ; i < t->total; i++, td++) {
3053                 if (td->flag & TD_NOACTION)
3054                         break;
3055                 
3056                 if(td->val) *td->val= td->ival*ratio;
3057         }
3058         
3059         recalcData(t);
3060         
3061         headerprint(str);
3062         
3063         force_draw(0);
3064         
3065         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
3066         
3067         return 1;
3068 }
3069
3070
3071 /* ******************** EditBone roll *************** */
3072
3073 void initBoneRoll(TransInfo *t)
3074 {
3075         t->mode = TFM_BONE_ROLL;
3076         t->transform = BoneRoll;
3077
3078         t->idx_max = 0;
3079         t->num.idx_max = 0;
3080         t->snap[0] = 0.0f;
3081         t->snap[1] = (float)((5.0/180)*M_PI);
3082         t->snap[2] = t->snap[1] * 0.2f;
3083         
3084         t->fac = 0.0f;
3085         
3086         t->flag |= T_NO_CONSTRAINT;
3087 }
3088
3089 int BoneRoll(TransInfo *t, short mval[2]) 
3090 {
3091         TransData *td = t->data;
3092         int i;
3093         char str[50];
3094
3095         float final;
3096
3097         int dx2 = t->center2d[0] - mval[0];
3098         int dy2 = t->center2d[1] - mval[1];
3099         double B = sqrt(dx2*dx2+dy2*dy2);
3100
3101         int dx1 = t->center2d[0] - t->imval[0];
3102         int dy1 = t->center2d[1] - t->imval[1];
3103         double A = sqrt(dx1*dx1+dy1*dy1);
3104
3105         int dx3 = mval[0] - t->imval[0];
3106         int dy3 = mval[1] - t->imval[1];
3107                 /* use doubles here, to make sure a "1.0" (no rotation) doesnt become 9.999999e-01, which gives 0.02 for acos */
3108         double deler= ((double)((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3) ))
3109                 / (2.0 * (A*B?A*B:1.0));
3110         /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
3111
3112         float dphi;
3113         
3114         dphi = saacos((float)deler);
3115         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
3116
3117         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
3118         else t->fac += dphi;
3119
3120         final = t->fac;
3121
3122         snapGrid(t, &final);
3123
3124         t->imval[0] = mval[0];
3125         t->imval[1] = mval[1];
3126
3127         if (hasNumInput(&t->num)) {
3128                 char c[20];
3129
3130                 applyNumInput(&t->num, &final);
3131
3132                 outputNumInput(&(t->num), c);
3133
3134                 sprintf(str, "Roll: %s", &c[0]);
3135
3136                 final *= (float)(M_PI / 180.0);
3137         }
3138         else {
3139                 sprintf(str, "Roll: %.2f", 180.0*final/M_PI);
3140         }
3141         
3142         /* set roll values */
3143         for (i = 0; i < t->total; i++, td++) {  
3144                 if (td->flag & TD_NOACTION)
3145                         break;
3146                 
3147                 *(td->val) = td->ival - final;
3148         }
3149                 
3150         recalcData(t);
3151
3152         headerprint(str);
3153
3154         viewRedrawForce(t);
3155
3156         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
3157
3158         return 1;
3159 }
3160
3161 /* ************************** MIRROR *************************** */
3162
3163 void Mirror(short mode) 
3164 {
3165         TransData *td;
3166         float mati[3][3], matview[3][3], mat[3][3];
3167         float size[3];
3168         int i;
3169
3170         Trans.context = CTX_NO_PET;
3171
3172         initTrans(&Trans);              // internal data, mouse, vectors
3173
3174         Mat3One(mati);
3175         Mat3CpyMat4(matview, Trans.viewinv); // t->viewinv was set in initTrans
3176         Mat3Ortho(matview);
3177
3178         createTransData(&Trans);        // make TransData structs from selection
3179
3180         calculatePropRatio(&Trans);
3181         calculateCenter(&Trans);
3182
3183         initResize(&Trans);
3184
3185         if (Trans.total == 0) {
3186                 postTrans(&Trans);
3187                 return;
3188         }
3189
3190         size[0] = size[1] = size[2] = 1.0f;
3191         td = Trans.data;
3192
3193         switch (mode) {
3194         case 1:
3195                 size[0] = -1.0f;
3196                 setConstraint(&Trans, mati, (CON_AXIS0), "");
3197                 break;
3198         case 2:
3199                 size[1] = -1.0f;
3200                 setConstraint(&Trans, mati, (CON_AXIS1), "");
3201                 break;
3202         case 3:
3203                 size[2] = -1.0f;
3204                 setConstraint(&Trans, mati, (CON_AXIS2), "");
3205                 break;
3206         case 4:
3207                 size[0] = -1.0f;
3208                 setLocalConstraint(&Trans, (CON_AXIS0), "");
3209                 break;
3210         case 5:
3211                 size[1] = -1.0f;
3212                 setLocalConstraint(&Trans, (CON_AXIS1), "");
3213                 break;
3214         case 6:
3215                 size[2] = -1.0f;
3216                 setLocalConstraint(&Trans, (CON_AXIS2), "");
3217                 break;
3218         case 7:
3219                 size[0] = -1.0f;
3220                 setConstraint(&Trans, matview, (CON_AXIS0), "");
3221                 break;
3222         case 8:
3223                 size[1] = -1.0f;
3224                 setConstraint(&Trans, matview, (CON_AXIS1), "");
3225                 break;
3226         case 9:
3227                 size[2] = -1.0f;
3228                 setConstraint(&Trans, matview, (CON_AXIS2), "");
3229                 break;
3230         default:
3231                 return;
3232         }
3233
3234         SizeToMat3(size, mat);
3235
3236         if (Trans.con.applySize) {
3237                 Trans.con.applySize(&Trans, NULL, mat);
3238         }
3239
3240         for(i = 0 ; i < Trans.total; i++, td++) {
3241                 if (td->flag & TD_NOACTION)
3242                         break;
3243                 
3244                 ElementResize(&Trans, td, mat);
3245         }
3246
3247         recalcData(&Trans);
3248         
3249         BIF_undo_push("Mirror");
3250
3251         /* free data, reset vars */
3252         postTrans(&Trans);
3253
3254         /* send events out for redraws */
3255         viewRedrawPost(&Trans);
3256 }
3257
3258 /* ************************************ */
3259
3260 void BIF_TransformSetUndo(char *str)
3261 {
3262         Trans.undostr= str;
3263 }
3264
3265
3266 void NDofTransform()
3267 {
3268     float fval[7];
3269     float maxval = 50.0f; // also serves as threshold
3270     int axis = -1;
3271     int mode = 0;
3272     int i;
3273
3274         getndof(fval);
3275
3276         for(i = 0; i < 6; i++)
3277         {
3278                 float val = fabs(fval[i]);
3279                 if (val > maxval)
3280                 {
3281                         axis = i;
3282                         maxval = val;
3283                 }
3284         }
3285         
3286         switch(axis)
3287         {
3288                 case -1:
3289                         /* No proper axis found */
3290                         break;
3291                 case 0:
3292                 case 1:
3293                 case 2:
3294                         mode = TFM_TRANSLATION;
3295                         break;
3296                 case 4:
3297                         mode = TFM_ROTATION;
3298                         break;
3299                 case 3:
3300                 case 5:
3301                         mode = TFM_TRACKBALL;
3302                         break;
3303                 default:
3304                         printf("ndof: what we are doing here ?");
3305         }
3306         
3307         if (mode != 0)
3308         {
3309                 initTransform(mode, CTX_NDOF);
3310                 Transform();
3311         }
3312 }