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