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