new round of warning fixes. we are now down to 24 with Xcode on blender
[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 <string.h>
35 #include <math.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifndef WIN32
42 #include <unistd.h>
43 #else
44 #include <io.h>
45 #endif
46
47 #include "MEM_guardedalloc.h"
48
49 #include "DNA_action_types.h"
50 #include "DNA_armature_types.h"
51 #include "DNA_camera_types.h"
52 #include "DNA_curve_types.h"
53 #include "DNA_effect_types.h"
54 #include "DNA_ika_types.h"
55 #include "DNA_image_types.h"
56 #include "DNA_ipo_types.h"
57 #include "DNA_key_types.h"
58 #include "DNA_lamp_types.h"
59 #include "DNA_lattice_types.h"
60 #include "DNA_mesh_types.h"
61 #include "DNA_meshdata_types.h"
62 #include "DNA_meta_types.h"
63 #include "DNA_object_types.h"
64 #include "DNA_scene_types.h"
65 #include "DNA_screen_types.h"
66 #include "DNA_texture_types.h"
67 #include "DNA_view3d_types.h"
68 #include "DNA_world_types.h"
69 #include "DNA_userdef_types.h"
70 #include "DNA_property_types.h"
71 #include "DNA_vfont_types.h"
72 #include "DNA_constraint_types.h"
73
74 #include "BIF_editview.h"
75 #include "BIF_resources.h"
76 #include "BIF_mywindow.h"
77 #include "BIF_gl.h"
78 #include "BIF_editlattice.h"
79 #include "BIF_editarmature.h"
80 #include "BIF_editmesh.h"
81 #include "BIF_screen.h"
82 #include "BIF_space.h"
83 #include "BIF_toets.h"
84 #include "BIF_toolbox.h"
85
86 #include "BKE_action.h"
87 #include "BKE_armature.h"
88 #include "BKE_blender.h"
89 #include "BKE_curve.h"
90 #include "BKE_displist.h"
91 #include "BKE_effect.h"
92 #include "BKE_global.h"
93 #include "BKE_ipo.h"
94 #include "BKE_lattice.h"
95 #include "BKE_mball.h"
96 #include "BKE_object.h"
97 #include "BKE_utildefines.h"
98
99 #include "BSE_view.h"
100 #include "BSE_edit.h"
101 #include "BSE_editipo.h"
102 #include "BSE_editipo_types.h"
103 #include "BDR_editobject.h"             // reset_slowparents()
104
105 #include "BLI_arithb.h"
106 #include "BLI_editVert.h"
107 #include "BLI_ghash.h"
108
109 #include "PIL_time.h"
110
111 #include "blendef.h"
112
113 #include "mydevice.h"
114
115 extern ListBase editNurb;
116 extern ListBase editelems;
117
118 extern void helpline(float *vec);
119
120
121 #include "transform.h"
122
123 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING  */
124 TransInfo Trans = {TFM_INIT, 0};        // enforce init on first usage
125 int     LastMode = TFM_TRANSLATION;
126
127 /* ************************** TRANSFORMATIONS **************************** */
128
129 static void view_editmove(unsigned short event)
130 {
131         /* Regular:   Zoom in */
132         /* Shift:     Scroll up */
133         /* Ctrl:      Scroll right */
134         /* Alt-Shift: Rotate up */
135         /* Alt-Ctrl:  Rotate right */
136         
137         switch(event) {
138                 case WHEELUPMOUSE:
139                         
140                         if( G.qual & LR_SHIFTKEY ) {
141                                 if( G.qual & LR_ALTKEY ) { 
142                                         G.qual &= ~LR_SHIFTKEY;
143                                         persptoetsen(PAD2);
144                                         G.qual |= LR_SHIFTKEY;
145                                 } else {
146                                         persptoetsen(PAD2);
147                                 }
148                         } else if( G.qual & LR_CTRLKEY ) {
149                                 if( G.qual & LR_ALTKEY ) { 
150                                         G.qual &= ~LR_CTRLKEY;
151                                         persptoetsen(PAD4);
152                                         G.qual |= LR_CTRLKEY;
153                                 } else {
154                                         persptoetsen(PAD4);
155                                 }
156                         } else if(U.uiflag & USER_WHEELZOOMDIR) 
157                                 persptoetsen(PADMINUS);
158                         else
159                                 persptoetsen(PADPLUSKEY);
160                         
161                         break;
162                 case WHEELDOWNMOUSE:
163                         if( G.qual & LR_SHIFTKEY ) {
164                                 if( G.qual & LR_ALTKEY ) { 
165                                         G.qual &= ~LR_SHIFTKEY;
166                                         persptoetsen(PAD8);
167                                         G.qual |= LR_SHIFTKEY;
168                                 } else {
169                                         persptoetsen(PAD8);
170                                 }
171                         } else if( G.qual & LR_CTRLKEY ) {
172                                 if( G.qual & LR_ALTKEY ) { 
173                                         G.qual &= ~LR_CTRLKEY;
174                                         persptoetsen(PAD6);
175                                         G.qual |= LR_CTRLKEY;
176                                 } else {
177                                         persptoetsen(PAD6);
178                                 }
179                         } else if(U.uiflag & USER_WHEELZOOMDIR) 
180                                 persptoetsen(PADPLUSKEY);
181                         else
182                                 persptoetsen(PADMINUS);
183                         
184                         break;
185         }
186 }
187
188 static char *transform_to_undostr(TransInfo *t)
189 {
190         switch (t->mode) {
191                 case TFM_TRANSLATION:
192                         return "Translate";
193                 case TFM_ROTATION:
194                         return "Rotate";
195                 case TFM_RESIZE:
196                         return "Scale";
197                 case TFM_TOSPHERE:
198                         return "To Sphere";
199                 case TFM_SHEAR:
200                         return "Shear";
201                 case TFM_WARP:
202                         return "Warp";
203                 case TFM_SHRINKFATTEN:
204                         return "Shrink/Fatten";
205                 case TFM_TILT:
206                         return "Tilt";
207                 case TFM_TRACKBALL:
208                         return "Trackball";
209                 case TFM_PUSHPULL:
210                         return "Push/Pull";
211                 case TFM_CREASE:
212                         return "Crease";
213         }
214         return "Transform";
215 }
216
217 /* ************************************************* */
218
219 void checkFirstTime() {
220         if(Trans.mode==TFM_INIT)
221                 memset(&Trans, 0, sizeof(TransInfo));
222 }
223
224 static void transformEvent(unsigned short event, short val) {
225         float mati[3][3];
226         char cmode = constraintModeToChar(&Trans);
227         Mat3One(mati);
228         
229
230         if (val) {
231                 switch (event){
232                 /* enforce redraw of transform when modifiers are used */
233                 case LEFTCTRLKEY:
234                 case RIGHTCTRLKEY:
235                         Trans.redraw = 1;
236                         break;
237                 case LEFTSHIFTKEY:
238                 case RIGHTSHIFTKEY:
239                         /* shift is modifier for higher resolution transform, works nice to store this mouse position */
240                         getmouseco_areawin(Trans.shiftmval);
241                         Trans.flag |= T_SHIFT_MOD;
242                         Trans.redraw = 1;
243                         break;
244                         
245                 case MIDDLEMOUSE:
246                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
247                                 /* exception for switching to dolly, or trackball, in camera view */
248                                 if (Trans.flag & T_CAMERA) {
249                                         if (Trans.mode==TFM_TRANSLATION)
250                                                 setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
251                                         else if (Trans.mode==TFM_ROTATION) {
252                                                 restoreTransObjects(&Trans);
253                                                 initTransModeFlags(&Trans, TFM_TRACKBALL);
254                                                 initTrackball(&Trans);
255                                         }
256                                 }
257                                 else {
258                                         Trans.flag |= T_MMB_PRESSED;
259                                         if (Trans.con.mode & CON_APPLY) {
260                                                 stopConstraint(&Trans);
261                                         }
262                                         else {
263                                                 initSelectConstraint(&Trans, mati);
264                                                 postSelectConstraint(&Trans);
265                                         }
266                                 }
267                                 Trans.redraw = 1;
268                         }
269                         break;
270                 case ESCKEY:
271                 case RIGHTMOUSE:
272                         Trans.state = TRANS_CANCEL;
273                         break;
274                 case LEFTMOUSE:
275                 case SPACEKEY:
276                 case PADENTER:
277                 case RETKEY:
278                         Trans.state = TRANS_CONFIRM;
279                         break;
280                 case GKEY:
281                         restoreTransObjects(&Trans);
282                         initTransModeFlags(&Trans, TFM_TRANSLATION);
283                         initTranslation(&Trans);
284                         Trans.redraw = 1;
285                         break;
286                 case SKEY:
287                         restoreTransObjects(&Trans);
288                         initTransModeFlags(&Trans, TFM_RESIZE);
289                         initResize(&Trans);
290                         Trans.redraw = 1;
291                         break;
292                 case RKEY:
293                         if (Trans.mode == TFM_ROTATION) {
294                                 restoreTransObjects(&Trans);
295                                 initTransModeFlags(&Trans, TFM_TRACKBALL);
296                                 initTrackball(&Trans);
297                         }
298                         else {
299                                 restoreTransObjects(&Trans);
300                                 initTransModeFlags(&Trans, TFM_ROTATION);
301                                 initRotation(&Trans);
302                         }
303                         Trans.redraw = 1;
304                         break;
305                 case CKEY:
306                         if (G.qual & LR_ALTKEY) {
307                                 Trans.flag ^= T_PROP_CONNECTED;
308                                 sort_trans_data_dist(&Trans);
309                                 calculatePropRatio(&Trans);
310                                 Trans.redraw= 1;
311                         }
312                         else {
313                                 stopConstraint(&Trans);
314                                 Trans.redraw = 1;
315                         }
316                         break;
317                 case XKEY:
318                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
319                                 if (cmode == 'X') {
320                                         if (Trans.con.mode & CON_LOCAL) {
321                                                 stopConstraint(&Trans);
322                                         }
323                                         else {
324                                                 if (G.qual == 0)
325                                                         setLocalConstraint(&Trans, (CON_AXIS0), "along local X");
326                                                 else if (G.qual == LR_SHIFTKEY)
327                                                         setLocalConstraint(&Trans, (CON_AXIS1|CON_AXIS2), "locking local X");
328                                         }
329                                 }
330                                 else {
331                                         if (G.qual == 0)
332                                                 setConstraint(&Trans, mati, (CON_AXIS0), "along global X");
333                                         else if (G.qual == LR_SHIFTKEY)
334                                                 setConstraint(&Trans, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
335                                 }
336                                 Trans.redraw = 1;
337                         }
338                         break;
339                 case YKEY:
340                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
341                                 if (cmode == 'Y') {
342                                         if (Trans.con.mode & CON_LOCAL) {
343                                                 stopConstraint(&Trans);
344                                         }
345                                         else {
346                                                 if (G.qual == 0)
347                                                         setLocalConstraint(&Trans, (CON_AXIS1), "along local Y");
348                                                 else if (G.qual == LR_SHIFTKEY)
349                                                         setLocalConstraint(&Trans, (CON_AXIS0|CON_AXIS2), "locking local Y");
350                                         }
351                                 }
352                                 else {
353                                         if (G.qual == 0)
354                                                 setConstraint(&Trans, mati, (CON_AXIS1), "along global Y");
355                                         else if (G.qual == LR_SHIFTKEY)
356                                                 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS2), "locking global Y");
357                                 }
358                                 Trans.redraw = 1;
359                         }
360                         break;
361                 case ZKEY:
362                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
363                                 if (cmode == 'Z') {
364                                         if (Trans.con.mode & CON_LOCAL) {
365                                                 stopConstraint(&Trans);
366                                         }
367                                         else {
368                                                 if (G.qual == 0)
369                                                         setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
370                                                 else if (G.qual == LR_SHIFTKEY)
371                                                         setLocalConstraint(&Trans, (CON_AXIS0|CON_AXIS1), "locking local Z");
372                                         }
373                                 }
374                                 else {
375                                         if (G.qual == 0)
376                                                 setConstraint(&Trans, mati, (CON_AXIS2), "along global Z");
377                                         else if (G.qual == LR_SHIFTKEY)
378                                                 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
379                                 }
380                                 Trans.redraw = 1;
381                         }
382                         break;
383                 case OKEY:
384                         if (Trans.flag & T_PROP_EDIT && G.qual==LR_SHIFTKEY) {
385                                 G.scene->prop_mode = (G.scene->prop_mode+1)%6;
386                                 calculatePropRatio(&Trans);
387                                 Trans.redraw= 1;
388                         }
389                         break;
390                 case WHEELDOWNMOUSE:
391                 case PADPLUSKEY:
392                         if(Trans.flag & T_PROP_EDIT) {
393                                 Trans.propsize*= 1.1f;
394                                 calculatePropRatio(&Trans);
395                         }
396                         else view_editmove(event);
397                         Trans.redraw= 1;
398                         break;
399                 case WHEELUPMOUSE:
400                 case PADMINUS:
401                         if(Trans.flag & T_PROP_EDIT) {
402                                 Trans.propsize*= 0.90909090f;
403                                 calculatePropRatio(&Trans);
404                         }
405                         else view_editmove(event);
406                         Trans.redraw= 1;
407                         break;
408                 }
409                 Trans.redraw |= handleNumInput(&(Trans.num), event);
410                 arrows_move_cursor(event);
411         }
412         else {
413                 switch (event){
414                 /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still 
415                    after releasing modifer key */
416                 case MIDDLEMOUSE:
417                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
418                                 Trans.flag &= ~T_MMB_PRESSED;
419                                 postSelectConstraint(&Trans);
420                                 Trans.redraw = 1;
421                         }
422                         break;
423                 case LEFTMOUSE:
424                 case RIGHTMOUSE:
425                         /* commented out, doesn't work for actions started with menu */
426                         // Trans.state = TRANS_CONFIRM;
427                         break;
428                 case LEFTSHIFTKEY:
429                 case RIGHTSHIFTKEY:
430                         /* shift is modifier for higher resolution transform */
431                         Trans.flag &= ~T_SHIFT_MOD;
432                         break;
433                 }
434         }
435 }
436
437 void initTransform(int mode, int context) {
438         /* added initialize, for external calls to set stuff in TransInfo, like undo string */
439         checkFirstTime();
440
441         Trans.state = TRANS_RUNNING;
442
443         /* stupid PET initialisation code */
444         /* START */
445         if (Trans.propsize == 0.0f) {
446                 Trans.propsize = 1.0;
447         }
448         /* END */
449
450         if (mode == TFM_REPEAT) {
451                 mode = LastMode;
452         }
453         else {
454                 LastMode = mode;
455         }
456
457         Trans.context = context;
458
459         initTrans(&Trans);                                      // internal data, mouse, vectors
460
461         initTransModeFlags(&Trans, mode);       // modal settings in struct Trans
462
463         createTransData(&Trans);                        // make TransData structs from selection
464
465         if (Trans.total == 0) {
466                 postTrans(&Trans);
467                 return;
468         }
469
470         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
471         /* EVIL2: we gave as argument also texture space context bit... was cleared */
472         mode= Trans.mode;
473         
474         calculatePropRatio(&Trans);
475         calculateCenter(&Trans);
476
477         switch (mode) {
478         case TFM_TRANSLATION:
479                 initTranslation(&Trans);
480                 break;
481         case TFM_ROTATION:
482                 initRotation(&Trans);
483                 break;
484         case TFM_RESIZE:
485                 initResize(&Trans);
486                 break;
487         case TFM_TOSPHERE:
488                 initToSphere(&Trans);
489                 break;
490         case TFM_SHEAR:
491                 initShear(&Trans);
492                 break;
493         case TFM_WARP:
494                 initWarp(&Trans);
495                 break;
496         case TFM_SHRINKFATTEN:
497                 initShrinkFatten(&Trans);
498                 break;
499         case TFM_TILT:
500                 initTilt(&Trans);
501                 break;
502         case TFM_TRACKBALL:
503                 initTrackball(&Trans);
504                 break;
505         case TFM_PUSHPULL:
506                 initPushPull(&Trans);
507                 break;
508         case TFM_CREASE:
509                 initCrease(&Trans);
510                 break;
511         }
512
513         initConstraint(&Trans);
514 }
515
516 void Transform() 
517 {
518         float mati[3][3];
519         short pmval[2] = {0, 0}, mval[2], val;
520         unsigned short event;
521
522         if(Trans.total==0) return;      // added, can happen now! (ton)
523         
524         Mat3One(mati);
525
526         // Emptying event queue
527         while( qtest() ) {
528                 event= extern_qread(&val);
529         }
530
531         Trans.redraw = 1;
532
533         while (Trans.state == TRANS_RUNNING) {
534
535                 getmouseco_areawin(mval);
536                 
537                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
538                         if (Trans.flag & T_MMB_PRESSED) {
539                                 initSelectConstraint(&Trans, mati);
540                         }
541                         Trans.redraw = 1;
542                 }
543                 if (Trans.redraw) {
544                         pmval[0] = mval[0];
545                         pmval[1] = mval[1];
546
547                         selectConstraint(&Trans);
548                         if (Trans.transform) {
549                                 Trans.transform(&Trans, mval);
550                         }
551                         Trans.redraw = 0;
552                 }
553                 
554                 /* essential for idling subloop */
555                 if( qtest()==0) PIL_sleep_ms(2);
556
557                 while( qtest() ) {
558                         event= extern_qread(&val);
559                         transformEvent(event, val);
560                 }
561         }
562         
563         
564         /* handle restoring objects and Undo */
565         if(Trans.state == TRANS_CANCEL) {
566                 restoreTransObjects(&Trans);
567                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
568         }
569         else {
570                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
571                 else BIF_undo_push(transform_to_undostr(&Trans));
572         }
573         Trans.undostr= NULL;
574         
575         /* free data, reset vars */
576         postTrans(&Trans);
577         
578         /* mess from old transform, just for now (ton) */
579         {
580                 char cmode='g';
581                 
582                 if(Trans.mode==TFM_RESIZE) cmode= 's';
583                 else if(Trans.mode==TFM_ROTATION) cmode= 'r';
584                 /* aftertrans does displists, ipos and action channels */
585                 /* 7 = keyflags, meaning do loc/rot/scale ipos. Not sure if I like the old method to detect what changed (ton) */
586                 special_aftertrans_update(cmode, 0, (short)(Trans.state == TRANS_CANCEL), 7);
587                 
588                 if(G.obedit==NULL && G.obpose==NULL)
589                         clear_trans_object_base_flags();
590         }
591         
592         /* send events out for redraws */
593         allqueue(REDRAWVIEW3D, 0);
594         allqueue(REDRAWBUTSOBJECT, 0);
595         scrarea_queue_headredraw(curarea);
596 }
597
598 void ManipulatorTransform(int mode) 
599 {
600         int mouse_moved = 0;
601         short pmval[2] = {0, 0}, mval[2], val;
602         unsigned short event;
603
604         Trans.state = TRANS_RUNNING;
605
606         /* stupid PET initialisation code */
607         /* START */
608         if (Trans.propsize == 0.0f) {
609                 Trans.propsize = 1.0;
610         }
611         /* END */
612
613         Trans.context = CTX_NONE;
614
615         initTrans(&Trans);                                      // internal data, mouse, vectors
616
617         initTransModeFlags(&Trans, mode);       // modal settings in struct Trans
618
619         G.moving |= G_TRANSFORM_MANIP;          // signal to draw manipuls while transform
620         createTransData(&Trans);                        // make TransData structs from selection
621
622         if (Trans.total == 0)
623                 return;
624
625         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
626         /* EVIL2: we gave as argument also texture space context bit... was cleared */
627         mode= Trans.mode;
628         
629         calculatePropRatio(&Trans);
630         calculateCenter(&Trans);
631
632         switch (mode) {
633         case TFM_TRANSLATION:
634                 initTranslation(&Trans);
635                 break;
636         case TFM_ROTATION:
637                 initRotation(&Trans);
638                 break;
639         case TFM_RESIZE:
640                 initResize(&Trans);
641                 break;
642         case TFM_TRACKBALL:
643                 initTrackball(&Trans);
644                 break;
645         }
646
647         initConstraint(&Trans);
648         
649         Trans.flag |= T_USES_MANIPULATOR;
650         Trans.redraw = 1;
651
652         while (Trans.state == TRANS_RUNNING) {
653                 
654                 getmouseco_areawin(mval);
655                 
656                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
657                         Trans.redraw = 1;
658                 }
659                 if (Trans.redraw) {
660                         pmval[0] = mval[0];
661                         pmval[1] = mval[1];
662
663                         //selectConstraint(&Trans);  needed?
664                         if (Trans.transform) {
665                                 Trans.transform(&Trans, mval);
666                         }
667                         Trans.redraw = 0;
668                 }
669                 
670                 /* essential for idling subloop */
671                 if( qtest()==0) PIL_sleep_ms(2);
672
673                 while( qtest() ) {
674                         event= extern_qread(&val);
675
676                         switch (event){
677                         case MOUSEX:
678                         case MOUSEY:
679                                 mouse_moved = 1;
680                                 break;
681                         /* enforce redraw of transform when modifiers are used */
682                         case LEFTCTRLKEY:
683                         case RIGHTCTRLKEY:
684                                 if(val) Trans.redraw = 1;
685                                 break;
686                         case LEFTSHIFTKEY:
687                         case RIGHTSHIFTKEY:
688                                 /* shift is modifier for higher resolution transform, works nice to store this mouse position */
689                                 if(val) {
690                                         getmouseco_areawin(Trans.shiftmval);
691                                         Trans.flag |= T_SHIFT_MOD;
692                                         Trans.redraw = 1;
693                                 }
694                                 else Trans.flag &= ~T_SHIFT_MOD; 
695                                 break;
696                                 
697                         case ESCKEY:
698                         case RIGHTMOUSE:
699                                 Trans.state = TRANS_CANCEL;
700                                 break;
701                         case LEFTMOUSE:
702                                 if(mouse_moved==0 && val==0) break;
703                                 // else we pass on event to next, which cancels
704                         case SPACEKEY:
705                         case PADENTER:
706                         case RETKEY:
707                                 Trans.state = TRANS_CONFIRM;
708                                 break;
709                         }
710                         if(val) {
711                                 switch(event) {
712                                 case WHEELDOWNMOUSE:
713                                 case PADPLUSKEY:
714                                         if(Trans.flag & T_PROP_EDIT) {
715                                                 Trans.propsize*= 1.1f;
716                                                 calculatePropRatio(&Trans);
717                                                 Trans.redraw= 1;
718                                         }
719                                         break;
720                                 case WHEELUPMOUSE:
721                                 case PADMINUS:
722                                         if(Trans.flag & T_PROP_EDIT) {
723                                                 Trans.propsize*= 0.90909090f;
724                                                 calculatePropRatio(&Trans);
725                                                 Trans.redraw= 1;
726                                         }
727                                         break;
728                                 }                       
729                         }
730                 }
731         }
732         
733         if(Trans.state == TRANS_CANCEL) {
734                 restoreTransObjects(&Trans);
735         }
736         else {
737                 BIF_undo_push(transform_to_undostr(&Trans));
738         }
739         
740         /* free data, reset vars */
741         postTrans(&Trans);
742         
743         /* mess from old transform, just for now (ton) */
744         {
745                 char cmode='g';
746                 
747                 if(mode==TFM_RESIZE) cmode= 's';
748                 else if(mode==TFM_ROTATION) cmode= 'r';
749                 /* aftertrans does displists, ipos and action channels */
750                 /* 7 = keyflags, meaning do loc/rot/scale ipos. Not sure if I like the old method to detect what changed (ton) */
751                 special_aftertrans_update(cmode, 0, (short)(Trans.state == TRANS_CANCEL), 7);
752                 
753                 if(G.obedit==NULL && G.obpose==NULL)
754                         clear_trans_object_base_flags();
755         }
756         
757         /* send events out for redraws */
758         allqueue(REDRAWVIEW3D, 0);
759         allqueue(REDRAWBUTSOBJECT, 0);
760         scrarea_queue_headredraw(curarea);
761 }
762
763
764
765 /* ************************** WRAP *************************** */
766
767 /* warp is done fully in view space */
768 void initWarp(TransInfo *t) 
769 {
770         float max[3], min[3];
771         int i;
772         
773         calculateCenterCursor(t);
774         t->idx_max = 0;
775         t->num.idx_max = 0;
776         t->transform = Warp;
777         t->snap[0] = 0.0f;
778         t->snap[1] = 5.0f;
779         t->snap[2] = 1.0f;
780         
781         t->fac = (float)(t->center2d[0] - t->imval[0]);
782         
783         /* we need min/max in view space */
784         for(i = 0; i < t->total; i++) {
785                 float center[3];
786                 VECCOPY(center, t->data[i].center);
787                 Mat3MulVecfl(t->data[i].mtx, center);
788                 Mat4MulVecfl(G.vd->viewmat, center);
789                 VecSubf(center, center, G.vd->viewmat[3]);
790                 if (i)
791                         MinMax3(min, max, center);
792                 else {
793                         VECCOPY(max, center);
794                         VECCOPY(min, center);
795                 }
796         }
797
798         t->center[0]= (min[0]+max[0])/2.0f;
799         t->center[1]= (min[1]+max[1])/2.0f;
800         t->center[2]= (min[2]+max[2])/2.0f;
801         
802         t->val= (max[0]-min[0])/2.0f;   // t->val is free variable
803 }
804
805
806 int Warp(TransInfo *t, short mval[2])
807 {
808         TransData *td = t->data;
809         float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
810         int i;
811         char str[50];
812         
813         curs= give_cursor();
814         /*
815          * gcursor is the one used for helpline.
816          * It has to be in the same space as the drawing loop
817          * (that means it needs to be in the object's space when in edit mode and
818          *  in global space in object mode)
819          *
820          * cursor is used for calculations.
821          * It needs to be in view space, but we need to take object's offset
822          * into account if in Edit mode.
823          */
824         VECCOPY(cursor, curs);
825         VECCOPY(gcursor, cursor);       
826         if (t->flag & T_EDIT) {
827                 VecSubf(cursor, cursor, G.obedit->obmat[3]);
828                 VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
829                 Mat3MulVecfl(t->data->smtx, gcursor);
830         }
831         Mat4MulVecfl(G.vd->viewmat, cursor);
832         VecSubf(cursor, cursor, G.vd->viewmat[3]);
833
834         // amount of degrees for warp, 450 = allow to create 360 degree warp
835         circumfac= 450.0f*(mval[1] - t->imval[1]) / (float)(curarea->winy);
836         circumfac+= 90.0f;
837
838         snapGrid(t, &circumfac);
839         applyNumInput(&t->num, &circumfac);
840         
841         /* header print for NumInput */
842         if (hasNumInput(&t->num)) {
843                 char c[20];
844                 
845                 outputNumInput(&(t->num), c);
846                 
847                 sprintf(str, "Warp: %s", c);
848         }
849         else {
850                 /* default header print */
851                 sprintf(str, "Warp: %.3f", circumfac);
852         }
853         
854         circumfac*= (float)(-M_PI/360.0);
855         
856         for(i = 0 ; i < t->total; i++, td++) {
857                 float loc[3];
858                 if (td->flag & TD_NOACTION)
859                         break;
860
861                 /* translate point to centre, rotate in such a way that outline==distance */
862                 
863                 VECCOPY(vec, td->iloc);
864                 Mat3MulVecfl(td->mtx, vec);
865                 Mat4MulVecfl(G.vd->viewmat, vec);
866                 VecSubf(vec, vec, G.vd->viewmat[3]);
867                 
868                 dist= vec[0]-cursor[0];
869
870                 phi0= (circumfac*dist/t->val);  // t->val is X dimension projected boundbox
871                 
872                 vec[1]= (vec[1]-cursor[1]);
873                 
874                 co= (float)cos(phi0);
875                 si= (float)sin(phi0);
876                 loc[0]= -si*vec[1]+cursor[0];
877                 loc[1]= co*vec[1]+cursor[1];
878                 loc[2]= vec[2];
879                 
880                 Mat4MulVecfl(G.vd->viewinv, loc);
881                 VecSubf(loc, loc, G.vd->viewinv[3]);
882                 Mat3MulVecfl(td->smtx, loc);
883
884                 VecSubf(loc, loc, td->iloc);
885                 VecMulf(loc, td->factor);
886                 VecAddf(td->loc, td->iloc, loc);
887         }
888
889         recalcData(t);
890         
891         headerprint(str);
892         
893         force_draw(0);
894         
895         helpline(gcursor);
896         
897         return 1;
898 }
899
900 /* ************************** SHEAR *************************** */
901
902 void initShear(TransInfo *t) 
903 {
904         t->idx_max = 0;
905         t->num.idx_max = 0;
906         t->snap[0] = 0.0f;
907         t->snap[1] = 0.1f;
908         t->snap[2] = t->snap[1] * 0.1f;
909         t->transform = Shear;
910         t->fac = (float)(t->center2d[0] - t->imval[0]);
911 }
912
913 int Shear(TransInfo *t, short mval[2]) 
914 {
915         TransData *td = t->data;
916         float vec[3];
917         float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
918         float value;
919         int i;
920         char str[50];
921
922         Mat3CpyMat4(persmat, G.vd->viewmat);
923         Mat3Inv(persinv, persmat);
924
925         value = -0.005f * ((float)(t->center2d[0] - mval[0]) - t->fac);
926
927         snapGrid(t, &value);
928
929         applyNumInput(&t->num, &value);
930
931         /* header print for NumInput */
932         if (hasNumInput(&t->num)) {
933                 char c[20];
934
935                 outputNumInput(&(t->num), c);
936
937                 sprintf(str, "Shear: %s %s", c, t->proptext);
938         }
939         else {
940                 /* default header print */
941                 sprintf(str, "Shear: %.3f %s", value, t->proptext);
942         }
943         
944         Mat3One(smat);
945         smat[1][0] = value;
946         Mat3MulMat3(tmat, smat, persmat);
947         Mat3MulMat3(totmat, persinv, tmat);
948         
949         for(i = 0 ; i < t->total; i++, td++) {
950                 if (td->flag & TD_NOACTION)
951                         break;
952
953                 if (G.obedit) {
954                         float mat3[3][3];
955                         Mat3MulMat3(mat3, totmat, td->mtx);
956                         Mat3MulMat3(tmat, td->smtx, mat3);
957                 }
958                 else {
959                         Mat3CpyMat3(tmat, totmat);
960                 }
961                 VecSubf(vec, td->center, t->center);
962
963                 Mat3MulVecfl(tmat, vec);
964
965                 VecAddf(vec, vec, t->center);
966                 VecSubf(vec, vec, td->center);
967
968                 VecMulf(vec, td->factor);
969
970                 VecAddf(td->loc, td->iloc, vec);
971         }
972
973         recalcData(t);
974
975         headerprint(str);
976
977         force_draw(0);
978
979         helpline (t->center);
980
981         return 1;
982 }
983
984 /* ************************** RESIZE *************************** */
985
986 void initResize(TransInfo *t) 
987 {
988         t->fac = (float)sqrt( (float)
989                 (
990                         (t->center2d[1] - t->imval[1])*(t->center2d[1] - t->imval[1])
991                 +
992                         (t->center2d[0] - t->imval[0])*(t->center2d[0] - t->imval[0])
993                 ) );
994
995         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
996         
997         t->idx_max = 2;
998         t->num.idx_max = 2;
999         t->snap[0] = 0.0f;
1000         t->snap[1] = 0.1f;
1001         t->snap[2] = t->snap[1] * 0.1f;
1002         t->transform = Resize;
1003 }
1004
1005 static void headerResize(TransInfo *t, float vec[3], char *str) {
1006         char tvec[60];
1007         if (hasNumInput(&t->num)) {
1008                 outputNumInput(&(t->num), tvec);
1009         }
1010         else {
1011                 sprintf(&tvec[0], "%.4f", vec[0]);
1012                 sprintf(&tvec[20], "%.4f", vec[1]);
1013                 sprintf(&tvec[40], "%.4f", vec[2]);
1014         }
1015
1016         if (t->con.mode & CON_APPLY) {
1017                 switch(t->num.idx_max) {
1018                 case 0:
1019                         sprintf(str, "Size: %s%s %s", &tvec[0], t->con.text, t->proptext);
1020                         break;
1021                 case 1:
1022                         sprintf(str, "Size: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1023                         break;
1024                 case 2:
1025                         sprintf(str, "Size: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1026                 }
1027         }
1028         else {
1029                 sprintf(str, "Size X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1030         }
1031 }
1032
1033 #define SIGN(a)         (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3)
1034 #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)
1035
1036 /* smat is reference matrix, only scaled */
1037 static void TransMat3ToSize( float mat[][3], float smat[][3], float *size)
1038 {
1039         float vec[3];
1040         
1041         VecCopyf(vec, mat[0]);
1042         size[0]= Normalise(vec);
1043         VecCopyf(vec, mat[1]);
1044         size[1]= Normalise(vec);
1045         VecCopyf(vec, mat[2]);
1046         size[2]= Normalise(vec);
1047         
1048         /* first tried with dotproduct... but the sign flip is crucial */
1049         if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0]; 
1050         if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1]; 
1051         if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2]; 
1052 }
1053
1054
1055 static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
1056         float tmat[3][3], smat[3][3], center[3];
1057         float vec[3];
1058
1059         if (t->flag & T_EDIT) {
1060                 Mat3MulMat3(smat, mat, td->mtx);
1061                 Mat3MulMat3(tmat, td->smtx, smat);
1062         }
1063         else {
1064                 Mat3CpyMat3(tmat, mat);
1065         }
1066
1067         if (t->con.applySize) {
1068                 t->con.applySize(t, td, tmat);
1069         }
1070
1071         /* local constraint shouldn't alter center */
1072         if (G.vd->around == V3D_LOCAL) {
1073                 if (t->flag & T_OBJECT) {
1074                         VECCOPY(center, td->center);    // not supported in editmode yet
1075                 }
1076                 else {
1077                         VECCOPY(center, t->center);             // Editmode needs to define center too...
1078                 }
1079         }
1080         else {
1081                 VECCOPY(center, t->center);
1082         }
1083
1084         if (td->ext) {
1085                 float fsize[3];
1086
1087                 if (t->flag & T_OBJECT) {
1088                         float obsizemat[3][3];
1089                         // Reorient the size mat to fit the oriented object.
1090                         Mat3MulMat3(obsizemat, tmat, td->axismtx);
1091                         //printmatrix3("obsizemat", obsizemat);
1092                         TransMat3ToSize(obsizemat, td->axismtx, fsize);
1093                         //printvecf("fsize", fsize);
1094                 }
1095                 else {
1096                         Mat3ToSize(tmat, fsize);
1097                 }
1098                 
1099                 if ((G.vd->flag & V3D_ALIGN)==0) {      // align mode doesn't rotate objects itself
1100                         /* handle ipokeys? */
1101                         if(td->tdi) {
1102                                 TransDataIpokey *tdi= td->tdi;
1103                                 /* calculate delta size (equal for size and dsize) */
1104                                 
1105                                 vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
1106                                 vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
1107                                 vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
1108                                 
1109                                 add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
1110                                 add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
1111                                 add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
1112                                 
1113                         }
1114                         else if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){
1115                                 /* scale val and reset size */
1116                                 *td->val = td->ival * fsize[0] * td->factor;
1117
1118                                 td->ext->size[0] = td->ext->isize[0];
1119                                 td->ext->size[1] = td->ext->isize[1];
1120                                 td->ext->size[2] = td->ext->isize[2];
1121                         }
1122                         else {
1123                                 /* Reset val if SINGLESIZE but using a constraint */
1124                                 if (td->flag & TD_SINGLESIZE)
1125                                         *td->val = td->ival;
1126
1127                                 td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
1128                                 td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
1129                                 td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
1130                         }
1131                 }
1132         }
1133         /* For individual element center, Editmode need to use iloc */
1134         if (t->flag & T_EDIT)
1135                 VecSubf(vec, td->iloc, center);
1136         else
1137                 VecSubf(vec, td->center, center);
1138
1139         Mat3MulVecfl(tmat, vec);
1140
1141         VecAddf(vec, vec, center);
1142         if (t->flag & T_EDIT)
1143                 VecSubf(vec, vec, td->iloc);
1144         else
1145                 VecSubf(vec, vec, td->center);
1146
1147         VecMulf(vec, td->factor);
1148
1149         if (t->flag & T_OBJECT) {
1150                 Mat3MulVecfl(td->smtx, vec);
1151         }
1152
1153         if(td->tdi) {
1154                 TransDataIpokey *tdi= td->tdi;
1155                 add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
1156                 add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
1157                 add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
1158         }
1159         else VecAddf(td->loc, td->iloc, vec);
1160 }
1161
1162 int Resize(TransInfo *t, short mval[2]) 
1163 {
1164         TransData *td = t->data;
1165         float size[3], mat[3][3];
1166         float ratio;
1167         int i;
1168         char str[50];
1169
1170         /* for manipulator, center handle, the scaling can't be done relative to center */
1171         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
1172                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
1173         }
1174         else {
1175                 
1176                 if(t->flag & T_SHIFT_MOD) {
1177                         /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
1178                         float dx= (float)(t->center2d[0] - t->shiftmval[0]);
1179                         float dy= (float)(t->center2d[1] - t->shiftmval[1]);
1180                         ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
1181                         
1182                         dx= (float)(t->center2d[0] - mval[0]);
1183                         dy= (float)(t->center2d[1] - mval[1]);
1184                         ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
1185                         
1186                 }
1187                 else {
1188                         float dx= (float)(t->center2d[0] - mval[0]);
1189                         float dy= (float)(t->center2d[1] - mval[1]);
1190                         ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
1191                 }
1192                 
1193                 /* flip scale, but not for manipulator center handle */
1194                 if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
1195                          (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
1196                                 ratio *= -1.0f;
1197         }
1198         
1199         size[0] = size[1] = size[2] = ratio;
1200
1201         snapGrid(t, size);
1202
1203         if (hasNumInput(&t->num)) {
1204                 applyNumInput(&t->num, size);
1205                 constraintNumInput(t, size);
1206         }
1207
1208         SizeToMat3(size, mat);
1209
1210         if (t->con.applySize) {
1211                 t->con.applySize(t, NULL, mat);
1212         }
1213
1214         Mat3CpyMat3(t->mat, mat);       // used in manipulator
1215         
1216         headerResize(t, size, str);
1217
1218         for(i = 0 ; i < t->total; i++, td++) {
1219                 if (td->flag & TD_NOACTION)
1220                         break;
1221                 
1222                 ElementResize(t, td, mat);
1223         }
1224
1225         recalcData(t);
1226
1227         headerprint(str);
1228
1229         force_draw(0);
1230
1231         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
1232
1233         return 1;
1234 }
1235
1236 /* ************************** TOSPHERE *************************** */
1237
1238 void initToSphere(TransInfo *t) 
1239 {
1240         TransData *td = t->data;
1241         int i;
1242
1243         // Calculate average radius
1244         for(i = 0 ; i < t->total; i++, td++) {
1245                 t->val += VecLenf(t->center, td->iloc);
1246         }
1247
1248         t->val /= (float)t->total;
1249
1250         Trans.fac = (float)sqrt( (float)
1251                 (
1252                         (Trans.center2d[1] - Trans.imval[1])*(Trans.center2d[1] - Trans.imval[1])
1253                 +
1254                         (Trans.center2d[0] - Trans.imval[0])*(Trans.center2d[0] - Trans.imval[0])
1255                 ) );
1256
1257         t->idx_max = 0;
1258         t->num.idx_max = 0;
1259         t->snap[0] = 0.0f;
1260         t->snap[1] = 0.1f;
1261         t->snap[2] = t->snap[1] * 0.1f;
1262         t->transform = ToSphere;
1263 }
1264
1265
1266
1267 int ToSphere(TransInfo *t, short mval[2]) 
1268 {
1269         float vec[3];
1270         float ratio, radius;
1271         int i;
1272         char str[50];
1273         TransData *td = t->data;
1274
1275         ratio = (float)sqrt( (float)
1276                 (
1277                         (t->center2d[1] - mval[1])*(t->center2d[1] - mval[1])
1278                 +
1279                         (t->center2d[0] - mval[0])*(t->center2d[0] - mval[0])
1280                 ) ) / t->fac;
1281
1282         snapGrid(t, &ratio);
1283
1284         applyNumInput(&t->num, &ratio);
1285
1286         if (ratio > 1.0f)
1287                 ratio = 1.0f;
1288
1289         /* header print for NumInput */
1290         if (hasNumInput(&t->num)) {
1291                 char c[20];
1292
1293                 outputNumInput(&(t->num), c);
1294
1295                 sprintf(str, "To Sphere: %s %s", c, t->proptext);
1296         }
1297         else {
1298                 /* default header print */
1299                 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
1300         }
1301         
1302         
1303         for(i = 0 ; i < t->total; i++, td++) {
1304                 float tratio;
1305                 if (td->flag & TD_NOACTION)
1306                         break;
1307
1308                 VecSubf(vec, td->iloc, t->center);
1309
1310                 radius = Normalise(vec);
1311
1312                 tratio = 1.0f - ((1.0f - ratio) * td->factor);
1313
1314                 VecMulf(vec, radius * tratio + t->val * (1.0f - tratio));
1315
1316                 VecAddf(td->loc, t->center, vec);
1317         }
1318
1319         recalcData(t);
1320
1321         headerprint(str);
1322
1323         force_draw(0);
1324
1325         helpline (t->center);
1326
1327         return 1;
1328 }
1329
1330 /* ************************** ROTATION *************************** */
1331
1332
1333 void initRotation(TransInfo *t) 
1334 {
1335         t->idx_max = 0;
1336         t->num.idx_max = 0;
1337         t->snap[0] = 0.0f;
1338         t->snap[1] = (float)((5.0/180)*M_PI);
1339         t->snap[2] = t->snap[1] * 0.2f;
1340         t->fac = 0;
1341         t->transform = Rotation;
1342 }
1343
1344 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
1345         float vec[3], totmat[3][3], smat[3][3];
1346         float eul[3], fmat[3][3], quat[4];
1347
1348         if (t->flag & T_EDIT) {
1349                 Mat3MulMat3(totmat, mat, td->mtx);
1350                 Mat3MulMat3(smat, td->smtx, totmat);
1351                 
1352                 VecSubf(vec, td->iloc, t->center);
1353                 Mat3MulVecfl(smat, vec);
1354                 
1355                 VecAddf(td->loc, vec, t->center);
1356
1357                 if(td->flag & TD_USEQUAT) {
1358                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1359                         Mat3ToQuat(fmat, quat); // Actual transform
1360                         QuatMul(td->ext->quat, quat, td->ext->iquat);
1361                 }
1362         }
1363         else {
1364                 /* translation */
1365                 
1366                 VecSubf(vec, td->center, t->center);
1367                 Mat3MulVecfl(mat, vec);
1368                 VecAddf(vec, vec, t->center);
1369                 /* vec now is the location where the object has to be */
1370                 VecSubf(vec, vec, td->center);
1371                 Mat3MulVecfl(td->smtx, vec);
1372                 
1373                 if(td->tdi) {
1374                         TransDataIpokey *tdi= td->tdi;
1375                         add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
1376                         add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
1377                         add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
1378                 }
1379                 else VecAddf(td->loc, td->iloc, vec);
1380                 
1381                 if(td->flag & TD_USEQUAT) {
1382                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1383                         Mat3ToQuat(fmat, quat); // Actual transform
1384                         QuatMul(td->ext->quat, quat, td->ext->iquat);
1385                 }
1386                 else if ((G.vd->flag & V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
1387                         float obmat[3][3];
1388                         
1389                         /* are there ipo keys? */
1390                         if(td->tdi) {
1391                                 TransDataIpokey *tdi= td->tdi;
1392                                 float rot[3];
1393                                 
1394                                 /* calculate the total rotatation in eulers */
1395                                 VecAddf(eul, td->ext->irot, td->ext->drot);
1396                                 EulToMat3(eul, obmat);
1397                                 /* mat = transform, obmat = object rotation */
1398                                 Mat3MulMat3(fmat, mat, obmat);
1399                                 Mat3ToEul(fmat, eul);
1400                                 compatible_eul(eul, td->ext->irot);
1401                                 
1402                                 /* correct back for delta rot */
1403                                 if(tdi->flag & TOB_IPODROT) {
1404                                         VecSubf(rot, eul, td->ext->irot);
1405                                 }
1406                                 else {
1407                                         VecSubf(rot, eul, td->ext->drot);
1408                                 }
1409                                 
1410                                 VecMulf(rot, (float)(9.0/M_PI_2));
1411                                 VecSubf(rot, rot, tdi->oldrot);
1412                                 
1413                                 add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
1414                                 add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
1415                                 add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
1416                         }
1417                         else {
1418                                 Mat3MulMat3(totmat, mat, td->mtx);
1419                                 Mat3MulMat3(smat, td->smtx, totmat);
1420                                 
1421                                 /* calculate the total rotatation in eulers */
1422                                 VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
1423                                 EulToMat3(eul, obmat);
1424                                 /* mat = transform, obmat = object rotation */
1425                                 Mat3MulMat3(fmat, smat, obmat);
1426                                 Mat3ToEul(fmat, eul);
1427                                 compatible_eul(eul, td->ext->irot);
1428                                 
1429                                 /* correct back for delta rot */
1430                                 VecSubf(eul, eul, td->ext->drot);
1431                                 /* and apply */
1432                                 VECCOPY(td->ext->rot, eul);
1433                         }
1434                 }
1435         }
1436 }
1437
1438 static void applyRotation(TransInfo *t, float angle, float axis[3]) 
1439 {
1440         TransData *td = t->data;
1441         float mat[3][3], center[3];
1442         int i;
1443
1444         /* saving original center */
1445         if (G.vd->around == V3D_LOCAL) {
1446                 VECCOPY(center, t->center);
1447         }
1448
1449         VecRotToMat3(axis, angle, mat);
1450
1451         for(i = 0 ; i < t->total; i++, td++) {
1452
1453                 if (td->flag & TD_NOACTION)
1454                         break;
1455                 
1456                 /* local constraint shouldn't alter center */
1457                 if (G.vd->around == V3D_LOCAL) {
1458                         if (t->flag & T_OBJECT)
1459                                 VECCOPY(t->center, td->center);         // not supported in editmode yet
1460                 }
1461                 
1462                 if (t->con.applyRot) {
1463                         t->con.applyRot(t, td, axis);
1464                         VecRotToMat3(axis, angle * td->factor, mat);
1465                 }
1466                 else if (t->flag & T_PROP_EDIT) {
1467                         VecRotToMat3(axis, angle * td->factor, mat);
1468                 }
1469
1470                 ElementRotation(t, td, mat);
1471         }
1472
1473         /* restoring original center */
1474         if (G.vd->around == V3D_LOCAL) {
1475                 VECCOPY(t->center, center);
1476         }
1477 }
1478
1479 int Rotation(TransInfo *t, short mval[2]) 
1480 {
1481         TransData *td = t->data;
1482         char str[50];
1483
1484         float final;
1485
1486         int dx2 = t->center2d[0] - mval[0];
1487         int dy2 = t->center2d[1] - mval[1];
1488         float B = (float)sqrt(dx2*dx2+dy2*dy2);
1489
1490         int dx1 = t->center2d[0] - t->imval[0];
1491         int dy1 = t->center2d[1] - t->imval[1];
1492         float A = (float)sqrt(dx1*dx1+dy1*dy1);
1493
1494         int dx3 = mval[0] - t->imval[0];
1495         int dy3 = mval[1] - t->imval[1];
1496
1497         float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
1498                 / (2 * (A*B?A*B:1.0f));
1499         /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
1500
1501         float dphi;
1502
1503         float axis[3];
1504         float mat[3][3];
1505
1506         VECCOPY(axis, t->viewinv[2]);
1507         VecMulf(axis, -1.0f);
1508         Normalise(axis);
1509
1510         dphi = saacos(deler);
1511         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
1512
1513         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
1514         else t->fac += dphi;
1515
1516         /*
1517         clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
1518         if (t->fac >= 2 * M_PI)
1519                 t->fac -= 2 * M_PI;
1520         else if (t->fac <= -2 * M_PI)
1521                 t->fac -= -2 * M_PI;
1522         */
1523
1524         final = t->fac;
1525
1526         snapGrid(t, &final);
1527
1528         t->imval[0] = mval[0];
1529         t->imval[1] = mval[1];
1530
1531         if (t->con.applyRot) {
1532                 t->con.applyRot(t, NULL, axis);
1533         }
1534
1535         if (hasNumInput(&t->num)) {
1536                 char c[20];
1537
1538                 applyNumInput(&t->num, &final);
1539
1540                 outputNumInput(&(t->num), c);
1541
1542                 sprintf(str, "Rot: %s %s", &c[0], t->proptext);
1543
1544                 final *= (float)(M_PI / 180.0);
1545         }
1546         else {
1547                 sprintf(str, "Rot: %.2f%s %s", 180.0*final/M_PI, t->con.text, t->proptext);
1548         }
1549
1550         VecRotToMat3(axis, final * td->factor, mat);
1551
1552         t->val = final;                         // used in manipulator
1553         Mat3CpyMat3(t->mat, mat);       // used in manipulator
1554         
1555         applyRotation(t, final, axis);
1556         
1557         recalcData(t);
1558
1559         headerprint(str);
1560
1561         force_draw(0);
1562
1563         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
1564
1565         return 1;
1566 }
1567
1568
1569 /* ************************** TRACKBALL *************************** */
1570
1571 void initTrackball(TransInfo *t) 
1572 {
1573         t->idx_max = 1;
1574         t->num.idx_max = 1;
1575         t->snap[0] = 0.0f;
1576         t->snap[1] = (float)((5.0/180)*M_PI);
1577         t->snap[2] = t->snap[1] * 0.2f;
1578         t->fac = 0;
1579         t->transform = Trackball;
1580 }
1581
1582 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
1583 {
1584         TransData *td = t->data;
1585         float mat[3][3], smat[3][3], totmat[3][3];
1586         int i;
1587
1588         VecRotToMat3(axis1, angles[0], smat);
1589         VecRotToMat3(axis2, angles[1], totmat);
1590         
1591         Mat3MulMat3(mat, smat, totmat);
1592
1593         for(i = 0 ; i < t->total; i++, td++) {
1594                 if (td->flag & TD_NOACTION)
1595                         break;
1596                 
1597                 if (G.vd->around == V3D_LOCAL) {
1598                         if (t->flag & T_OBJECT)
1599                                 VECCOPY(t->center, td->center); // not supported in editmode yet
1600                 }
1601                 
1602                 if (t->flag & T_PROP_EDIT) {
1603                         VecRotToMat3(axis1, td->factor * angles[0], smat);
1604                         VecRotToMat3(axis2, td->factor * angles[1], totmat);
1605                         
1606                         Mat3MulMat3(mat, smat, totmat);
1607                 }
1608
1609                 ElementRotation(t, td, mat);
1610         }
1611 }
1612
1613 int Trackball(TransInfo *t, short mval[2]) 
1614 {
1615         char str[80];
1616         float axis1[3], axis2[3];
1617         float mat[3][3], totmat[3][3], smat[3][3];
1618         float phi[2];
1619         
1620         VECCOPY(axis1, t->persinv[0]);
1621         VECCOPY(axis2, t->persinv[1]);
1622         Normalise(axis1);
1623         Normalise(axis2);
1624         
1625         /* factore has to become setting or so */
1626         phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
1627         phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
1628         
1629         //if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
1630         //else t->fac += dphi;
1631         
1632         snapGrid(t, phi);
1633         
1634         if (hasNumInput(&t->num)) {
1635                 char c[40];
1636                 
1637                 applyNumInput(&t->num, phi);
1638                 
1639                 outputNumInput(&(t->num), c);
1640                 
1641                 sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
1642                 
1643                 phi[0] *= (float)(M_PI / 180.0);
1644                 phi[1] *= (float)(M_PI / 180.0);
1645         }
1646         else {
1647                 sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
1648         }
1649         
1650         VecRotToMat3(axis1, phi[0], smat);
1651         VecRotToMat3(axis2, phi[1], totmat);
1652         
1653         Mat3MulMat3(mat, smat, totmat);
1654         
1655         Mat3CpyMat3(t->mat, mat);       // used in manipulator
1656         
1657         applyTrackball(t, axis1, axis2, phi);
1658         
1659         recalcData(t);
1660         
1661         headerprint(str);
1662         
1663         force_draw(0);
1664         
1665         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
1666         
1667         return 1;
1668 }
1669
1670 /* ************************** TRANSLATION *************************** */
1671         
1672 void initTranslation(TransInfo *t) 
1673 {
1674         t->idx_max = 2;
1675         t->num.idx_max = 2;
1676         t->snap[0] = 0.0f;
1677         t->snap[1] = G.vd->gridview * 1.0f;
1678         t->snap[2] = t->snap[1] * 0.1f;
1679         t->transform = Translation;
1680         
1681         /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
1682         if (G.obedit) {
1683                 float vec[3];
1684                 
1685                 VECCOPY(vec, t->center);
1686                 Mat4MulVecfl(G.obedit->obmat, vec);
1687                 initgrabz(vec[0], vec[1], vec[2]);
1688         }
1689         else initgrabz(t->center[0], t->center[1], t->center[2]); 
1690 }
1691
1692 static void headerTranslation(TransInfo *t, float vec[3], char *str) {
1693         char tvec[60];
1694         if (hasNumInput(&t->num)) {
1695                 outputNumInput(&(t->num), tvec);
1696         }
1697         else {
1698                 sprintf(&tvec[0], "%.4f", vec[0]);
1699                 sprintf(&tvec[20], "%.4f", vec[1]);
1700                 sprintf(&tvec[40], "%.4f", vec[2]);
1701         }
1702
1703         if (t->con.mode & CON_APPLY) {
1704                 switch(t->num.idx_max) {
1705                 case 0:
1706                         sprintf(str, "D: %s%s %s", &tvec[0], t->con.text, t->proptext);
1707                         break;
1708                 case 1:
1709                         sprintf(str, "D: %s   D: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1710                         break;
1711                 case 2:
1712                         sprintf(str, "D: %s   D: %s  D: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1713                 }
1714         }
1715         else {
1716                 sprintf(str, "Dx: %s   Dy: %s  Dz: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1717         }
1718 }
1719
1720 static void applyTranslation(TransInfo *t, float vec[3]) {
1721         TransData *td = t->data;
1722         float tvec[3];
1723         int i;
1724
1725         for(i = 0 ; i < t->total; i++, td++) {
1726                 if (td->flag & TD_NOACTION)
1727                         break;
1728
1729                 if (t->con.applyVec) {
1730                         float pvec[3];
1731                         t->con.applyVec(t, td, vec, tvec, pvec);
1732                 }
1733                 else {
1734                         VECCOPY(tvec, vec);
1735                 }
1736
1737                 Mat3MulVecfl(td->smtx, tvec);
1738                 VecMulf(tvec, td->factor);
1739                 
1740                 /* transdata ipokey */
1741                 if(td->tdi) {
1742                         TransDataIpokey *tdi= td->tdi;
1743                         add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
1744                         add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
1745                         add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
1746                 }
1747                 else VecAddf(td->loc, td->iloc, tvec);
1748         }
1749 }
1750
1751 /* uses t->vec to store actual translation in */
1752 int Translation(TransInfo *t, short mval[2]) 
1753 {
1754         float tvec[3];
1755         char str[200];
1756         
1757         if(t->flag & T_SHIFT_MOD) {
1758                 float dvec[3];
1759                 /* calculate the main translation and the precise one separate */
1760                 window_to_3d(dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
1761                 VecMulf(dvec, 0.1f);
1762                 window_to_3d(t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
1763                 VecAddf(t->vec, t->vec, dvec);
1764         }
1765         else window_to_3d(t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
1766
1767         if (t->con.mode & CON_APPLY) {
1768                 float pvec[3] = {0.0f, 0.0f, 0.0f};
1769                 t->con.applyVec(t, NULL, t->vec, tvec, pvec);
1770                 VECCOPY(t->vec, tvec);
1771                 headerTranslation(t, pvec, str);
1772         }
1773         else {
1774                 snapGrid(t, t->vec);
1775                 applyNumInput(&t->num, t->vec);
1776                 headerTranslation(t, t->vec, str);
1777         }
1778
1779         applyTranslation(t, t->vec);
1780
1781         recalcData(t);
1782
1783         headerprint(str);
1784
1785         force_draw(0);
1786
1787         return 1;
1788 }
1789
1790 /* ************************** SHRINK/FATTEN *************************** */
1791
1792 void initShrinkFatten(TransInfo *t) 
1793 {
1794         if (G.obedit==NULL || G.obedit->type != OB_MESH) {
1795                 initTransModeFlags(t, TFM_RESIZE);
1796                 initResize(t);
1797                 return;
1798         }
1799
1800         t->idx_max = 0;
1801         t->num.idx_max = 0;
1802         t->snap[0] = 0.0f;
1803         t->snap[1] = 1.0f;
1804         t->snap[2] = t->snap[1] * 0.1f;
1805         t->transform = ShrinkFatten;
1806 }
1807
1808
1809
1810 int ShrinkFatten(TransInfo *t, short mval[2]) 
1811 {
1812         float vec[3];
1813         float ratio;
1814         int i;
1815         char str[50];
1816         TransData *td = t->data;
1817
1818         window_to_3d(t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
1819         Projf(vec, t->vec, G.vd->viewinv[1]);
1820         ratio = Inpf(G.vd->viewinv[1], vec) * -2.0f;
1821
1822         snapGrid(t, &ratio);
1823
1824         applyNumInput(&t->num, &ratio);
1825
1826         /* header print for NumInput */
1827         if (hasNumInput(&t->num)) {
1828                 char c[20];
1829
1830                 outputNumInput(&(t->num), c);
1831
1832                 sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
1833         }
1834         else {
1835                 /* default header print */
1836                 sprintf(str, "Shrink/Fatten: %.4f %s", ratio, t->proptext);
1837         }
1838         
1839         
1840         for(i = 0 ; i < t->total; i++, td++) {
1841                 if (td->flag & TD_NOACTION)
1842                         break;
1843
1844                 VECCOPY(vec, td->axismtx[2]);
1845                 VecMulf(vec, ratio);
1846                 VecMulf(vec, td->factor);
1847
1848                 VecAddf(td->loc, td->iloc, vec);
1849         }
1850
1851         recalcData(t);
1852
1853         headerprint(str);
1854
1855         force_draw(0);
1856
1857         return 1;
1858 }
1859
1860 /* ************************** TILT *************************** */
1861
1862 void initTilt(TransInfo *t) 
1863 {
1864         t->idx_max = 0;
1865         t->num.idx_max = 0;
1866         t->snap[0] = 0.0f;
1867         t->snap[1] = (float)((5.0/180)*M_PI);
1868         t->snap[2] = t->snap[1] * 0.2f;
1869         t->fac = 0;
1870         t->transform = Tilt;
1871 }
1872
1873
1874
1875 int Tilt(TransInfo *t, short mval[2]) 
1876 {
1877         TransData *td = t->data;
1878         int i;
1879         char str[50];
1880
1881         float final;
1882
1883         int dx2 = t->center2d[0] - mval[0];
1884         int dy2 = t->center2d[1] - mval[1];
1885         float B = (float)sqrt(dx2*dx2+dy2*dy2);
1886
1887         int dx1 = t->center2d[0] - t->imval[0];
1888         int dy1 = t->center2d[1] - t->imval[1];
1889         float A = (float)sqrt(dx1*dx1+dy1*dy1);
1890
1891         int dx3 = mval[0] - t->imval[0];
1892         int dy3 = mval[1] - t->imval[1];
1893
1894         float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
1895                 / (2 * A * B);
1896
1897         float dphi;
1898
1899         dphi = saacos(deler);
1900         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
1901
1902         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
1903         else t->fac += dphi;
1904
1905         final = t->fac;
1906
1907         snapGrid(t, &final);
1908
1909         t->imval[0] = mval[0];
1910         t->imval[1] = mval[1];
1911
1912         if (hasNumInput(&t->num)) {
1913                 char c[20];
1914
1915                 applyNumInput(&t->num, &final);
1916
1917                 outputNumInput(&(t->num), c);
1918
1919                 sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
1920
1921                 final *= (float)(M_PI / 180.0);
1922         }
1923         else {
1924                 sprintf(str, "Tilt: %.2f %s", 180.0*final/M_PI, t->proptext);
1925         }
1926
1927         for(i = 0 ; i < t->total; i++, td++) {
1928                 if (td->flag & TD_NOACTION)
1929                         break;
1930
1931                 if (td->val) {
1932                         *td->val = td->ival + final * td->factor;
1933                 }
1934         }
1935
1936         recalcData(t);
1937
1938         headerprint(str);
1939
1940         force_draw(0);
1941
1942         helpline (t->center);
1943
1944         return 1;
1945 }
1946
1947 /* ************************** PUSH/PULL *************************** */
1948
1949 void initPushPull(TransInfo *t) 
1950 {
1951         t->idx_max = 0;
1952         t->num.idx_max = 0;
1953         t->snap[0] = 0.0f;
1954         t->snap[1] = 1.0f;
1955         t->snap[2] = t->snap[1] * 0.1f;
1956         t->transform = PushPull;
1957 }
1958
1959
1960
1961 int PushPull(TransInfo *t, short mval[2]) 
1962 {
1963         float vec[3], axis[3];
1964         float distance;
1965         int i;
1966         char str[50];
1967         TransData *td = t->data;
1968
1969         window_to_3d(t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
1970         Projf(vec, t->vec, G.vd->viewinv[1]);
1971         distance = Inpf(G.vd->viewinv[1], vec) * 2.0f;
1972
1973         snapGrid(t, &distance);
1974
1975         applyNumInput(&t->num, &distance);
1976
1977         /* header print for NumInput */
1978         if (hasNumInput(&t->num)) {
1979                 char c[20];
1980
1981                 outputNumInput(&(t->num), c);
1982
1983                 sprintf(str, "Push/Pull: %s%s %s", c, t->con.text, t->proptext);
1984         }
1985         else {
1986                 /* default header print */
1987                 sprintf(str, "Push/Pull: %.4f%s %s", distance, t->con.text, t->proptext);
1988         }
1989         
1990         if (t->con.applyRot && t->con.mode & CON_APPLY) {
1991                 t->con.applyRot(t, NULL, axis);
1992         }
1993         
1994         for(i = 0 ; i < t->total; i++, td++) {
1995                 if (td->flag & TD_NOACTION)
1996                         break;
1997
1998                 VecSubf(vec, t->center, td->center);
1999                 if (t->con.applyRot && t->con.mode & CON_APPLY) {
2000                         t->con.applyRot(t, td, axis);
2001                         if (isLockConstraint(t)) {
2002                                 float dvec[3];
2003                                 Projf(dvec, vec, axis);
2004                                 VecSubf(vec, vec, dvec);
2005                         }
2006                         else {
2007                                 Projf(vec, vec, axis);
2008                         }
2009                 }
2010                 Normalise(vec);
2011                 VecMulf(vec, distance);
2012                 VecMulf(vec, td->factor);
2013
2014                 VecAddf(td->loc, td->iloc, vec);
2015         }
2016
2017         recalcData(t);
2018
2019         headerprint(str);
2020
2021         force_draw(0);
2022
2023         return 1;
2024 }
2025
2026 /* ************************** CREASE *************************** */
2027
2028 void initCrease(TransInfo *t) 
2029 {
2030         t->idx_max = 0;
2031         t->num.idx_max = 0;
2032         t->snap[0] = 0.0f;
2033         t->snap[1] = 0.1f;
2034         t->snap[2] = t->snap[1] * 0.1f;
2035         t->transform = Crease;
2036         t->fac = (float)sqrt( (float)
2037                 (
2038                         (t->center2d[1] - t->imval[1])*(t->center2d[1] - t->imval[1])
2039                 +
2040                         (t->center2d[0] - t->imval[0])*(t->center2d[0] - t->imval[0])
2041                 ) );
2042
2043         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2044 }
2045
2046 int Crease(TransInfo *t, short mval[2]) 
2047 {
2048         TransData *td = t->data;
2049         float crease;
2050         int i;
2051         char str[50];
2052
2053                 
2054         if(t->flag & T_SHIFT_MOD) {
2055                 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2056                 float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2057                 float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2058                 crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
2059                 
2060                 dx= (float)(t->center2d[0] - mval[0]);
2061                 dy= (float)(t->center2d[1] - mval[1]);
2062                 crease+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -crease);
2063                 
2064         }
2065         else {
2066                 float dx= (float)(t->center2d[0] - mval[0]);
2067                 float dy= (float)(t->center2d[1] - mval[1]);
2068                 crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
2069         }
2070
2071         crease -= 1.0f;
2072         if (crease > 1.0f) crease = 1.0f;
2073
2074         snapGrid(t, &crease);
2075
2076         applyNumInput(&t->num, &crease);
2077
2078         /* header print for NumInput */
2079         if (hasNumInput(&t->num)) {
2080                 char c[20];
2081
2082                 outputNumInput(&(t->num), c);
2083
2084                 if (crease >= 0.0f)
2085                         sprintf(str, "Crease: +%s %s", c, t->proptext);
2086                 else
2087                         sprintf(str, "Crease: %s %s", c, t->proptext);
2088         }
2089         else {
2090                 /* default header print */
2091                 if (crease >= 0.0f)
2092                         sprintf(str, "Crease: +%.3f %s", crease, t->proptext);
2093                 else
2094                         sprintf(str, "Crease: %.3f %s", crease, t->proptext);
2095         }
2096         
2097         for(i = 0 ; i < t->total; i++, td++) {
2098                 if (td->flag & TD_NOACTION)
2099                         break;
2100
2101                 if (td->val) {
2102                         *td->val = td->ival + crease * td->factor;
2103                         if (*td->val < 0.0f) *td->val = 0.0f;
2104                         if (*td->val > 1.0f) *td->val = 1.0f;
2105                 }
2106         }
2107
2108         recalcData(t);
2109
2110         headerprint(str);
2111
2112         force_draw(0);
2113
2114         helpline (t->center);
2115
2116         return 1;
2117 }
2118
2119 /* ************************** MIRROR *************************** */
2120
2121 void Mirror(short mode) 
2122 {
2123         TransData *td;
2124         float mati[3][3], matview[3][3], mat[3][3];
2125         float size[3];
2126         int i;
2127
2128         Mat3One(mati);
2129         Mat3CpyMat4(matview, G.vd->viewinv);
2130         Mat3Ortho(matview);
2131
2132         Trans.context = CTX_NO_PET;
2133
2134         initTrans(&Trans);                                      // internal data, mouse, vectors
2135
2136         initTransModeFlags(&Trans, TFM_MIRROR); // modal settings in struct Trans
2137
2138         createTransData(&Trans);                        // make TransData structs from selection
2139
2140         calculatePropRatio(&Trans);
2141         calculateCenter(&Trans);
2142
2143         initResize(&Trans);
2144
2145         initConstraint(&Trans);
2146
2147         if (Trans.total == 0) {
2148                 postTrans(&Trans);
2149                 return;
2150         }
2151
2152         size[0] = size[1] = size[2] = 1.0f;
2153         td = Trans.data;
2154
2155         switch (mode) {
2156         case 1:
2157                 size[0] = -1.0f;
2158                 setConstraint(&Trans, mati, (CON_AXIS0), "");
2159                 break;
2160         case 2:
2161                 size[1] = -1.0f;
2162                 setConstraint(&Trans, mati, (CON_AXIS1), "");
2163                 break;
2164         case 3:
2165                 size[2] = -1.0f;
2166                 setConstraint(&Trans, mati, (CON_AXIS2), "");
2167                 break;
2168         case 4:
2169                 size[0] = -1.0f;
2170                 setLocalConstraint(&Trans, (CON_AXIS0), "");
2171                 break;
2172         case 5:
2173                 size[1] = -1.0f;
2174                 setLocalConstraint(&Trans, (CON_AXIS1), "");
2175                 break;
2176         case 6:
2177                 size[2] = -1.0f;
2178                 setLocalConstraint(&Trans, (CON_AXIS2), "");
2179                 break;
2180         case 7:
2181                 size[0] = -1.0f;
2182                 setConstraint(&Trans, matview, (CON_AXIS0), "");
2183                 break;
2184         case 8:
2185                 size[1] = -1.0f;
2186                 setConstraint(&Trans, matview, (CON_AXIS1), "");
2187                 break;
2188         case 9:
2189                 size[2] = -1.0f;
2190                 setConstraint(&Trans, matview, (CON_AXIS2), "");
2191                 break;
2192         default:
2193                 return;
2194         }
2195
2196         SizeToMat3(size, mat);
2197
2198         if (Trans.con.applySize) {
2199                 Trans.con.applySize(&Trans, NULL, mat);
2200         }
2201
2202         for(i = 0 ; i < Trans.total; i++, td++) {
2203                 if (td->flag & TD_NOACTION)
2204                         break;
2205                 
2206                 ElementResize(&Trans, td, mat);
2207         }
2208
2209         recalcData(&Trans);
2210         
2211         BIF_undo_push("Mirror");
2212
2213         /* free data, reset vars */
2214         postTrans(&Trans);
2215
2216         /* send events out for redraws */
2217         allqueue(REDRAWVIEW3D, 0);
2218         allqueue(REDRAWBUTSOBJECT, 0);
2219         scrarea_queue_headredraw(curarea);
2220 }
2221
2222
2223 void BIF_TransformSetUndo(char *str)
2224 {
2225         Trans.undostr= str;
2226 }
2227
2228