- Removed temporal hack that switched manipulator type on G, R, S hotkeys.
[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 #include "transform_generics.h"
122 #include "transform_constraints.h"
123 #include "transform_numinput.h"
124
125 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING  */
126 TransInfo Trans;
127 int     LastMode = TFM_TRANSLATION;
128
129 /* ************************** Functions *************************** */
130
131 static void qsort_trans_data(TransData *head, TransData *tail) {
132         TransData pivot = *head;
133         TransData *ihead = head;
134         TransData *itail = tail;
135
136         while (head < tail)
137         {
138                 while ((tail->dist >= pivot.dist) && (head < tail))
139                         tail--;
140
141                 if (head != tail)
142                 {
143                         *head = *tail;
144                         head++;
145                 }
146
147                 while ((head->dist <= pivot.dist) && (head < tail))
148                         head++;
149
150                 if (head != tail)
151                 {
152                         *tail = *head;
153                         tail--;
154                 }
155         }
156
157         *head = pivot;
158         if (ihead < head) {
159                 qsort_trans_data(ihead, head-1);
160         }
161         if (itail > head) {
162                 qsort_trans_data(head+1, itail);
163         }
164 }
165
166 static void sort_trans_data_dist(TransInfo *t) {
167         TransData *start = t->data;
168         int i = 1;
169
170         while(i < t->total && start->flag & TD_SELECTED) {
171                 start++;
172                 i++;
173         }
174         qsort_trans_data(start, t->data + t->total - 1);
175 }
176
177 static void sort_trans_data(TransInfo *t) 
178 {
179         TransData *sel, *unsel;
180         TransData temp;
181         unsel = t->data;
182         sel = t->data;
183         sel += t->total - 1;
184         while (sel > unsel) {
185                 while (unsel->flag & TD_SELECTED) {
186                         unsel++;
187                         if (unsel == sel) {
188                                 return;
189                         }
190                 }
191                 while (!(sel->flag & TD_SELECTED)) {
192                         sel--;
193                         if (unsel == sel) {
194                                 return;
195                         }
196                 }
197                 temp = *unsel;
198                 *unsel = *sel;
199                 *sel = temp;
200                 sel--;
201                 unsel++;
202         }
203 }
204
205
206 /* distance calculated from not-selected vertex to nearest selected vertex
207    warning; this is loops inside loop, has minor N^2 issues, but by sorting list it is OK */
208 static void set_prop_dist(TransInfo *t)
209 {
210         TransData *tob;
211         int a;
212         
213         for(a=0, tob= t->data; a<t->total; a++, tob++) {
214                 
215                 tob->dist= 0.0f; // init, it was mallocced
216                 
217                 if((tob->flag & TD_SELECTED)==0) {
218                         TransData *td;
219                         int i;
220                         float dist, vec[3];
221
222                         tob->dist = -1.0f; // signal for next loop
223                                 
224                         for (i = 0, td= t->data; i < t->total; i++, td++) {
225                                 if(td->flag & TD_SELECTED) {
226                                         VecSubf(vec, tob->center, td->center);
227                                         Mat3MulVecfl(tob->mtx, vec);
228                                         dist = Normalise(vec);
229                                         if (tob->dist == -1.0f) {
230                                                 tob->dist = dist;
231                                         }
232                                         else if (dist < tob->dist) {
233                                                 tob->dist = dist;
234                                         }
235                                 }
236                                 else break;     // by definition transdata has selected items in beginning
237                         }
238                 }       
239         }
240 }
241
242 /* ************************** CONVERSIONS ************************* */
243
244 static void createTransTexspace(void)
245 {
246         TransData *td;
247         Object *ob;
248         ID *id;
249         
250         ob= OBACT;
251         Trans.total = 1;
252         td= Trans.data= MEM_callocN(sizeof(TransData), "TransTexspace");
253         td->ext= Trans.ext= MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
254         
255         td->flag= TD_SELECTED;
256         VECCOPY(td->center, ob->obmat[3]);
257         td->ob = ob;
258         
259         Mat3CpyMat4(td->mtx, ob->obmat);
260         Mat3Inv(td->smtx, td->mtx);
261         
262         id= ob->data;
263         if(id==0);
264         else if( GS(id->name)==ID_ME) {
265                 Mesh *me= ob->data;
266                 me->texflag &= ~AUTOSPACE;
267                 td->loc= me->loc;
268                 td->ext->rot= me->rot;
269                 td->ext->size= me->size;
270         }
271         else if( GS(id->name)==ID_CU) {
272                 Curve *cu= ob->data;
273                 cu->texflag &= ~CU_AUTOSPACE;
274                 td->loc= cu->loc;
275                 td->ext->rot= cu->rot;
276                 td->ext->size= cu->size;
277         }
278         else if( GS(id->name)==ID_MB) {
279                 MetaBall *mb= ob->data;
280                 mb->texflag &= ~MB_AUTOSPACE;
281                 td->loc= mb->loc;
282                 td->ext->rot= mb->rot;
283                 td->ext->size= mb->size;
284         }
285         
286         VECCOPY(td->iloc, td->loc);
287         VECCOPY(td->ext->irot, td->ext->rot);
288         VECCOPY(td->ext->isize, td->ext->size);
289 }
290
291
292 /* ********************* pose mode ************* */
293
294 /* callback, make sure it's identical structured as next one */
295 /* also used to count for manipulator */
296 void count_bone_select(ListBase *lb, int *counter) 
297 {
298         Bone *bone;
299         
300         for(bone= lb->first; bone; bone= bone->next) {
301                 if (bone->flag & BONE_SELECTED) {
302                         /* We don't let IK children get "grabbed" */
303                         /* ALERT! abusive global Trans here */
304                         if ( (Trans.mode!=TFM_TRANSLATION) || (bone->flag & BONE_IK_TOPARENT)==0 ) {
305                                 (*counter)++;
306                                 return; // no transform on children if one parent bone is selected
307                         }
308                 }
309                 count_bone_select( &bone->childbase, counter);
310         }
311 }
312
313 /* recursive */
314 static void add_pose_transdata(ListBase *lb, Object *ob, TransData **tdp)
315 {
316         Bone *bone;
317         TransData *td= *tdp;
318         float   parmat[4][4], tempmat[4][4];
319         float tempobmat[4][4];
320         float vec[3];
321         
322         for(bone= lb->first; bone; bone= bone->next) {
323                 if (bone->flag & BONE_SELECTED) {
324                         /* We don't let IK children get "grabbed" */
325                         /* ALERT! abusive global Trans here */
326                         if ( (Trans.mode!=TFM_TRANSLATION) || (bone->flag & BONE_IK_TOPARENT)==0 ) {
327                                 
328                                 get_bone_root_pos (bone, vec, 1);
329                                 
330                                 //VecAddf (centroid, centroid, vec);
331                                 VECCOPY(td->center, vec);
332                                 
333                                 td->ob = ob;
334                                 td->flag= TD_SELECTED|TD_USEQUAT;
335                                 td->loc = bone->loc;
336                                 VECCOPY(td->iloc, bone->loc);
337                                 
338                                 td->ext->rot= NULL;
339                                 td->ext->quat= bone->quat;
340                                 td->ext->size= bone->size;
341                                 td->ext->bone= bone; // FIXME: Dangerous
342
343                                 QUATCOPY(td->ext->iquat, bone->quat);
344                                 VECCOPY(td->ext->isize, bone->size);
345                                 
346                                 /* Get the matrix of this bone minus the usertransform */
347                                 Mat4CpyMat4 (tempobmat, bone->obmat);
348                                 Mat4One (bone->obmat);
349                                 get_objectspace_bone_matrix(bone, tempmat, 1, 1);
350                                 Mat4CpyMat4 (bone->obmat, tempobmat);
351
352                                 Mat4MulMat4 (parmat, tempmat, ob->obmat);       /* Original */
353                                 
354                                 Mat3CpyMat4 (td->mtx, parmat);
355                                 Mat3Inv (td->smtx, td->mtx);
356                                 
357                                 (*tdp)++;
358                                 return; // see above function
359                         }
360                 }
361                 add_pose_transdata(&bone->childbase, ob, tdp);
362         }
363 }
364
365 static void createTransPose(void)
366 {
367         bArmature *arm;
368         TransData *td;
369         TransDataExtension *tdx;
370         int i;
371         
372         Trans.total= 0; // to be able to return
373         
374         /* check validity of state */
375         arm=get_armature (G.obpose);
376         if (arm==NULL) return;
377         
378         if (arm->flag & ARM_RESTPOS){
379                 notice ("Transformation not possible while Rest Position is enabled");
380                 return;
381         }
382         if (!(G.obpose->lay & G.vd->lay)) return;
383
384         /* copied from old code, no idea. we let linker solve it for now */
385         {
386                 extern void figure_bone_nocalc(Object *ob);
387                 extern void figure_pose_updating(void);
388
389                 /* figure out which bones need calculating */
390                 figure_bone_nocalc(G.obpose);
391                 figure_pose_updating();
392         }
393         
394         /* copied from old code, no idea... (ton) */
395         apply_pose_armature(arm, G.obpose->pose, 0);
396         where_is_armature (G.obpose);
397         
398         /* count total */
399         count_bone_select(&arm->bonebase, &Trans.total);
400         
401         if(Trans.total==0 && Trans.mode==TFM_TRANSLATION) {
402                 Trans.mode= TFM_ROTATION;
403                 count_bone_select(&arm->bonebase, &Trans.total);
404         }               
405         if(Trans.total==0) return;
406         
407         /* init trans data */
408     td = Trans.data = MEM_mallocN(Trans.total*sizeof(TransData), "TransPoseBone");
409     tdx = Trans.ext = MEM_mallocN(Trans.total*sizeof(TransDataExtension), "TransPoseBoneExt");
410         for(i=0; i<Trans.total; i++, td++, tdx++) {
411                 td->ext= tdx;
412                 td->tdi = NULL;
413                 td->val = NULL;
414         }       
415         /* recursive fill trans data */
416         td= Trans.data;
417         add_pose_transdata(&arm->bonebase, G.obpose, &td);
418         
419 }
420
421 static void createTransArmatureVerts(void)
422 {
423         EditBone *ebo;
424         TransData *td;
425         float mtx[3][3], smtx[3][3];
426
427         Trans.total = 0;
428         for (ebo=G.edbo.first;ebo;ebo=ebo->next){
429                 if (ebo->flag & BONE_TIPSEL){
430                         Trans.total++;
431                 }
432                 if (ebo->flag & BONE_ROOTSEL){
433                         Trans.total++;
434                 }
435         }
436
437     if (!Trans.total) return;
438         
439         Mat3CpyMat4(mtx, G.obedit->obmat);
440         Mat3Inv(smtx, mtx);
441
442     td = Trans.data = MEM_mallocN(Trans.total*sizeof(TransData), "TransEditBone");
443         
444         for (ebo=G.edbo.first;ebo;ebo=ebo->next){
445                 if (ebo->flag & BONE_TIPSEL){
446                         VECCOPY (td->iloc, ebo->tail);
447                         VECCOPY (td->center, td->iloc);
448                         td->loc= ebo->tail;
449                         td->flag= TD_SELECTED;
450
451                         Mat3CpyMat3(td->smtx, smtx);
452                         Mat3CpyMat3(td->mtx, mtx);
453
454                         td->ext = NULL;
455                         td->tdi = NULL;
456                         td->val = NULL;
457
458                         td++;
459                 }
460                 if (ebo->flag & BONE_ROOTSEL){
461                         VECCOPY (td->iloc, ebo->head);
462                         VECCOPY (td->center, td->iloc);
463                         td->loc= ebo->head;
464                         td->flag= TD_SELECTED;
465
466                         Mat3CpyMat3(td->smtx, smtx);
467                         Mat3CpyMat3(td->mtx, mtx);
468
469                         td->ext = NULL;
470                         td->tdi = NULL;
471                         td->val = NULL;
472
473                         td++;
474                 }
475                         
476         }
477 }
478
479 static void createTransMBallVerts(void)
480 {
481         MetaElem *ml;
482         TransData *td;
483         TransDataExtension *tx;
484         float mtx[3][3], smtx[3][3];
485         int count=0, countsel=0;
486         int propmode = G.f & G_PROPORTIONAL;
487
488         /* count totals */
489     for(ml= editelems.first; ml; ml= ml->next) {
490                 if(ml->flag & SELECT) countsel++;
491                 if(propmode) count++;
492         }
493
494         /* note: in prop mode we need at least 1 selected */
495         if (countsel==0) return;
496         
497         if(propmode) Trans.total = count; 
498         else Trans.total = countsel;
499         
500         Trans.data= MEM_mallocN(Trans.total*sizeof(TransData), "TransObData(MBall EditMode)");
501         tx = Trans.ext = MEM_mallocN(Trans.total*sizeof(TransDataExtension), "MetaElement_TransExtension");
502
503         Mat3CpyMat4(mtx, G.obedit->obmat);
504         Mat3Inv(smtx, mtx);
505     
506         td = Trans.data;
507     for(ml= editelems.first; ml; ml= ml->next) {
508                 if(propmode || (ml->flag & SELECT)) {
509                         td->loc= &ml->x;
510                         VECCOPY(td->iloc, td->loc);
511                         VECCOPY(td->center, td->loc);
512                         if(ml->flag & SELECT) td->flag= TD_SELECTED;
513                         else td->flag= 0;
514                         Mat3CpyMat3(td->smtx, smtx);
515                         Mat3CpyMat3(td->mtx, mtx);
516
517                         td->ext = tx;
518                         td->tdi = NULL;
519                         td->val = NULL;
520
521                         tx->size = &ml->expx;
522                         tx->isize[0] = ml->expx;
523                         tx->isize[1] = ml->expy;
524                         tx->isize[2] = ml->expz;
525
526                         tx->rot = NULL;
527
528                         td++;
529                         tx++;
530                 }
531         }
532
533
534 static void createTransCurveVerts(void)
535 {
536         TransData *td = NULL;
537         Nurb *nu;
538         BezTriple *bezt;
539         BPoint *bp;
540         float mtx[3][3], smtx[3][3];
541         int a;
542         int count=0, countsel=0;
543         int propmode = G.f & G_PROPORTIONAL;
544
545         /* count total of vertices, check identical as in 2nd loop for making transdata! */
546         for(nu= editNurb.first; nu; nu= nu->next) {
547                 if((nu->type & 7)==CU_BEZIER) {
548                         for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) {
549                                 if(bezt->hide==0) {
550                                         if(bezt->f1 & 1) countsel++;
551                                         if(bezt->f2 & 1) countsel++;
552                                         if(bezt->f3 & 1) countsel++;
553                                         if(propmode) count+= 3;
554                                 }
555                         }
556                 }
557                 else {
558                         for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) {
559                                 if(bp->hide==0) {
560                                         if(propmode) count++;
561                                         if(bp->f1 & 1) countsel++;
562                                 }
563                         }
564                 }
565         }
566         /* note: in prop mode we need at least 1 selected */
567         if (countsel==0) return;
568         
569         if(propmode) Trans.total = count; 
570         else Trans.total = countsel;
571         Trans.data= MEM_mallocN(Trans.total*sizeof(TransData), "TransObData(Curve EditMode)");
572
573         Mat3CpyMat4(mtx, G.obedit->obmat);
574         Mat3Inv(smtx, mtx);
575
576     td = Trans.data;
577         for(nu= editNurb.first; nu; nu= nu->next) {
578                 if((nu->type & 7)==CU_BEZIER) {
579                         for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) {
580                                 if(bezt->hide==0) {
581                                         if(propmode || (bezt->f1 & 1)) {
582                                                 VECCOPY(td->iloc, bezt->vec[0]);
583                                                 td->loc= bezt->vec[0];
584                                                 VECCOPY(td->center, td->loc);
585                                                 if(bezt->f1 & 1) td->flag= TD_SELECTED;
586                                                 else td->flag= 0;
587                                                 td->ext = NULL;
588                                                 td->tdi = NULL;
589                                                 td->val = NULL;
590
591                                                 Mat3CpyMat3(td->smtx, smtx);
592                                                 Mat3CpyMat3(td->mtx, mtx);
593
594                                                 td++;
595                                                 count++;
596                                         }
597                                         /* THIS IS THE CV, the other two are handles */
598                                         if(propmode || (bezt->f2 & 1)) {
599                                                 VECCOPY(td->iloc, bezt->vec[1]);
600                                                 td->loc= bezt->vec[1];
601                                                 VECCOPY(td->center, td->loc);
602                                                 if(bezt->f2 & 1) td->flag= TD_SELECTED;
603                                                 else td->flag= 0;
604                                                 td->ext = NULL;
605                                                 td->tdi = NULL;
606                                                 td->val = &(bezt->alfa);
607                                                 td->ival = bezt->alfa;
608
609                                                 Mat3CpyMat3(td->smtx, smtx);
610                                                 Mat3CpyMat3(td->mtx, mtx);
611
612                                                 td++;
613                                                 count++;
614                                         }
615                                         if(propmode || (bezt->f3 & 1)) {
616                                                 VECCOPY(td->iloc, bezt->vec[2]);
617                                                 td->loc= bezt->vec[2];
618                                                 VECCOPY(td->center, td->loc);
619                                                 if(bezt->f3 & 1) td->flag= TD_SELECTED;
620                                                 else td->flag= 0;
621                                                 td->ext = NULL;
622                                                 td->tdi = NULL;
623                                                 td->val = NULL;
624
625                                                 Mat3CpyMat3(td->smtx, smtx);
626                                                 Mat3CpyMat3(td->mtx, mtx);
627
628                                                 td++;
629                                                 count++;
630                                         }
631                                 }
632                         }
633                 }
634                 else {
635                         for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) {
636                                 if(bp->hide==0) {
637                                         if(propmode || (bp->f1 & 1)) {
638                                                 VECCOPY(td->iloc, bp->vec);
639                                                 td->loc= bp->vec;
640                                                 VECCOPY(td->center, td->loc);
641                                                 if(bp->f1 & 1) td->flag= TD_SELECTED;
642                                                 else td->flag= 0;
643                                                 td->ext = NULL;
644                                                 td->tdi = NULL;
645                                                 td->val = &(bp->alfa);
646                                                 td->ival = bp->alfa;
647
648                                                 Mat3CpyMat3(td->smtx, smtx);
649                                                 Mat3CpyMat3(td->mtx, mtx);
650
651                                                 td++;
652                                                 count++;
653                                         }
654                                 }
655                         }
656                 }
657         }
658         
659 }
660
661 static void createTransLatticeVerts(void)
662 {
663         TransData *td = NULL;
664         BPoint *bp;
665         float mtx[3][3], smtx[3][3];
666         int a;
667         int count=0, countsel=0;
668         int propmode = G.f & G_PROPORTIONAL;
669
670         bp= editLatt->def;
671         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
672         while(a--) {
673                 if(bp->f1 & 1) countsel++;
674                 if(propmode) count++;
675                 bp++;
676         }
677         
678         /* note: in prop mode we need at least 1 selected */
679         if (countsel==0) return;
680         
681         if(propmode) Trans.total = count; 
682         else Trans.total = countsel;
683         Trans.data= MEM_mallocN(Trans.total*sizeof(TransData), "TransObData(Lattice EditMode)");
684         
685         Mat3CpyMat4(mtx, G.obedit->obmat);
686         Mat3Inv(smtx, mtx);
687
688         td = Trans.data;
689         bp= editLatt->def;
690         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
691         while(a--) {
692                 if(propmode || (bp->f1 & 1)) {
693                         if(bp->hide==0) {
694                                 VECCOPY(td->iloc, bp->vec);
695                                 td->loc= bp->vec;
696                                 VECCOPY(td->center, td->loc);
697                                 if(bp->f1 & 1) td->flag= TD_SELECTED;
698                                 else td->flag= 0;
699                                 Mat3CpyMat3(td->smtx, smtx);
700                                 Mat3CpyMat3(td->mtx, mtx);
701
702                                 td->ext = NULL;
703                                 td->tdi = NULL;
704                                 td->val = NULL;
705
706                                 td++;
707                                 count++;
708                         }
709                 }
710                 bp++;
711         }
712
713
714 static void VertsToTransData(TransData *td, EditVert *eve)
715 {
716         td->flag = 0;
717         td->loc = eve->co;
718         VECCOPY(td->center, td->loc);
719         VECCOPY(td->iloc, td->loc);
720
721         // Setting normals
722         VECCOPY(td->axismtx[2], eve->no);
723         td->axismtx[0][0]               =
724                 td->axismtx[0][1]       =
725                 td->axismtx[0][2]       =
726                 td->axismtx[1][0]       =
727                 td->axismtx[1][1]       =
728                 td->axismtx[1][2]       = 0.0f;
729
730         td->ext = NULL;
731         td->tdi = NULL;
732         td->val = NULL;
733 }
734
735 static void createTransEditVerts(void)
736 {
737         TransData *tob = NULL;
738         EditMesh *em = G.editMesh;
739         EditVert *eve;
740         float mtx[3][3], smtx[3][3];
741         int count=0, countsel=0;
742         int propmode = G.f & G_PROPORTIONAL;
743                 
744         // transform now requires awareness for select mode, so we tag the f1 flags in verts
745         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
746                 for(eve= em->verts.first; eve; eve= eve->next) {
747                         if(eve->h==0 && (eve->f & SELECT)) 
748                                 eve->f1= SELECT;
749                         else
750                                 eve->f1= 0;
751                 }
752         }
753         else if(G.scene->selectmode & SCE_SELECT_EDGE) {
754                 EditEdge *eed;
755                 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
756                 for(eed= em->edges.first; eed; eed= eed->next) {
757                         if(eed->h==0 && (eed->f & SELECT))
758                                 eed->v1->f1= eed->v2->f1= SELECT;
759                 }
760         }
761         else {
762                 EditFace *efa;
763                 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
764                 for(efa= em->faces.first; efa; efa= efa->next) {
765                         if(efa->h==0 && (efa->f & SELECT)) {
766                                 efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
767                                 if(efa->v4) efa->v4->f1= SELECT;
768                         }
769                 }
770         }
771         
772         /* now we can count */
773         for(eve= em->verts.first; eve; eve= eve->next) {
774                 if(eve->h==0) {
775                         if(eve->f1) countsel++;
776                         if(propmode) count++;
777                 }
778         }
779         
780         /* note: in prop mode we need at least 1 selected */
781         if (countsel==0) return;
782         
783         if(propmode) Trans.total = count; 
784         else Trans.total = countsel;
785         tob= Trans.data= MEM_mallocN(Trans.total*sizeof(TransData), "TransObData(Mesh EditMode)");
786         
787         Mat3CpyMat4(mtx, G.obedit->obmat);
788         Mat3Inv(smtx, mtx);
789
790         for (eve=em->verts.first; eve; eve=eve->next) {
791                 if(eve->h==0) {
792                         if(propmode || eve->f1) {
793                                 VertsToTransData(tob, eve);
794
795                                 if(eve->f1) tob->flag |= TD_SELECTED;
796
797                                 Mat3CpyMat3(tob->smtx, smtx);
798                                 Mat3CpyMat3(tob->mtx, mtx);
799
800                                 tob++;
801                         }
802                 }       
803         }
804 }
805
806 /* **************** IpoKey stuff, for Object TransData ********** */
807
808 /* storage of bezier triple. thats why -3 and +3! */
809 static void set_tdi_old(float *old, float *poin)
810 {
811         old[0]= *(poin);
812         old[3]= *(poin-3);
813         old[6]= *(poin+3);
814 }
815
816 /* while transforming */
817 static void add_tdi_poin(float *poin, float *old, float delta)
818 {
819         if(poin) {
820                 poin[0]= old[0]+delta;
821                 poin[-3]= old[3]+delta;
822                 poin[3]= old[6]+delta;
823         }
824 }
825
826 /* fill ipokey transdata with old vals and pointers */
827 static void ipokey_to_transdata(IpoKey *ik, TransData *td)
828 {
829         extern int ob_ar[];             // blenkernel ipo.c
830         TransDataIpokey *tdi= td->tdi;
831         BezTriple *bezt;
832         int a, delta= 0;
833         
834         for(a=0; a<OB_TOTIPO; a++) {
835                 if(ik->data[a]) {
836                         bezt= ik->data[a];
837                         
838                         switch( ob_ar[a] ) {
839                                 case OB_LOC_X:
840                                 case OB_DLOC_X:
841                                         tdi->locx= &(bezt->vec[1][1]); break;
842                                 case OB_LOC_Y:
843                                 case OB_DLOC_Y:
844                                         tdi->locy= &(bezt->vec[1][1]); break;
845                                 case OB_LOC_Z:
846                                 case OB_DLOC_Z:
847                                         tdi->locz= &(bezt->vec[1][1]); break;
848                                         
849                                 case OB_DROT_X:
850                                         delta= 1;
851                                 case OB_ROT_X:
852                                         tdi->rotx= &(bezt->vec[1][1]); break;
853                                 case OB_DROT_Y:
854                                         delta= 1;
855                                 case OB_ROT_Y:
856                                         tdi->roty= &(bezt->vec[1][1]); break;
857                                 case OB_DROT_Z:
858                                         delta= 1;
859                                 case OB_ROT_Z:
860                                         tdi->rotz= &(bezt->vec[1][1]); break;
861                                         
862                                 case OB_SIZE_X:
863                                 case OB_DSIZE_X:
864                                         tdi->sizex= &(bezt->vec[1][1]); break;
865                                 case OB_SIZE_Y:
866                                 case OB_DSIZE_Y:
867                                         tdi->sizey= &(bezt->vec[1][1]); break;
868                                 case OB_SIZE_Z:
869                                 case OB_DSIZE_Z:
870                                         tdi->sizez= &(bezt->vec[1][1]); break;          
871                         }       
872                 }
873         }
874         
875         /* oldvals for e.g. undo */
876         if(tdi->locx) set_tdi_old(tdi->oldloc, tdi->locx);
877         if(tdi->locy) set_tdi_old(tdi->oldloc+1, tdi->locy);
878         if(tdi->locz) set_tdi_old(tdi->oldloc+2, tdi->locz);
879         
880         /* remember, for mapping curves ('1'=10 degrees)  */
881         if(tdi->rotx) set_tdi_old(tdi->oldrot, tdi->rotx);
882         if(tdi->roty) set_tdi_old(tdi->oldrot+1, tdi->roty);
883         if(tdi->rotz) set_tdi_old(tdi->oldrot+2, tdi->rotz);
884         
885         /* this is not allowed to be dsize! */
886         if(tdi->sizex) set_tdi_old(tdi->oldsize, tdi->sizex);
887         if(tdi->sizey) set_tdi_old(tdi->oldsize+1, tdi->sizey);
888         if(tdi->sizez) set_tdi_old(tdi->oldsize+2, tdi->sizez);
889         
890         tdi->flag= TOB_IPO;
891         if(delta) tdi->flag |= TOB_IPODROT;
892 }
893
894
895 /* *************************** Object Transform data ******************* */
896
897 static void ObjectToTransData(TransData *td, Object *ob) 
898 {
899         float obmtx[3][3];
900         Object *tr;
901         void *cfirst, *clast;
902
903         cfirst = ob->constraints.first;
904         clast = ob->constraints.last;
905         ob->constraints.first=ob->constraints.last=NULL;
906
907         tr= ob->track;
908         ob->track= NULL;
909
910         where_is_object(ob);
911
912         ob->track= tr;
913
914         ob->constraints.first = cfirst;
915         ob->constraints.last = clast;
916
917         td->ob = ob;
918
919         td->loc = ob->loc;
920         VECCOPY(td->iloc, td->loc);
921         
922         td->ext->rot = ob->rot;
923         VECCOPY(td->ext->irot, ob->rot);
924         VECCOPY(td->ext->drot, ob->drot);
925         
926         td->ext->size = ob->size;
927         VECCOPY(td->ext->isize, ob->size);
928         VECCOPY(td->ext->dsize, ob->dsize);
929
930         VECCOPY(td->center, ob->obmat[3]);
931
932         Mat3CpyMat4(td->axismtx, ob->obmat);
933         Mat3Ortho(td->axismtx);
934
935         if (ob->parent)
936         {
937                 float totmat[3][3], obinv[3][3];
938                 
939                 /* we calculate smtx without obmat: so a parmat */
940                 object_to_mat3(ob, obmtx);
941                 Mat3CpyMat4(totmat, ob->obmat);
942                 Mat3Inv(obinv, totmat);
943                 Mat3MulMat3(td->smtx, obmtx, obinv);
944                 Mat3Inv(td->mtx, td->smtx);
945         }
946         else
947         {
948                 Mat3One(td->smtx);
949                 Mat3One(td->mtx);
950         }
951 }
952
953 /* only used in function below, stuff to be removed */
954 static Object *is_a_parent_selected_int(Object *startob, Object *ob, GHash *done_hash) 
955 {
956         if (ob!=startob && TESTBASE(ob))
957                 return ob;
958         
959         if (BLI_ghash_haskey(done_hash, ob))
960                 return NULL;
961         else
962                 BLI_ghash_insert(done_hash, ob, NULL);
963         
964         if (ob->parent) {
965                 Object *par= is_a_parent_selected_int(startob, ob->parent, done_hash);
966                 if (par)
967                         return par;
968         }
969         return NULL;
970 }
971
972 /* only used in function below, stuff to be removed */
973 static Object *is_a_parent_selected(Object *ob) 
974 {
975         GHash *gh= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
976         Object *res= is_a_parent_selected_int(ob, ob, gh);
977         BLI_ghash_free(gh, NULL, NULL);
978         
979         return res;
980 }
981
982
983
984 /* sets flags in Bases to define whether they take part in transform */
985 /* it deselects Bases, so we have to call the clear function always after */
986 static void set_trans_object_base_flags(TransInfo *t)
987 {
988         /*
989          if Base selected and has parent selected:
990          base->flag= BA_WASSEL+BA_PARSEL
991          if base not selected and parent selected:
992          base->flag= BA_PARSEL
993          */
994         GHash *object_to_base_hash= NULL; 
995         Base *base;
996         
997         /* moved to start of function, it is needed for hooks now too */
998         if (!object_to_base_hash) {
999                 Base *b;
1000                 object_to_base_hash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
1001                 
1002                 for (b= FIRSTBASE; b; b= b->next)
1003                         BLI_ghash_insert(object_to_base_hash, b->object, b);
1004         }
1005         
1006         /* makes sure base flags and object flags are identical */
1007         copy_baseflags();
1008         
1009         for (base= FIRSTBASE; base; base= base->next) {
1010                 base->flag &= ~(BA_PARSEL+BA_WASSEL);
1011                 
1012                 if( (base->lay & G.vd->lay) && base->object->id.lib==0) {
1013                         Object *ob= base->object;
1014                         Object *parsel= is_a_parent_selected(ob);
1015                         
1016                         /* parentkey here? */
1017                         
1018                         if(parsel) {
1019                                 if(base->flag & SELECT) {
1020                                         base->flag &= ~SELECT;
1021                                         base->flag |= (BA_PARSEL+BA_WASSEL);
1022                                 }
1023                                 else base->flag |= BA_PARSEL;
1024                         }
1025                         
1026                         if(t->mode==TFM_TRANSLATION)  {
1027                                 if(ob->track && TESTBASE(ob->track) && (base->flag & SELECT)==0)  
1028                                         base->flag |= BA_PARSEL;
1029                         }
1030                         
1031                         /* updates? */
1032                         if(ob->hooks.first) {
1033                                 Base *b;
1034                                 ObHook *hook= ob->hooks.first;
1035                                 
1036                                 while(hook) {
1037                                         if(hook->parent) {
1038                                                 Object *parsel= is_a_parent_selected(hook->parent);
1039                                                 
1040                                                 b= BLI_ghash_lookup(object_to_base_hash, hook->parent);
1041                                                 if(parsel || ((base->flag | b->flag) & (SELECT | BA_PARSEL)) ) {
1042                                                         base->flag |= BA_DISP_UPDATE;
1043                                                 }
1044                                         }
1045                                         hook= hook->next;
1046                                 }
1047                         }
1048                         
1049                         if(ob->parent && ob->parent->type==OB_LATTICE)
1050                                 if(ob->parent->hooks.first) base->flag |= BA_DISP_UPDATE;
1051                         
1052                         if(base->flag & (SELECT | BA_PARSEL)) {
1053                                 
1054                                 base->flag |= BA_WHERE_UPDATE;
1055                                 
1056                                 if(ob->parent) {
1057                                         if(ob->parent->type==OB_LATTICE) base->flag |= BA_DISP_UPDATE;
1058                                         else if(ob->partype==PARSKEL) {
1059                                                 if ELEM3(ob->parent->type, OB_IKA, OB_CURVE, OB_ARMATURE) 
1060                                                         base->flag |= BA_DISP_UPDATE;
1061                                         }
1062                                 }
1063                                 if(ob->track) {
1064                                         ;
1065                                 }
1066                                 
1067                                 if( give_parteff(ob) ) base->flag |= BA_DISP_UPDATE;
1068                                 
1069                                 if(ob->type==OB_MBALL) {
1070                                         Base *b;
1071                                         
1072                                         b= BLI_ghash_lookup(object_to_base_hash, find_basis_mball(ob));
1073                                         b->flag |= BA_DISP_UPDATE;
1074                                 }
1075                         }
1076                 }
1077         }
1078         
1079         if (object_to_base_hash)
1080                 BLI_ghash_free(object_to_base_hash, NULL, NULL);
1081         
1082 }
1083
1084 static void clear_trans_object_base_flags(void)
1085 {
1086         Base *base;
1087         
1088         base= FIRSTBASE;
1089         while(base) {
1090                 if(base->flag & BA_WASSEL) base->flag |= SELECT;
1091                 base->flag &= ~(BA_PARSEL+BA_WASSEL);
1092                 
1093                 base->flag &= ~(BA_DISP_UPDATE+BA_WHERE_UPDATE+BA_DO_IPO);
1094                 
1095                 /* pose here? */
1096                 if (base->object->pose) {
1097                         Object *ob= base->object;
1098                         bPoseChannel *chan;
1099                         for (chan = ob->pose->chanbase.first; chan; chan=chan->next) {
1100                                 chan->flag &= ~PCHAN_TRANS_UPDATE;
1101                         }
1102                 }
1103                 
1104                 base= base->next;
1105         }
1106         copy_baseflags();
1107 }
1108
1109
1110 static void createTransObject(void)
1111 {
1112         TransData *td = NULL;
1113         TransDataExtension *tx;
1114         Object *ob;
1115         Base *base;
1116         IpoKey *ik;
1117         ListBase elems;
1118         
1119         /* hackish... but we have to do it somewhere */
1120         reset_slowparents();
1121         
1122         set_trans_object_base_flags(&Trans);
1123         
1124         /* count */     
1125         for(base= FIRSTBASE; base; base= base->next) {
1126                 if TESTBASELIB(base) {
1127                         ob= base->object;
1128                         
1129                         /* store ipo keys? */
1130                         if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) {
1131                                 elems.first= elems.last= NULL;
1132                                 make_ipokey_transform(ob, &elems, 1); /* '1' only selected keys */
1133                                 
1134                                 pushdata(&elems, sizeof(ListBase));
1135                                 
1136                                 for(ik= elems.first; ik; ik= ik->next) Trans.total++;
1137
1138                                 if(elems.first==NULL) Trans.total++;
1139                         }
1140                         else {
1141                                 Trans.total++;
1142                         }
1143                 }
1144         }
1145
1146         if(!Trans.total) {
1147                 /* clear here, main transform function escapes too */
1148                 clear_trans_object_base_flags();
1149                 return;
1150         }
1151         
1152         td = Trans.data = MEM_mallocN(Trans.total*sizeof(TransData), "TransOb");
1153         tx = Trans.ext = MEM_mallocN(Trans.total*sizeof(TransDataExtension), "TransObExtension");
1154
1155         for(base= FIRSTBASE; base; base= base->next) {
1156                 if TESTBASELIB(base) {
1157                         ob= base->object;
1158                         
1159                         td->flag= TD_SELECTED;
1160                         td->ext = tx;
1161
1162                         /* store ipo keys? */
1163                         if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) {
1164                                 
1165                                 popfirst(&elems);       // bring back pushed listbase
1166                                 
1167                                 if(elems.first) {
1168                                         float cfraont;
1169                                         int ipoflag;
1170                                         
1171                                         base->flag |= BA_DO_IPO+BA_WASSEL;
1172                                         base->flag &= ~SELECT;
1173                                         
1174                                         cfraont= CFRA;
1175                                         set_no_parent_ipo(1);
1176                                         ipoflag= ob->ipoflag;
1177                                         ob->ipoflag &= ~OB_OFFS_OB;
1178                                         
1179                                         pushdata(ob->loc, 7*3*4); // tsk! tsk!
1180                                         
1181                                         for(ik= elems.first; ik; ik= ik->next) {
1182                                                 
1183                                                 /* weak... this doesn't correct for floating values, giving small errors */
1184                                                 CFRA= (short)(ik->val/G.scene->r.framelen);
1185                                                 
1186                                                 do_ob_ipo(ob);
1187                                                 ObjectToTransData(td, ob);      // does where_is_object()
1188                                                 
1189                                                 td->tdi= MEM_callocN(sizeof(TransDataIpokey), "TransDataIpokey");
1190                                                 /* also does tdi->flag and oldvals, needs to be after ob_to_transob()! */
1191                                                 ipokey_to_transdata(ik, td);
1192                                                 
1193                                                 td++;
1194                                                 tx++;
1195                                                 if(ik->next) td->ext= tx;       // prevent corrupting mem!
1196                                         }
1197                                         free_ipokey(&elems);
1198                                         
1199                                         poplast(ob->loc);
1200                                         set_no_parent_ipo(0);
1201                                         
1202                                         CFRA= (short)cfraont;
1203                                         ob->ipoflag= ipoflag;
1204                                 }
1205                                 else {
1206                                         ObjectToTransData(td, ob);
1207                                         td->tdi = NULL;
1208                                         td->val = NULL;
1209                                 }
1210                         }
1211                         else {
1212                                 ObjectToTransData(td, ob);
1213                                 td->tdi = NULL;
1214                                 td->val = NULL;
1215                         }
1216                         td++;
1217                         tx++;
1218                 }
1219         }
1220 }
1221
1222 static void createTransData(TransInfo *t) 
1223 {
1224         if( t->mode & TFM_TEX) {
1225                 t->flag |= T_TEXTURE;
1226                 createTransTexspace();
1227                 t->mode &= ~TFM_TEX;    // now becoming normal grab/rot/scale
1228         }
1229         else if (G.obpose) {
1230                 t->flag |= T_POSE;
1231                 createTransPose();
1232         }
1233         else if (G.obedit) {
1234                 if (G.obedit->type == OB_MESH) {
1235                         if(t->mode==TFM_SHRINKFATTEN) vertexnormals(0);
1236                         createTransEditVerts(); 
1237                 }
1238                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1239                         createTransCurveVerts();
1240                 }
1241                 else if (G.obedit->type==OB_LATTICE) {
1242                         createTransLatticeVerts();
1243                 }
1244                 else if (G.obedit->type==OB_MBALL) {
1245                         createTransMBallVerts();
1246                 }
1247                 else if (G.obedit->type==OB_ARMATURE) {
1248                         createTransArmatureVerts();
1249                 }                                                       
1250                 else {
1251                         printf("not done yet! only have mesh surface curve\n");
1252                 }
1253                 
1254                 if(G.f & G_PROPORTIONAL) {
1255                         sort_trans_data(t);     // makes selected become first in array
1256                         set_prop_dist(t);
1257                         sort_trans_data_dist(t);
1258                 }
1259                 t->flag |= T_EDIT;
1260         }
1261         else {
1262                 createTransObject();
1263                 t->flag |= T_OBJECT;
1264         }
1265 }
1266
1267 #define TRANS_CANCEL    2
1268 #define TRANS_CONFIRM   1
1269
1270 /* ************************** TRANSFORMATIONS **************************** */
1271
1272 void Transform(int mode) 
1273 {
1274         int ret_val = 0;
1275         short pmval[2] = {0, 0}, mval[2], val;
1276         float mati[3][3];
1277         unsigned short event;
1278         char cmode = '\0';
1279
1280         /*joeedh -> hopefully may be what makes the old transform() constant*/
1281         /* ton: I doubt, but it doesnt harm for now. shouldnt be needed though */
1282         areawinset(curarea->win);
1283
1284         Mat3One(mati);
1285
1286         /* stupid PET initialisation code */
1287         /* START */
1288         if (Trans.propsize == 0.0f) {
1289                 Trans.propsize = 1.0;
1290         }
1291         /* END */
1292
1293         if (mode == TFM_REPEAT) {
1294                 mode = LastMode;
1295         }
1296         else {
1297                 LastMode = mode;
1298         }
1299         
1300         initTransModeFlags(&Trans, mode);       // modal settings in struct Trans
1301
1302         initTrans(&Trans);                                      // internal data, mouse, vectors
1303
1304         createTransData(&Trans);                        // make TransData structs from selection
1305
1306         if (Trans.total == 0)
1307                 return;
1308
1309         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1310         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1311         mode= Trans.mode;
1312         
1313         calculatePropRatio(&Trans);
1314         calculateCenter(&Trans);
1315
1316         switch (mode) {
1317         case TFM_TRANSLATION:
1318                 initTranslation(&Trans);
1319                 break;
1320         case TFM_ROTATION:
1321                 initRotation(&Trans);
1322                 break;
1323         case TFM_RESIZE:
1324                 initResize(&Trans);
1325                 break;
1326         case TFM_TOSPHERE:
1327                 initToSphere(&Trans);
1328                 break;
1329         case TFM_SHEAR:
1330                 initShear(&Trans);
1331                 break;
1332         case TFM_WARP:
1333                 initWarp(&Trans);
1334                 break;
1335         case TFM_SHRINKFATTEN:
1336                 initShrinkFatten(&Trans);
1337                 break;
1338         case TFM_TILT:
1339                 initTilt(&Trans);
1340                 break;
1341         case TFM_TRACKBALL:
1342                 initTrackball(&Trans);
1343                 break;
1344         }
1345
1346         initConstraint(&Trans);
1347
1348         // Emptying event queue
1349         while( qtest() ) {
1350                 event= extern_qread(&val);
1351         }
1352
1353         Trans.redraw = 1;
1354
1355         while (ret_val == 0) {
1356
1357                 getmouseco_areawin(mval);
1358                 
1359                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1360                         Trans.redraw = 1;
1361                 }
1362                 if (Trans.redraw) {
1363                         pmval[0] = mval[0];
1364                         pmval[1] = mval[1];
1365
1366                         selectConstraint(&Trans);
1367                         if (Trans.transform) {
1368                                 Trans.transform(&Trans, mval);
1369                         }
1370                         Trans.redraw = 0;
1371                 }
1372                 
1373                 /* essential for idling subloop */
1374                 if( qtest()==0) PIL_sleep_ms(2);
1375
1376                 while( qtest() ) {
1377                         event= extern_qread(&val);
1378
1379                         if(val) {
1380                                 switch (event){
1381                                 /* enforce redraw of transform when modifiers are used */
1382                                 case LEFTCTRLKEY:
1383                                 case RIGHTCTRLKEY:
1384                                 case LEFTSHIFTKEY:
1385                                 case RIGHTSHIFTKEY:
1386                                         Trans.redraw = 1;
1387                                         break;
1388                                         
1389                                 case MIDDLEMOUSE:
1390                                         /* exception for switching to dolly, in camera view */
1391                                         if( (Trans.flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp>1) {
1392                                         //      setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
1393                                         }
1394                                         else 
1395                                                 initSelectConstraint(&Trans);
1396                                         Trans.redraw = 1;
1397                                         break;
1398                                 case ESCKEY:
1399                                 case RIGHTMOUSE:
1400                                         ret_val = TRANS_CANCEL;
1401                                         break;
1402                                 case LEFTMOUSE:
1403                                 case SPACEKEY:
1404                                 case PADENTER:
1405                                 case RETKEY:
1406                                         ret_val = TRANS_CONFIRM;
1407                                         break;
1408                                 case GKEY:
1409                                         restoreTransObjects(&Trans);
1410                                         initTransModeFlags(&Trans, TFM_TRANSLATION);
1411                                         initTranslation(&Trans);
1412                                         Trans.redraw = 1;
1413                                         break;
1414                                 case SKEY:
1415                                         restoreTransObjects(&Trans);
1416                                         initTransModeFlags(&Trans, TFM_RESIZE);
1417                                         initResize(&Trans);
1418                                         Trans.redraw = 1;
1419                                         break;
1420                                 case RKEY:
1421                                         restoreTransObjects(&Trans);
1422                                         initTransModeFlags(&Trans, TFM_ROTATION);
1423                                         initRotation(&Trans);
1424                                         Trans.redraw = 1;
1425                                         break;
1426                                 case XKEY:
1427                                         if (cmode == 'X') {
1428                                                 stopConstraint(&Trans);
1429                                                 cmode = '\0';
1430                                         }
1431                                         else if(cmode == 'x') {
1432                                                 if (G.qual == 0)
1433                                                         setLocalConstraint(&Trans, (CON_AXIS0), "along local X");
1434                                                 else if (G.qual == LR_SHIFTKEY)
1435                                                         setLocalConstraint(&Trans, (CON_AXIS1|CON_AXIS2), "locking local X");
1436
1437                                                 cmode = 'X';
1438                                         }
1439                                         else {
1440                                                 if (G.qual == 0)
1441                                                         setConstraint(&Trans, mati, (CON_AXIS0), "along global X");
1442                                                 else if (G.qual == LR_SHIFTKEY)
1443                                                         setConstraint(&Trans, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
1444
1445                                                 cmode = 'x';
1446                                         }
1447                                         Trans.redraw = 1;
1448                                         break;
1449                                 case YKEY:
1450                                         if (cmode == 'Y') {
1451                                                 stopConstraint(&Trans);
1452                                                 cmode = '\0';
1453                                         }
1454                                         else if(cmode == 'y') {
1455                                                 if (G.qual == 0)
1456                                                         setLocalConstraint(&Trans, (CON_AXIS1), "along global Y");
1457                                                 else if (G.qual == LR_SHIFTKEY)
1458                                                         setLocalConstraint(&Trans, (CON_AXIS0|CON_AXIS2), "locking global Y");
1459
1460                                                 cmode = 'Y';
1461                                         }
1462                                         else {
1463                                                 if (G.qual == 0)
1464                                                         setConstraint(&Trans, mati, (CON_AXIS1), "along local Y");
1465                                                 else if (G.qual == LR_SHIFTKEY)
1466                                                         setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS2), "locking local Y");
1467
1468                                                 cmode = 'y';
1469                                         }
1470                                         Trans.redraw = 1;
1471                                         break;
1472                                 case ZKEY:
1473                                         if (cmode == 'Z') {
1474                                                 stopConstraint(&Trans);
1475                                                 cmode = '\0';
1476                                         }
1477                                         else if(cmode == 'z') {
1478                                                 if (G.qual == 0)
1479                                                         setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
1480                                                 else if (G.qual == LR_SHIFTKEY)
1481                                                         setLocalConstraint(&Trans, (CON_AXIS0|CON_AXIS1), "locking local Z");
1482
1483                                                 cmode = 'Z';
1484                                         }
1485                                         else {
1486                                                 if (G.qual == 0)
1487                                                         setConstraint(&Trans, mati, (CON_AXIS2), "along global Z");
1488                                                 else if (G.qual == LR_SHIFTKEY)
1489                                                         setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
1490
1491                                                 cmode = 'z';
1492                                         }
1493                                         Trans.redraw = 1;
1494                                         break;
1495                                 case OKEY:
1496                                         if (G.qual==LR_SHIFTKEY) {
1497                                                 extern int prop_mode;
1498                                                 prop_mode = (prop_mode+1)%5;
1499                                                 calculatePropRatio(&Trans);
1500                                                 Trans.redraw= 1;
1501                                         }
1502                                         break;
1503                                 case WHEELDOWNMOUSE:
1504                                 case PADPLUSKEY:
1505                                         if(G.f & G_PROPORTIONAL) {
1506                                                 Trans.propsize*= 1.1f;
1507                                                 calculatePropRatio(&Trans);
1508                                                 Trans.redraw= 1;
1509                                         }
1510                                         break;
1511                                 case WHEELUPMOUSE:
1512                                 case PADMINUS:
1513                                         if(G.f & G_PROPORTIONAL) {
1514                                                 Trans.propsize*= 0.90909090f;
1515                                                 calculatePropRatio(&Trans);
1516                                                 Trans.redraw= 1;
1517                                         }
1518                                         break;
1519                                 }
1520                                 Trans.redraw |= handleNumInput(&(Trans.num), event);
1521                                 arrows_move_cursor(event);
1522                         }
1523                         else {
1524                                 switch (event){
1525                                 /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still 
1526                                    after releasing modifer key */
1527                                 case MIDDLEMOUSE:
1528                                         postSelectConstraint(&Trans);
1529                                         Trans.redraw = 1;
1530                                         break;
1531                                 case LEFTMOUSE:
1532                                 case RIGHTMOUSE:
1533                                         /* commented out, doesn't work for actions started with menu */
1534                                         // ret_val = TRANS_CONFIRM;
1535                                         break;
1536                                 }
1537                         }
1538                 }
1539         }
1540         
1541         
1542         if(ret_val == TRANS_CANCEL) {
1543                 restoreTransObjects(&Trans);
1544         }
1545         else {
1546                 BIF_undo_push("Transform");
1547         }
1548         
1549         /* free data, reset vars */
1550         postTrans(&Trans);
1551         
1552         /* mess from old transform, just for now (ton) */
1553         {
1554                 char cmode='g';
1555                 
1556                 if(mode==TFM_RESIZE) cmode= 's';
1557                 else if(mode==TFM_ROTATION) cmode= 'r';
1558                 /* aftertrans does displists, ipos and action channels */
1559                 /* 7 = keyflags, meaning do loc/rot/scale ipos. Not sure if I like the old method to detect what changed (ton) */
1560                 special_aftertrans_update(cmode, 0, (short)(ret_val == TRANS_CANCEL), 7);
1561                 
1562                 if(G.obedit==NULL && G.obpose==NULL)
1563                         clear_trans_object_base_flags();
1564         }
1565         
1566         
1567         /* send events out for redraws */
1568         allqueue(REDRAWVIEW3D, 0);
1569         allqueue(REDRAWBUTSOBJECT, 0);
1570         scrarea_queue_headredraw(curarea);
1571 }
1572
1573 void ManipulatorTransform(int mode) 
1574 {
1575         int ret_val = 0;
1576         short pmval[2] = {0, 0}, mval[2], val;
1577         unsigned short event;
1578
1579
1580         /* stupid PET initialisation code */
1581         /* START */
1582         if (Trans.propsize == 0.0f) {
1583                 Trans.propsize = 1.0;
1584         }
1585         /* END */
1586
1587         initTransModeFlags(&Trans, mode);       // modal settings in struct Trans
1588
1589         initTrans(&Trans);                                      // internal data, mouse, vectors
1590         G.moving |= G_TRANSFORM_MANIP;          // signal to draw manipuls while transform
1591         createTransData(&Trans);                        // make TransData structs from selection
1592
1593         if (Trans.total == 0)
1594                 return;
1595
1596         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1597         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1598         mode= Trans.mode;
1599         
1600         calculatePropRatio(&Trans);
1601         calculateCenter(&Trans);
1602
1603         switch (mode) {
1604         case TFM_TRANSLATION:
1605                 initTranslation(&Trans);
1606                 break;
1607         case TFM_ROTATION:
1608                 initRotation(&Trans);
1609                 break;
1610         case TFM_RESIZE:
1611                 initResize(&Trans);
1612                 break;
1613         case TFM_TRACKBALL:
1614                 initTrackball(&Trans);
1615                 break;
1616         }
1617
1618         initConstraint(&Trans);
1619         
1620         Trans.flag |= T_USES_MANIPULATOR;
1621         Trans.redraw = 1;
1622
1623         while (ret_val == 0) {
1624                 
1625                 getmouseco_areawin(mval);
1626                 
1627                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1628                         Trans.redraw = 1;
1629                 }
1630                 if (Trans.redraw) {
1631                         pmval[0] = mval[0];
1632                         pmval[1] = mval[1];
1633
1634                         //selectConstraint(&Trans);  needed?
1635                         if (Trans.transform) {
1636                                 Trans.transform(&Trans, mval);
1637                         }
1638                         Trans.redraw = 0;
1639                 }
1640                 
1641                 /* essential for idling subloop */
1642                 if( qtest()==0) PIL_sleep_ms(2);
1643
1644                 while( qtest() ) {
1645                         event= extern_qread(&val);
1646
1647                         switch (event){
1648                         /* enforce redraw of transform when modifiers are used */
1649                         case LEFTCTRLKEY:
1650                         case RIGHTCTRLKEY:
1651                         case LEFTSHIFTKEY:
1652                         case RIGHTSHIFTKEY:
1653                                 if(val) Trans.redraw = 1;
1654                                 break;
1655                                 
1656                         case ESCKEY:
1657                         case RIGHTMOUSE:
1658                                 ret_val = TRANS_CANCEL;
1659                                 break;
1660                         case LEFTMOUSE:
1661                         case SPACEKEY:
1662                         case PADENTER:
1663                         case RETKEY:
1664                                 ret_val = TRANS_CONFIRM;
1665                                 break;
1666                         }
1667                         if(val) {
1668                                 switch(event) {
1669                                 case WHEELDOWNMOUSE:
1670                                 case PADPLUSKEY:
1671                                         if(G.f & G_PROPORTIONAL) {
1672                                                 Trans.propsize*= 1.1f;
1673                                                 calculatePropRatio(&Trans);
1674                                                 Trans.redraw= 1;
1675                                         }
1676                                         break;
1677                                 case WHEELUPMOUSE:
1678                                 case PADMINUS:
1679                                         if(G.f & G_PROPORTIONAL) {
1680                                                 Trans.propsize*= 0.90909090f;
1681                                                 calculatePropRatio(&Trans);
1682                                                 Trans.redraw= 1;
1683                                         }
1684                                         break;
1685                                 }                       
1686                         }
1687                 }
1688         }
1689         
1690         if(ret_val == TRANS_CANCEL) {
1691                 restoreTransObjects(&Trans);
1692         }
1693         else {
1694                 BIF_undo_push("Transform");
1695         }
1696         
1697         /* free data, reset vars */
1698         postTrans(&Trans);
1699         
1700         /* mess from old transform, just for now (ton) */
1701         {
1702                 char cmode='g';
1703                 
1704                 if(mode==TFM_RESIZE) cmode= 's';
1705                 else if(mode==TFM_ROTATION) cmode= 'r';
1706                 /* aftertrans does displists, ipos and action channels */
1707                 /* 7 = keyflags, meaning do loc/rot/scale ipos. Not sure if I like the old method to detect what changed (ton) */
1708                 special_aftertrans_update(cmode, 0, (short)(ret_val == TRANS_CANCEL), 7);
1709                 
1710                 if(G.obedit==NULL && G.obpose==NULL)
1711                         clear_trans_object_base_flags();
1712         }
1713         
1714         /* send events out for redraws */
1715         allqueue(REDRAWVIEW3D, 0);
1716         allqueue(REDRAWBUTSOBJECT, 0);
1717         scrarea_queue_headredraw(curarea);
1718 }
1719
1720
1721
1722 /* ************************** WRAP *************************** */
1723
1724 /* warp is done fully in view space */
1725 void initWarp(TransInfo *t) 
1726 {
1727         float max[3], min[3];
1728         int i;
1729         
1730         calculateCenterCursor(t);
1731         t->idx_max = 0;
1732         t->num.idx_max = 0;
1733         t->transform = Warp;
1734         t->snap[0] = 0.0f;
1735         t->snap[1] = 5.0f;
1736         t->snap[2] = 1.0f;
1737         
1738         t->fac = (float)(t->center2d[0] - t->imval[0]);
1739         
1740         /* we need min/max in view space */
1741         for(i = 0; i < t->total; i++) {
1742                 float center[3];
1743                 VECCOPY(center, t->data[i].center);
1744                 Mat3MulVecfl(t->data[i].mtx, center);
1745                 Mat4MulVecfl(G.vd->viewmat, center);
1746                 VecSubf(center, center, G.vd->viewmat[3]);
1747                 if (i)
1748                         MinMax3(min, max, center);
1749                 else {
1750                         VECCOPY(max, center);
1751                         VECCOPY(min, center);
1752                 }
1753         }
1754
1755         t->center[0]= (min[0]+max[0])/2.0f;
1756         t->center[1]= (min[1]+max[1])/2.0f;
1757         t->center[2]= (min[2]+max[2])/2.0f;
1758         
1759         t->val= (max[0]-min[0])/2.0f;   // t->val is free variable
1760 }
1761
1762
1763 int Warp(TransInfo *t, short mval[2])
1764 {
1765         TransData *td = t->data;
1766         float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
1767         int i;
1768         char str[50];
1769         
1770         curs= give_cursor();
1771         /*
1772          * gcursor is the one used for helpline.
1773          * It has to be in the same space as the drawing loop
1774          * (that means it needs to be in the object's space when in edit mode and
1775          *  in global space in object mode)
1776          *
1777          * cursor is used for calculations.
1778          * It needs to be in view space, but we need to take object's offset
1779          * into account if in Edit mode.
1780          */
1781         VECCOPY(cursor, curs);
1782         VECCOPY(gcursor, cursor);       
1783         if (t->flag & T_EDIT) {
1784                 VecSubf(cursor, cursor, G.obedit->obmat[3]);
1785                 VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
1786                 Mat3MulVecfl(t->data->smtx, gcursor);
1787         }
1788         Mat4MulVecfl(G.vd->viewmat, cursor);
1789         VecSubf(cursor, cursor, G.vd->viewmat[3]);
1790
1791         // amount of degrees for warp, 450 = allow to create 360 degree warp
1792         circumfac= 450.0f*(mval[1] - t->imval[1]) / (float)(curarea->winy);
1793         circumfac+= 90.0f;
1794
1795         snapGrid(t, &circumfac);
1796         applyNumInput(&t->num, &circumfac);
1797         
1798         /* header print for NumInput */
1799         if (hasNumInput(&t->num)) {
1800                 char c[20];
1801                 
1802                 outputNumInput(&(t->num), c);
1803                 
1804                 sprintf(str, "Warp: %s", c);
1805         }
1806         else {
1807                 /* default header print */
1808                 sprintf(str, "Warp: %.3f", circumfac);
1809         }
1810         
1811         circumfac*= (float)(-M_PI/360.0);
1812         
1813         for(i = 0 ; i < t->total; i++, td++) {
1814                 float loc[3];
1815                 if (td->flag & TD_NOACTION)
1816                         break;
1817
1818                 /* translate point to centre, rotate in such a way that outline==distance */
1819                 
1820                 VECCOPY(vec, td->iloc);
1821                 Mat3MulVecfl(td->mtx, vec);
1822                 Mat4MulVecfl(G.vd->viewmat, vec);
1823                 VecSubf(vec, vec, G.vd->viewmat[3]);
1824                 
1825                 dist= vec[0]-cursor[0];
1826
1827                 phi0= (circumfac*dist/t->val);  // t->val is X dimension projected boundbox
1828                 
1829                 vec[1]= (vec[1]-cursor[1]);
1830                 
1831                 co= (float)cos(phi0);
1832                 si= (float)sin(phi0);
1833                 loc[0]= -si*vec[1]+cursor[0];
1834                 loc[1]= co*vec[1]+cursor[1];
1835                 loc[2]= vec[2];
1836                 
1837                 Mat4MulVecfl(G.vd->viewinv, loc);
1838                 VecSubf(loc, loc, G.vd->viewinv[3]);
1839                 Mat3MulVecfl(td->smtx, loc);
1840
1841                 VecSubf(loc, loc, td->iloc);
1842                 VecMulf(loc, td->factor);
1843                 VecAddf(td->loc, td->iloc, loc);
1844         }
1845
1846         recalcData(t);
1847         
1848         headerprint(str);
1849         
1850         force_draw(0);
1851         
1852         helpline(gcursor);
1853         
1854         return 1;
1855 }
1856
1857 /* ************************** SHEAR *************************** */
1858
1859 void initShear(TransInfo *t) 
1860 {
1861         t->idx_max = 0;
1862         t->num.idx_max = 0;
1863         t->snap[0] = 0.0f;
1864         t->snap[1] = G.vd->grid * 0.1f;
1865         t->snap[2] = t->snap[1] * 0.1f;
1866         t->transform = Shear;
1867         t->fac = (float)(t->center2d[0] - t->imval[0]);
1868 }
1869
1870 int Shear(TransInfo *t, short mval[2]) 
1871 {
1872         TransData *td = t->data;
1873         float vec[3];
1874         float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
1875         float value;
1876         int i;
1877         char str[50];
1878
1879         Mat3CpyMat4(persmat, G.vd->viewmat);
1880         Mat3Inv(persinv, persmat);
1881
1882         value = -0.005f * ((float)(t->center2d[0] - mval[0]) - t->fac);
1883
1884         snapGrid(t, &value);
1885
1886         applyNumInput(&t->num, &value);
1887
1888         /* header print for NumInput */
1889         if (hasNumInput(&t->num)) {
1890                 char c[20];
1891
1892                 outputNumInput(&(t->num), c);
1893
1894                 sprintf(str, "Shear: %s %s", c, t->proptext);
1895         }
1896         else {
1897                 /* default header print */
1898                 sprintf(str, "Shear: %.3f %s", value, t->proptext);
1899         }
1900         
1901         Mat3One(smat);
1902         smat[1][0] = value;
1903         Mat3MulMat3(tmat, smat, persmat);
1904         Mat3MulMat3(totmat, persinv, tmat);
1905         
1906         for(i = 0 ; i < t->total; i++, td++) {
1907                 if (td->flag & TD_NOACTION)
1908                         break;
1909
1910                 if (G.obedit) {
1911                         float mat3[3][3];
1912                         Mat3MulMat3(mat3, totmat, td->mtx);
1913                         Mat3MulMat3(tmat, td->smtx, mat3);
1914                 }
1915                 else {
1916                         Mat3CpyMat3(tmat, totmat);
1917                 }
1918                 VecSubf(vec, td->center, t->center);
1919
1920                 Mat3MulVecfl(tmat, vec);
1921
1922                 VecAddf(vec, vec, t->center);
1923                 VecSubf(vec, vec, td->center);
1924
1925                 VecMulf(vec, td->factor);
1926
1927                 VecAddf(td->loc, td->iloc, vec);
1928         }
1929
1930         recalcData(t);
1931
1932         headerprint(str);
1933
1934         force_draw(0);
1935
1936         helpline (t->center);
1937
1938         return 1;
1939 }
1940
1941 /* ************************** RESIZE *************************** */
1942
1943 void initResize(TransInfo *t) 
1944 {
1945         t->fac = (float)sqrt( (float)
1946                 (
1947                         (t->center2d[1] - t->imval[1])*(t->center2d[1] - t->imval[1])
1948                 +
1949                         (t->center2d[0] - t->imval[0])*(t->center2d[0] - t->imval[0])
1950                 ) );
1951
1952         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
1953         
1954         t->idx_max = 2;
1955         t->num.idx_max = 2;
1956         t->snap[0] = 0.0f;
1957         t->snap[1] = G.vd->grid * 0.1f;
1958         t->snap[2] = t->snap[1] * 0.1f;
1959         t->transform = Resize;
1960 }
1961
1962 static void headerResize(TransInfo *t, float vec[3], char *str) {
1963         char tvec[60];
1964         if (hasNumInput(&t->num)) {
1965                 outputNumInput(&(t->num), tvec);
1966         }
1967         else {
1968                 sprintf(&tvec[0], "%.4f", vec[0]);
1969                 sprintf(&tvec[20], "%.4f", vec[1]);
1970                 sprintf(&tvec[40], "%.4f", vec[2]);
1971         }
1972
1973         if (t->con.mode & CON_APPLY) {
1974                 switch(t->num.idx_max) {
1975                 case 0:
1976                         sprintf(str, "Size: %s%s %s", &tvec[0], t->con.text, t->proptext);
1977                         break;
1978                 case 1:
1979                         sprintf(str, "Size: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
1980                         break;
1981                 case 2:
1982                         sprintf(str, "Size: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1983                 }
1984         }
1985         else {
1986                 sprintf(str, "Size X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
1987         }
1988 }
1989
1990 int Resize(TransInfo *t, short mval[2]) 
1991 {
1992         TransData *td = t->data;
1993         float vec[3];
1994         float size[3], mat[3][3], tmat[3][3];
1995         float ratio;
1996         int i;
1997         char str[50];
1998
1999         /* for manipulator, center handle, the scaling can't be done relative to center */
2000         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
2001                 ratio = 1.0f - ((t->center2d[0] - mval[0]) + (t->center2d[1] - mval[1]))/100.0f;
2002         }
2003         else {
2004                 ratio = (float)sqrt( (float)
2005                         (
2006                                 (t->center2d[1] - mval[1])*(t->center2d[1] - mval[1])
2007                         +
2008                                 (t->center2d[0] - mval[0])*(t->center2d[0] - mval[0])
2009                         ) ) / t->fac;
2010         }
2011
2012         if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) < 0)
2013                 ratio *= -1.0f;
2014         
2015         size[0] = size[1] = size[2] = ratio;
2016
2017         snapGrid(t, size);
2018
2019         if (hasNumInput(&t->num)) {
2020                 applyNumInput(&t->num, size);
2021                 constraintNumInput(t, size);
2022         }
2023
2024         SizeToMat3(size, mat);
2025
2026         if (t->con.applySize) {
2027                 t->con.applySize(t, NULL, mat);
2028         }
2029
2030         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2031         
2032         headerResize(t, size, str);
2033
2034         for(i = 0 ; i < t->total; i++, td++) {
2035                 float smat[3][3];
2036                 if (td->flag & TD_NOACTION)
2037                         break;
2038
2039
2040                 if (t->flag & T_EDIT) {
2041                         Mat3MulMat3(smat, mat, td->mtx);
2042                         Mat3MulMat3(tmat, td->smtx, smat);
2043                 }
2044                 else {
2045                         Mat3CpyMat3(tmat, mat);
2046                 }
2047
2048                 if (t->con.applySize) {
2049                         t->con.applySize(t, td, tmat);
2050                 }
2051
2052                 if (G.vd->around == V3D_LOCAL) {
2053                         VECCOPY(t->center, td->center);
2054                 }
2055
2056                 if (td->ext) {
2057                         float fsize[3];
2058
2059                         if (t->flag & T_OBJECT) {
2060                                 float obsizemat[3][3];
2061                                 // Reorient the size mat to fit the oriented object.
2062                                 Mat3MulMat3(obsizemat, tmat, td->axismtx);
2063                                 Mat3ToSize(obsizemat, fsize);
2064                         }
2065                         else {
2066                                 Mat3ToSize(tmat, fsize);
2067                         }
2068                         
2069                         if ((G.vd->flag & V3D_ALIGN)==0) {      // align mode doesn't rotate objects itself
2070                                 /* handle ipokeys? */
2071                                 if(td->tdi) {
2072                                         TransDataIpokey *tdi= td->tdi;
2073                                         /* calculate delta size (equal for size and dsize) */
2074                                         
2075                                         // commented out for now
2076                                         vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
2077                                         vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
2078                                         vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
2079                                         
2080                                         add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
2081                                         add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
2082                                         add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
2083                                         
2084                                 }
2085                                 else {
2086                                         td->ext->size[0] = td->ext->isize[0] + td->ext->isize[0] * (fsize[0] - 1.0f) * td->factor;
2087                                         td->ext->size[1] = td->ext->isize[1] + td->ext->isize[1] * (fsize[1] - 1.0f) * td->factor;
2088                                         td->ext->size[2] = td->ext->isize[2] + td->ext->isize[2] * (fsize[2] - 1.0f) * td->factor;
2089                                 }
2090                         }
2091                 }
2092                 VecSubf(vec, td->center, t->center);
2093
2094                 Mat3MulVecfl(tmat, vec);
2095
2096                 VecAddf(vec, vec, t->center);
2097                 VecSubf(vec, vec, td->center);
2098
2099                 VecMulf(vec, td->factor);
2100
2101                 if (t->flag & T_OBJECT) {
2102                         Mat3MulVecfl(td->smtx, vec);
2103                 }
2104
2105                 VecAddf(td->loc, td->iloc, vec);
2106         }
2107
2108         recalcData(t);
2109
2110         headerprint(str);
2111
2112         force_draw(0);
2113
2114         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
2115
2116         return 1;
2117 }
2118
2119 /* ************************** TOSPHERE *************************** */
2120
2121 void initToSphere(TransInfo *t) 
2122 {
2123         TransData *td = t->data;
2124         int i;
2125
2126         // Calculate average radius
2127         for(i = 0 ; i < t->total; i++, td++) {
2128                 t->val += VecLenf(t->center, td->iloc);
2129         }
2130
2131         t->val /= (float)t->total;
2132
2133         Trans.fac = (float)sqrt( (float)
2134                 (
2135                         (Trans.center2d[1] - Trans.imval[1])*(Trans.center2d[1] - Trans.imval[1])
2136                 +
2137                         (Trans.center2d[0] - Trans.imval[0])*(Trans.center2d[0] - Trans.imval[0])
2138                 ) );
2139
2140         t->idx_max = 0;
2141         t->num.idx_max = 0;
2142         t->snap[0] = 0.0f;
2143         t->snap[1] = G.vd->grid * 0.1f;
2144         t->snap[2] = t->snap[1] * 0.1f;
2145         t->transform = ToSphere;
2146 }
2147
2148
2149
2150 int ToSphere(TransInfo *t, short mval[2]) 
2151 {
2152         float vec[3];
2153         float ratio, radius;
2154         int i;
2155         char str[50];
2156         TransData *td = t->data;
2157
2158         ratio = (float)sqrt( (float)
2159                 (
2160                         (t->center2d[1] - mval[1])*(t->center2d[1] - mval[1])
2161                 +
2162                         (t->center2d[0] - mval[0])*(t->center2d[0] - mval[0])
2163                 ) ) / t->fac;
2164
2165         snapGrid(t, &ratio);
2166
2167         applyNumInput(&t->num, &ratio);
2168
2169         if (ratio > 1.0f)
2170                 ratio = 1.0f;
2171
2172         /* header print for NumInput */
2173         if (hasNumInput(&t->num)) {
2174                 char c[20];
2175
2176                 outputNumInput(&(t->num), c);
2177
2178                 sprintf(str, "To Sphere: %s %s", c, t->proptext);
2179         }
2180         else {
2181                 /* default header print */
2182                 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
2183         }
2184         
2185         
2186         for(i = 0 ; i < t->total; i++, td++) {
2187                 float tratio;
2188                 if (td->flag & TD_NOACTION)
2189                         break;
2190
2191                 VecSubf(vec, td->iloc, t->center);
2192
2193                 radius = Normalise(vec);
2194
2195                 tratio = 1.0f - ((1.0f - ratio) * td->factor);
2196
2197                 VecMulf(vec, radius * tratio + t->val * (1.0f - tratio));
2198
2199                 VecAddf(td->loc, t->center, vec);
2200         }
2201
2202         recalcData(t);
2203
2204         headerprint(str);
2205
2206         force_draw(0);
2207
2208         helpline (t->center);
2209
2210         return 1;
2211 }
2212
2213 /* ************************** ROTATION *************************** */
2214
2215
2216 void initRotation(TransInfo *t) 
2217 {
2218         t->idx_max = 0;
2219         t->num.idx_max = 0;
2220         t->snap[0] = 0.0f;
2221         t->snap[1] = G.vd->grid * (float)((5.0/180)*M_PI);
2222         t->snap[2] = t->snap[1] * 0.2f;
2223         t->fac = 0;
2224         t->transform = Rotation;
2225 }
2226
2227 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
2228         float vec[3], totmat[3][3], smat[3][3];
2229         if (t->flag & T_EDIT) {
2230                 Mat3MulMat3(totmat, mat, td->mtx);
2231                 Mat3MulMat3(smat, td->smtx, totmat);
2232                 
2233                 VecSubf(vec, td->iloc, t->center);
2234                 Mat3MulVecfl(smat, vec);
2235                 
2236                 VecAddf(td->loc, vec, t->center);
2237         }
2238         else {
2239                 float eul[3], fmat[3][3];
2240                 
2241                 /* translation */
2242                 VecSubf(vec, td->center, t->center);
2243                 Mat3MulVecfl(mat, vec);
2244                 VecAddf(vec, vec, t->center);
2245                 /* vec now is the location where the object has to be */
2246                 VecSubf(vec, vec, td->center);
2247                 Mat3MulVecfl(td->smtx, vec);
2248                 
2249                 VecAddf(td->loc, td->iloc, vec);
2250                 
2251                 if(td->flag & TD_USEQUAT) {
2252                         float quat[4];
2253                         
2254                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2255                         
2256                         Mat3ToQuat(fmat, quat); // Actual transform
2257                         
2258                         QuatMul(td->ext->quat, quat, td->ext->iquat);
2259                 }
2260                 else if ((G.vd->flag & V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2261                         float obmat[3][3];
2262                         
2263                         /* are there ipo keys? */
2264                         if(td->tdi) {
2265                                 TransDataIpokey *tdi= td->tdi;
2266                                 float rot[3];
2267                                 
2268                                 /* calculate the total rotatation in eulers */
2269                                 VecAddf(eul, td->ext->irot, td->ext->drot);
2270                                 EulToMat3(eul, obmat);
2271                                 /* mat = transform, obmat = object rotation */
2272                                 Mat3MulMat3(fmat, mat, obmat);
2273                                 Mat3ToEul(fmat, eul);
2274                                 compatible_eul(eul, td->ext->irot);
2275                                 
2276                                 /* correct back for delta rot */
2277                                 if(tdi->flag & TOB_IPODROT) {
2278                                         VecSubf(rot, eul, td->ext->irot);
2279                                 }
2280                                 else {
2281                                         VecSubf(rot, eul, td->ext->drot);
2282                                 }
2283                                 
2284                                 VecMulf(rot, (float)(9.0/M_PI_2));
2285                                 VecSubf(rot, rot, tdi->oldrot);
2286                                 
2287                                 add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
2288                                 add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
2289                                 add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
2290                         }
2291                         else {
2292                                 
2293                                 /* calculate the total rotatation in eulers */
2294                                 VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
2295                                 EulToMat3(eul, obmat);
2296                                 /* mat = transform, obmat = object rotation */
2297                                 Mat3MulMat3(fmat, mat, obmat);
2298                                 Mat3ToEul(fmat, eul);
2299                                 compatible_eul(eul, td->ext->irot);
2300                                 
2301                                 /* correct back for delta rot */
2302                                 VecSubf(eul, eul, td->ext->drot);
2303                                 /* and apply */
2304                                 VECCOPY(td->ext->rot, eul);
2305                         }
2306                 }
2307         }
2308 }
2309
2310 static void applyRotation(TransInfo *t, float angle, float axis[3]) 
2311 {
2312         TransData *td = t->data;
2313         float mat[3][3];
2314         int i;
2315
2316         VecRotToMat3(axis, angle, mat);
2317
2318         for(i = 0 ; i < t->total; i++, td++) {
2319                 if (td->flag & TD_NOACTION)
2320                         break;
2321                 
2322                 if (G.vd->around == V3D_LOCAL) {
2323                         VECCOPY(t->center, td->center);
2324                 }
2325                 
2326                 if (t->con.applyRot) {
2327                         t->con.applyRot(t, td, axis);
2328                         VecRotToMat3(axis, angle * td->factor, mat);
2329                 }
2330                 else if (G.f & G_PROPORTIONAL) {
2331                         VecRotToMat3(axis, angle * td->factor, mat);
2332                 }
2333
2334                 ElementRotation(t, td, mat);
2335         }
2336 }
2337
2338 int Rotation(TransInfo *t, short mval[2]) 
2339 {
2340         TransData *td = t->data;
2341         char str[50];
2342
2343         float final;
2344
2345         int dx2 = t->center2d[0] - mval[0];
2346         int dy2 = t->center2d[1] - mval[1];
2347         float B = (float)sqrt(dx2*dx2+dy2*dy2);
2348
2349         int dx1 = t->center2d[0] - t->imval[0];
2350         int dy1 = t->center2d[1] - t->imval[1];
2351         float A = (float)sqrt(dx1*dx1+dy1*dy1);
2352
2353         int dx3 = mval[0] - t->imval[0];
2354         int dy3 = mval[1] - t->imval[1];
2355
2356         float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
2357                 / (2 * (A*B?A*B:1.0f));
2358         /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
2359
2360         float dphi;
2361
2362         float axis[3];
2363         float mat[3][3];
2364
2365         VECCOPY(axis, G.vd->persinv[2]);
2366         Normalise(axis);
2367
2368         dphi = saacos(deler);
2369         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
2370
2371         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2372         else t->fac += dphi;
2373
2374         /*
2375         clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
2376         if (t->fac >= 2 * M_PI)
2377                 t->fac -= 2 * M_PI;
2378         else if (t->fac <= -2 * M_PI)
2379                 t->fac -= -2 * M_PI;
2380         */
2381
2382         final = t->fac;
2383
2384         snapGrid(t, &final);
2385
2386         t->imval[0] = mval[0];
2387         t->imval[1] = mval[1];
2388
2389         if (t->con.applyRot) {
2390                 t->con.applyRot(t, NULL, axis);
2391         }
2392
2393         if (hasNumInput(&t->num)) {
2394                 char c[20];
2395
2396                 applyNumInput(&t->num, &final);
2397
2398                 outputNumInput(&(t->num), c);
2399
2400                 sprintf(str, "Rot: %s %s", &c[0], t->proptext);
2401
2402                 final *= (float)(M_PI / 180.0);
2403         }
2404         else {
2405                 sprintf(str, "Rot: %.2f %s", 180.0*final/M_PI, t->proptext);
2406         }
2407
2408         //printf("Axis %f %f %f\n", axis[0], axis[1], axis[2]);
2409         VecRotToMat3(axis, final * td->factor, mat);
2410
2411         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2412         
2413         applyRotation(t, final, axis);
2414         
2415         recalcData(t);
2416
2417         headerprint(str);
2418
2419         force_draw(0);
2420
2421         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
2422
2423         return 1;
2424 }
2425
2426
2427 /* ************************** TRACKBALL *************************** */
2428
2429 void initTrackball(TransInfo *t) 
2430 {
2431         t->idx_max = 1;
2432         t->num.idx_max = 1;
2433         t->snap[0] = 0.0f;
2434         t->snap[1] = G.vd->grid * (float)((5.0/180)*M_PI);
2435         t->snap[2] = t->snap[1] * 0.2f;
2436         t->fac = 0;
2437         t->transform = Trackball;
2438 }
2439
2440 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
2441 {
2442         TransData *td = t->data;
2443         float mat[3][3], smat[3][3], totmat[3][3];
2444         int i;
2445
2446         VecRotToMat3(axis1, angles[0], smat);
2447         VecRotToMat3(axis2, angles[1], totmat);
2448         
2449         Mat3MulMat3(mat, smat, totmat);
2450
2451         for(i = 0 ; i < t->total; i++, td++) {
2452                 if (td->flag & TD_NOACTION)
2453                         break;
2454                 
2455                 if (G.vd->around == V3D_LOCAL) {
2456                         VECCOPY(t->center, td->center);
2457                 }
2458                 
2459                 if (G.f & G_PROPORTIONAL) {
2460                         VecRotToMat3(axis1, td->factor * angles[0], smat);
2461                         VecRotToMat3(axis2, td->factor * angles[1], totmat);
2462                         
2463                         Mat3MulMat3(mat, smat, totmat);
2464                 }
2465
2466                 ElementRotation(t, td, mat);
2467         }
2468 }
2469
2470 int Trackball(TransInfo *t, short mval[2]) 
2471 {
2472         char str[50];
2473         float axis1[3], axis2[3];
2474         float mat[3][3], totmat[3][3], smat[3][3];
2475         float phi[2];
2476         
2477         VECCOPY(axis1, G.vd->persinv[0]);
2478         VECCOPY(axis2, G.vd->persinv[1]);
2479         Normalise(axis1);
2480         Normalise(axis2);
2481         
2482         /* factore has to become setting or so */
2483         phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
2484         phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
2485         
2486         //if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2487         //else t->fac += dphi;
2488         
2489         snapGrid(t, phi);
2490         
2491         if (hasNumInput(&t->num)) {
2492                 //char c[20];
2493                 
2494                 //applyNumInput(&t->num, phi);
2495                 
2496                 //outputNumInput(&(t->num), c);
2497                 
2498                 //sprintf(str, "Trackball: %s %s", &c[0], t->proptext);
2499                 
2500                 //final *= (float)(M_PI / 180.0);
2501         }
2502         else {
2503                 sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
2504         }
2505         
2506         VecRotToMat3(axis1, phi[0], smat);
2507         VecRotToMat3(axis2, phi[1], totmat);
2508         
2509         Mat3MulMat3(mat, smat, totmat);
2510         
2511         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2512         
2513         applyTrackball(t, axis1, axis2, phi);
2514         
2515         recalcData(t);
2516         
2517         headerprint(str);
2518         
2519         force_draw(0);
2520         
2521         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
2522         
2523         return 1;
2524 }
2525
2526 /* ************************** TRANSLATION *************************** */
2527         
2528 void initTranslation(TransInfo *t) 
2529 {
2530         t->idx_max = 2;
2531         t->num.idx_max = 2;
2532         t->snap[0] = 0.0f;
2533         t->snap[1] = G.vd->grid * 1.0f;
2534         t->snap[2] = t->snap[1] * 0.1f;
2535         t->transform = Translation;
2536         
2537         /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
2538         if (G.obedit) {
2539                 float vec[3];
2540                 
2541                 VECCOPY(vec, t->center);
2542                 Mat4MulVecfl(G.obedit->obmat, vec);
2543                 initgrabz(vec[0], vec[1], vec[2]);
2544         }
2545         else initgrabz(t->center[0], t->center[1], t->center[2]); 
2546 }
2547
2548 static void headerTranslation(TransInfo *t, float vec[3], char *str) {
2549         char tvec[60];
2550         if (hasNumInput(&t->num)) {
2551                 outputNumInput(&(t->num), tvec);
2552         }
2553         else {
2554                 sprintf(&tvec[0], "%.4f", vec[0]);
2555                 sprintf(&tvec[20], "%.4f", vec[1]);
2556                 sprintf(&tvec[40], "%.4f", vec[2]);
2557         }
2558
2559         if (t->con.mode & CON_APPLY) {
2560                 switch(t->num.idx_max) {
2561                 case 0:
2562                         sprintf(str, "D: %s%s %s", &tvec[0], t->con.text, t->proptext);
2563                         break;
2564                 case 1:
2565                         sprintf(str, "D: %s   D: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2566                         break;
2567                 case 2:
2568                         sprintf(str, "D: %s   D: %s  D: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2569                 }
2570         }
2571         else {
2572                 sprintf(str, "Dx: %s   Dy: %s  Dz: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2573         }
2574 }
2575
2576 static void applyTranslation(TransInfo *t, float vec[3]) {
2577         TransData *td = t->data;
2578         float tvec[3];
2579         int i;
2580
2581         for(i = 0 ; i < t->total; i++, td++) {
2582                 if (td->flag & TD_NOACTION)
2583                         break;
2584
2585                 if (t->con.applyVec) {
2586                         float pvec[3];
2587                         t->con.applyVec(t, td, vec, tvec, pvec);
2588                 }
2589                 else {
2590                         VECCOPY(tvec, vec);
2591                 }
2592
2593                 Mat3MulVecfl(td->smtx, tvec);
2594                 VecMulf(tvec, td->factor);
2595                 
2596                 /* transdata ipokey */
2597                 if(td->tdi) {
2598                         TransDataIpokey *tdi= td->tdi;
2599                         add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
2600                         add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
2601                         add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
2602                 }
2603                 else VecAddf(td->loc, td->iloc, tvec);
2604         }
2605 }
2606
2607 /* uses t->vec to store actual translation in */
2608 int Translation(TransInfo *t, short mval[2]) 
2609 {
2610         float tvec[3];
2611         char str[200];
2612
2613         window_to_3d(t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2614
2615         if (t->con.mode & CON_APPLY) {
2616                 float pvec[3] = {0.0f, 0.0f, 0.0f};
2617                 t->con.applyVec(t, NULL, t->vec, tvec, pvec);
2618                 VECCOPY(t->vec, tvec);
2619                 headerTranslation(t, pvec, str);
2620         }
2621         else {
2622                 snapGrid(t, t->vec);
2623                 applyNumInput(&t->num, t->vec);
2624                 headerTranslation(t, t->vec, str);
2625         }
2626
2627         applyTranslation(t, t->vec);
2628
2629         recalcData(t);
2630
2631         headerprint(str);
2632
2633         force_draw(0);
2634
2635         return 1;
2636 }
2637
2638 /* ************************** SHRINK/FATTEN *************************** */
2639
2640 void initShrinkFatten(TransInfo *t) 
2641 {
2642         if (G.obedit==NULL || G.obedit->type != OB_MESH) {
2643                 initTransModeFlags(t, TFM_RESIZE);
2644                 initResize(t);
2645                 return;
2646         }
2647
2648         t->idx_max = 0;
2649         t->num.idx_max = 0;
2650         t->snap[0] = 0.0f;
2651         t->snap[1] = G.vd->grid * 1.0f;
2652         t->snap[2] = t->snap[1] * 0.1f;
2653         t->transform = ShrinkFatten;
2654 }
2655
2656
2657
2658 int ShrinkFatten(TransInfo *t, short mval[2]) 
2659 {
2660         float vec[3];
2661         float ratio;
2662         int i;
2663         char str[50];
2664         TransData *td = t->data;
2665
2666         window_to_3d(t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2667         Projf(vec, t->vec, G.vd->viewinv[1]);
2668         ratio = Normalise(vec);
2669
2670         if (mval[1] < t->imval[1])
2671                 ratio *= -1;
2672
2673         snapGrid(t, &ratio);
2674
2675         applyNumInput(&t->num, &ratio);
2676
2677         /* header print for NumInput */
2678         if (hasNumInput(&t->num)) {
2679                 char c[20];
2680
2681                 outputNumInput(&(t->num), c);
2682
2683                 sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
2684         }
2685         else {
2686                 /* default header print */
2687                 sprintf(str, "Shrink/Fatten: %.4f %s", ratio, t->proptext);
2688         }
2689         
2690         
2691         for(i = 0 ; i < t->total; i++, td++) {
2692                 if (td->flag & TD_NOACTION)
2693                         break;
2694
2695                 VECCOPY(vec, td->axismtx[2]);
2696                 VecMulf(vec, ratio);
2697                 VecMulf(vec, td->factor);
2698
2699                 VecAddf(td->loc, td->iloc, vec);
2700         }
2701
2702         recalcData(t);
2703
2704         headerprint(str);
2705
2706         force_draw(0);
2707
2708         return 1;
2709 }
2710
2711 /* ************************** TILT *************************** */
2712
2713 void initTilt(TransInfo *t) 
2714 {
2715         t->idx_max = 0;
2716         t->num.idx_max = 0;
2717         t->snap[0] = 0.0f;
2718         t->snap[1] = G.vd->grid * (float)((5.0/180)*M_PI);
2719         t->snap[2] = t->snap[1] * 0.2f;
2720         t->fac = 0;
2721         t->transform = Tilt;
2722 }
2723
2724
2725
2726 int Tilt(TransInfo *t, short mval[2]) 
2727 {
2728         TransData *td = t->data;
2729         int i;
2730         char str[50];
2731
2732         float final;
2733
2734         int dx2 = t->center2d[0] - mval[0];
2735         int dy2 = t->center2d[1] - mval[1];
2736         float B = (float)sqrt(dx2*dx2+dy2*dy2);
2737
2738         int dx1 = t->center2d[0] - t->imval[0];
2739         int dy1 = t->center2d[1] - t->imval[1];
2740         float A = (float)sqrt(dx1*dx1+dy1*dy1);
2741
2742         int dx3 = mval[0] - t->imval[0];
2743         int dy3 = mval[1] - t->imval[1];
2744
2745         float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
2746                 / (2 * A * B);
2747
2748         float dphi;
2749
2750         dphi = saacos(deler);
2751         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
2752
2753         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2754         else t->fac += dphi;
2755
2756         final = t->fac;
2757
2758         snapGrid(t, &final);
2759
2760         t->imval[0] = mval[0];
2761         t->imval[1] = mval[1];
2762
2763         if (hasNumInput(&t->num)) {
2764                 char c[20];
2765
2766                 applyNumInput(&t->num, &final);
2767
2768                 outputNumInput(&(t->num), c);
2769
2770                 sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
2771
2772                 final *= (float)(M_PI / 180.0);
2773         }
2774         else {
2775                 sprintf(str, "Tilt: %.2f %s", 180.0*final/M_PI, t->proptext);
2776         }
2777
2778         for(i = 0 ; i < t->total; i++, td++) {
2779                 if (td->flag & TD_NOACTION)
2780                         break;
2781
2782                 if (td->val) {
2783                         *td->val = td->ival + final * td->factor;
2784                 }
2785         }
2786
2787         recalcData(t);
2788
2789         headerprint(str);
2790
2791         force_draw(0);
2792
2793         helpline (t->center);
2794
2795         return 1;
2796 }
2797