6bccb672fb6dcaae07d2d4358e029feb1fca6926
[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= 1;
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) {
820                                         if (v2->f2) {
821                                                 float nvec[3];
822                                                 float len1 = VecLength(vec1);
823                                                 float len2 = VecLength(vec2);
824                                                 float lenn;
825                                                 /* for v2 */
826                                                 VecSubf(nvec, v2->co, E_NEAR(v1)->co);
827                                                 lenn = VecLength(nvec);
828                                                 if (lenn - len1 > 0.00001f && len2 - lenn > 0.00001f) {
829                                                         VECCOPY(vec2, nvec);
830                                                         E_NEAR(v2) = E_NEAR(v1);
831                                                         done = 1;
832                                                 }
833                                                 /* for v1 */
834                                                 VecSubf(nvec, v1->co, E_NEAR(v2)->co);
835                                                 if (lenn - len2 > 0.00001f && len1 - lenn > 0.00001f) {
836                                                         VECCOPY(vec1, nvec);
837                                                         E_NEAR(v1) = E_NEAR(v2);
838                                                         done = 1;
839                                                 }
840                                         }
841                                         else {
842                                                 v2->f2 = 1;
843                                                 VecSubf(vec2, v2->co, E_NEAR(v1)->co);
844                                                 if (VecLength(vec1) - VecLength(vec2) > 0.00001f) {
845                                                         VECCOPY(vec2, vec1);
846                                                 }
847                                                 E_NEAR(v2) = E_NEAR(v1);
848                                                 done = 1;
849                                         }
850                                 }
851                                 else if (v2->f2) {
852                                         v1->f2 = 1;
853                                         VecSubf(vec1, v1->co, E_NEAR(v2)->co);
854                                         if (VecLength(vec2) - VecLength(vec1) > 0.00001f) {
855                                                 VECCOPY(vec1, vec2);
856                                         }
857                                         E_NEAR(v1) = E_NEAR(v2);
858                                         done = 1;
859                                 }
860                         }
861                 }
862         }
863
864         /* set unused or clipped away vertices on huge dist */
865         for(i=0, eve= em->verts.first; eve; eve= eve->next, i++) {
866                 if(eve->f2==0) {
867                         E_NEAR(eve) = NULL;
868                 }
869         }
870 }
871
872
873 static void VertsToTransData(TransData *td, EditVert *eve)
874 {
875         td->flag = 0;
876         td->loc = eve->co;
877         VECCOPY(td->center, td->loc);
878         VECCOPY(td->iloc, td->loc);
879
880         // Setting normals
881         VECCOPY(td->axismtx[2], eve->no);
882         td->axismtx[0][0]               =
883                 td->axismtx[0][1]       =
884                 td->axismtx[0][2]       =
885                 td->axismtx[1][0]       =
886                 td->axismtx[1][1]       =
887                 td->axismtx[1][2]       = 0.0f;
888
889         td->ext = NULL;
890         td->tdi = NULL;
891         td->val = NULL;
892 }
893
894 static void createTransEditVerts(void)
895 {
896         TransData *tob = NULL;
897         EditMesh *em = G.editMesh;
898         EditVert *eve;
899         EditVert **nears;
900         float mtx[3][3], smtx[3][3];
901         float *vectors;
902         int count=0, countsel=0;
903         int propmode = G.f & G_PROPORTIONAL;
904                 
905         // transform now requires awareness for select mode, so we tag the f1 flags in verts
906         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
907                 for(eve= em->verts.first; eve; eve= eve->next) {
908                         if(eve->h==0 && (eve->f & SELECT)) 
909                                 eve->f1= SELECT;
910                         else
911                                 eve->f1= 0;
912                 }
913         }
914         else if(G.scene->selectmode & SCE_SELECT_EDGE) {
915                 EditEdge *eed;
916                 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
917                 for(eed= em->edges.first; eed; eed= eed->next) {
918                         if(eed->h==0 && (eed->f & SELECT))
919                                 eed->v1->f1= eed->v2->f1= SELECT;
920                 }
921         }
922         else {
923                 EditFace *efa;
924                 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
925                 for(efa= em->faces.first; efa; efa= efa->next) {
926                         if(efa->h==0 && (efa->f & SELECT)) {
927                                 efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
928                                 if(efa->v4) efa->v4->f1= SELECT;
929                         }
930                 }
931         }
932         
933         /* now we can count */
934         for(eve= em->verts.first; eve; eve= eve->next) {
935                 if(eve->h==0) {
936                         if(eve->f1) countsel++;
937                         if(propmode) count++;
938                 }
939         }
940         
941         /* note: in prop mode we need at least 1 selected */
942         if (countsel==0) return;
943         
944         if(propmode) {
945                 Trans.total = count; 
946         
947                 /* allocating scratch arrays */
948                 vectors = (float *)malloc(Trans.total * 3 * sizeof(float));
949                 nears = (EditVert**)malloc(Trans.total * sizeof(EditVert*));
950         }
951         else Trans.total = countsel;
952         tob= Trans.data= MEM_mallocN(Trans.total*sizeof(TransData), "TransObData(Mesh EditMode)");
953         
954         Mat3CpyMat4(mtx, G.obedit->obmat);
955         Mat3Inv(smtx, mtx);
956
957         if(propmode) editmesh_set_connectivity_distance(Trans.total, vectors, nears);
958         
959         for (eve=em->verts.first; eve; eve=eve->next) {
960                 if(eve->h==0) {
961                         if(propmode || eve->f1) {
962                                 VertsToTransData(tob, eve);
963
964                                 if(eve->f1) tob->flag |= TD_SELECTED;
965                                 if(propmode) {
966                                         if (E_NEAR(eve)) {
967                                                 tob->dist= VecLength(E_VEC(eve));
968                                         }
969                                         else {
970                                                 tob->flag |= TD_NOTCONNECTED;
971                                                 tob->dist = 10000000.0f;
972                                         }
973                                 }
974                                 
975                                 Mat3CpyMat3(tob->smtx, smtx);
976                                 Mat3CpyMat3(tob->mtx, mtx);
977
978                                 tob++;
979                         }
980                 }       
981         }
982         if (propmode) {
983                 free(nears);
984                 free(vectors);
985         }
986
987 }
988
989 /* **************** IpoKey stuff, for Object TransData ********** */
990
991 /* storage of bezier triple. thats why -3 and +3! */
992 static void set_tdi_old(float *old, float *poin)
993 {
994         old[0]= *(poin);
995         old[3]= *(poin-3);
996         old[6]= *(poin+3);
997 }
998
999 /* while transforming */
1000 static void add_tdi_poin(float *poin, float *old, float delta)
1001 {
1002         if(poin) {
1003                 poin[0]= old[0]+delta;
1004                 poin[-3]= old[3]+delta;
1005                 poin[3]= old[6]+delta;
1006         }
1007 }
1008
1009 /* fill ipokey transdata with old vals and pointers */
1010 static void ipokey_to_transdata(IpoKey *ik, TransData *td)
1011 {
1012         extern int ob_ar[];             // blenkernel ipo.c
1013         TransDataIpokey *tdi= td->tdi;
1014         BezTriple *bezt;
1015         int a, delta= 0;
1016         
1017         for(a=0; a<OB_TOTIPO; a++) {
1018                 if(ik->data[a]) {
1019                         bezt= ik->data[a];
1020                         
1021                         switch( ob_ar[a] ) {
1022                                 case OB_LOC_X:
1023                                 case OB_DLOC_X:
1024                                         tdi->locx= &(bezt->vec[1][1]); break;
1025                                 case OB_LOC_Y:
1026                                 case OB_DLOC_Y:
1027                                         tdi->locy= &(bezt->vec[1][1]); break;
1028                                 case OB_LOC_Z:
1029                                 case OB_DLOC_Z:
1030                                         tdi->locz= &(bezt->vec[1][1]); break;
1031                                         
1032                                 case OB_DROT_X:
1033                                         delta= 1;
1034                                 case OB_ROT_X:
1035                                         tdi->rotx= &(bezt->vec[1][1]); break;
1036                                 case OB_DROT_Y:
1037                                         delta= 1;
1038                                 case OB_ROT_Y:
1039                                         tdi->roty= &(bezt->vec[1][1]); break;
1040                                 case OB_DROT_Z:
1041                                         delta= 1;
1042                                 case OB_ROT_Z:
1043                                         tdi->rotz= &(bezt->vec[1][1]); break;
1044                                         
1045                                 case OB_SIZE_X:
1046                                 case OB_DSIZE_X:
1047                                         tdi->sizex= &(bezt->vec[1][1]); break;
1048                                 case OB_SIZE_Y:
1049                                 case OB_DSIZE_Y:
1050                                         tdi->sizey= &(bezt->vec[1][1]); break;
1051                                 case OB_SIZE_Z:
1052                                 case OB_DSIZE_Z:
1053                                         tdi->sizez= &(bezt->vec[1][1]); break;          
1054                         }       
1055                 }
1056         }
1057         
1058         /* oldvals for e.g. undo */
1059         if(tdi->locx) set_tdi_old(tdi->oldloc, tdi->locx);
1060         if(tdi->locy) set_tdi_old(tdi->oldloc+1, tdi->locy);
1061         if(tdi->locz) set_tdi_old(tdi->oldloc+2, tdi->locz);
1062         
1063         /* remember, for mapping curves ('1'=10 degrees)  */
1064         if(tdi->rotx) set_tdi_old(tdi->oldrot, tdi->rotx);
1065         if(tdi->roty) set_tdi_old(tdi->oldrot+1, tdi->roty);
1066         if(tdi->rotz) set_tdi_old(tdi->oldrot+2, tdi->rotz);
1067         
1068         /* this is not allowed to be dsize! */
1069         if(tdi->sizex) set_tdi_old(tdi->oldsize, tdi->sizex);
1070         if(tdi->sizey) set_tdi_old(tdi->oldsize+1, tdi->sizey);
1071         if(tdi->sizez) set_tdi_old(tdi->oldsize+2, tdi->sizez);
1072         
1073         tdi->flag= TOB_IPO;
1074         if(delta) tdi->flag |= TOB_IPODROT;
1075 }
1076
1077
1078 /* *************************** Object Transform data ******************* */
1079
1080 static void ObjectToTransData(TransData *td, Object *ob) 
1081 {
1082         float obmtx[3][3];
1083         Object *tr;
1084         void *cfirst, *clast;
1085
1086         cfirst = ob->constraints.first;
1087         clast = ob->constraints.last;
1088         ob->constraints.first=ob->constraints.last=NULL;
1089
1090         tr= ob->track;
1091         ob->track= NULL;
1092
1093         where_is_object(ob);
1094
1095         ob->track= tr;
1096
1097         ob->constraints.first = cfirst;
1098         ob->constraints.last = clast;
1099
1100         td->ob = ob;
1101
1102         td->loc = ob->loc;
1103         VECCOPY(td->iloc, td->loc);
1104         
1105         td->ext->rot = ob->rot;
1106         VECCOPY(td->ext->irot, ob->rot);
1107         VECCOPY(td->ext->drot, ob->drot);
1108         
1109         td->ext->size = ob->size;
1110         VECCOPY(td->ext->isize, ob->size);
1111         VECCOPY(td->ext->dsize, ob->dsize);
1112
1113         VECCOPY(td->center, ob->obmat[3]);
1114
1115         Mat3CpyMat4(td->axismtx, ob->obmat);
1116         Mat3Ortho(td->axismtx);
1117
1118         if (ob->parent)
1119         {
1120                 float totmat[3][3], obinv[3][3];
1121                 
1122                 /* we calculate smtx without obmat: so a parmat */
1123                 object_to_mat3(ob, obmtx);
1124                 Mat3CpyMat4(totmat, ob->obmat);
1125                 Mat3Inv(obinv, totmat);
1126                 Mat3MulMat3(td->smtx, obmtx, obinv);
1127                 Mat3Inv(td->mtx, td->smtx);
1128         }
1129         else
1130         {
1131                 Mat3One(td->smtx);
1132                 Mat3One(td->mtx);
1133         }
1134 }
1135
1136 /* only used in function below, stuff to be removed */
1137 static Object *is_a_parent_selected_int(Object *startob, Object *ob, GHash *done_hash) 
1138 {
1139         if (ob!=startob && TESTBASE(ob))
1140                 return ob;
1141         
1142         if (BLI_ghash_haskey(done_hash, ob))
1143                 return NULL;
1144         else
1145                 BLI_ghash_insert(done_hash, ob, NULL);
1146         
1147         if (ob->parent) {
1148                 Object *par= is_a_parent_selected_int(startob, ob->parent, done_hash);
1149                 if (par)
1150                         return par;
1151         }
1152         return NULL;
1153 }
1154
1155 /* only used in function below, stuff to be removed */
1156 static Object *is_a_parent_selected(Object *ob) 
1157 {
1158         GHash *gh= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
1159         Object *res= is_a_parent_selected_int(ob, ob, gh);
1160         BLI_ghash_free(gh, NULL, NULL);
1161         
1162         return res;
1163 }
1164
1165
1166
1167 /* sets flags in Bases to define whether they take part in transform */
1168 /* it deselects Bases, so we have to call the clear function always after */
1169 static void set_trans_object_base_flags(TransInfo *t)
1170 {
1171         /*
1172          if Base selected and has parent selected:
1173          base->flag= BA_WASSEL+BA_PARSEL
1174          if base not selected and parent selected:
1175          base->flag= BA_PARSEL
1176          */
1177         GHash *object_to_base_hash= NULL; 
1178         Base *base;
1179         
1180         /* moved to start of function, it is needed for hooks now too */
1181         if (!object_to_base_hash) {
1182                 Base *b;
1183                 object_to_base_hash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
1184                 
1185                 for (b= FIRSTBASE; b; b= b->next)
1186                         BLI_ghash_insert(object_to_base_hash, b->object, b);
1187         }
1188         
1189         /* makes sure base flags and object flags are identical */
1190         copy_baseflags();
1191         
1192         for (base= FIRSTBASE; base; base= base->next) {
1193                 base->flag &= ~(BA_PARSEL+BA_WASSEL);
1194                 
1195                 if( (base->lay & G.vd->lay) && base->object->id.lib==0) {
1196                         Object *ob= base->object;
1197                         Object *parsel= is_a_parent_selected(ob);
1198                         
1199                         /* parentkey here? */
1200                         
1201                         if(parsel) {
1202                                 if(base->flag & SELECT) {
1203                                         base->flag &= ~SELECT;
1204                                         base->flag |= (BA_PARSEL+BA_WASSEL);
1205                                 }
1206                                 else base->flag |= BA_PARSEL;
1207                         }
1208                         
1209                         if(t->mode==TFM_TRANSLATION)  {
1210                                 if(ob->track && TESTBASE(ob->track) && (base->flag & SELECT)==0)  
1211                                         base->flag |= BA_PARSEL;
1212                         }
1213                         
1214                         /* updates? */
1215                         if(ob->hooks.first) {
1216                                 Base *b;
1217                                 ObHook *hook= ob->hooks.first;
1218                                 
1219                                 while(hook) {
1220                                         if(hook->parent) {
1221                                                 Object *parsel= is_a_parent_selected(hook->parent);
1222                                                 
1223                                                 b= BLI_ghash_lookup(object_to_base_hash, hook->parent);
1224                                                 if(parsel || ((base->flag | b->flag) & (SELECT | BA_PARSEL)) ) {
1225                                                         base->flag |= BA_DISP_UPDATE;
1226                                                 }
1227                                         }
1228                                         hook= hook->next;
1229                                 }
1230                         }
1231                         
1232                         if(ob->parent && ob->parent->type==OB_LATTICE)
1233                                 if(ob->parent->hooks.first) base->flag |= BA_DISP_UPDATE;
1234                         
1235                         if(base->flag & (SELECT | BA_PARSEL)) {
1236                                 
1237                                 base->flag |= BA_WHERE_UPDATE;
1238                                 
1239                                 if(ob->parent) {
1240                                         if(ob->parent->type==OB_LATTICE) base->flag |= BA_DISP_UPDATE;
1241                                         else if(ob->partype==PARSKEL) {
1242                                                 if ELEM3(ob->parent->type, OB_IKA, OB_CURVE, OB_ARMATURE) 
1243                                                         base->flag |= BA_DISP_UPDATE;
1244                                         }
1245                                 }
1246                                 if(ob->track) {
1247                                         ;
1248                                 }
1249                                 
1250                                 if( give_parteff(ob) ) base->flag |= BA_DISP_UPDATE;
1251                                 
1252                                 if(ob->type==OB_MBALL) {
1253                                         Base *b;
1254                                         
1255                                         b= BLI_ghash_lookup(object_to_base_hash, find_basis_mball(ob));
1256                                         b->flag |= BA_DISP_UPDATE;
1257                                 }
1258                         }
1259                 }
1260         }
1261         
1262         if (object_to_base_hash)
1263                 BLI_ghash_free(object_to_base_hash, NULL, NULL);
1264         
1265 }
1266
1267 static void clear_trans_object_base_flags(void)
1268 {
1269         Base *base;
1270         
1271         base= FIRSTBASE;
1272         while(base) {
1273                 if(base->flag & BA_WASSEL) base->flag |= SELECT;
1274                 base->flag &= ~(BA_PARSEL+BA_WASSEL);
1275                 
1276                 base->flag &= ~(BA_DISP_UPDATE+BA_WHERE_UPDATE+BA_DO_IPO);
1277                 
1278                 /* pose here? */
1279                 if (base->object->pose) {
1280                         Object *ob= base->object;
1281                         bPoseChannel *chan;
1282                         for (chan = ob->pose->chanbase.first; chan; chan=chan->next) {
1283                                 chan->flag &= ~PCHAN_TRANS_UPDATE;
1284                         }
1285                 }
1286                 
1287                 base= base->next;
1288         }
1289         copy_baseflags();
1290 }
1291
1292
1293 static void createTransObject(void)
1294 {
1295         TransData *td = NULL;
1296         TransDataExtension *tx;
1297         Object *ob;
1298         Base *base;
1299         IpoKey *ik;
1300         ListBase elems;
1301         
1302         /* hackish... but we have to do it somewhere */
1303         reset_slowparents();
1304         
1305         set_trans_object_base_flags(&Trans);
1306         
1307         /* count */     
1308         for(base= FIRSTBASE; base; base= base->next) {
1309                 if TESTBASELIB(base) {
1310                         ob= base->object;
1311                         
1312                         /* store ipo keys? */
1313                         if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) {
1314                                 elems.first= elems.last= NULL;
1315                                 make_ipokey_transform(ob, &elems, 1); /* '1' only selected keys */
1316                                 
1317                                 pushdata(&elems, sizeof(ListBase));
1318                                 
1319                                 for(ik= elems.first; ik; ik= ik->next) Trans.total++;
1320
1321                                 if(elems.first==NULL) Trans.total++;
1322                         }
1323                         else {
1324                                 Trans.total++;
1325                         }
1326                 }
1327         }
1328
1329         if(!Trans.total) {
1330                 /* clear here, main transform function escapes too */
1331                 clear_trans_object_base_flags();
1332                 return;
1333         }
1334         
1335         td = Trans.data = MEM_mallocN(Trans.total*sizeof(TransData), "TransOb");
1336         tx = Trans.ext = MEM_mallocN(Trans.total*sizeof(TransDataExtension), "TransObExtension");
1337
1338         for(base= FIRSTBASE; base; base= base->next) {
1339                 if TESTBASELIB(base) {
1340                         ob= base->object;
1341                         
1342                         td->flag= TD_SELECTED;
1343                         td->ext = tx;
1344
1345                         /* store ipo keys? */
1346                         if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) {
1347                                 
1348                                 popfirst(&elems);       // bring back pushed listbase
1349                                 
1350                                 if(elems.first) {
1351                                         float cfraont;
1352                                         int ipoflag;
1353                                         
1354                                         base->flag |= BA_DO_IPO+BA_WASSEL;
1355                                         base->flag &= ~SELECT;
1356                                         
1357                                         cfraont= CFRA;
1358                                         set_no_parent_ipo(1);
1359                                         ipoflag= ob->ipoflag;
1360                                         ob->ipoflag &= ~OB_OFFS_OB;
1361                                         
1362                                         pushdata(ob->loc, 7*3*4); // tsk! tsk!
1363                                         
1364                                         for(ik= elems.first; ik; ik= ik->next) {
1365                                                 
1366                                                 /* weak... this doesn't correct for floating values, giving small errors */
1367                                                 CFRA= (short)(ik->val/G.scene->r.framelen);
1368                                                 
1369                                                 do_ob_ipo(ob);
1370                                                 ObjectToTransData(td, ob);      // does where_is_object()
1371                                                 
1372                                                 td->tdi= MEM_callocN(sizeof(TransDataIpokey), "TransDataIpokey");
1373                                                 /* also does tdi->flag and oldvals, needs to be after ob_to_transob()! */
1374                                                 ipokey_to_transdata(ik, td);
1375                                                 
1376                                                 td++;
1377                                                 tx++;
1378                                                 if(ik->next) td->ext= tx;       // prevent corrupting mem!
1379                                         }
1380                                         free_ipokey(&elems);
1381                                         
1382                                         poplast(ob->loc);
1383                                         set_no_parent_ipo(0);
1384                                         
1385                                         CFRA= (short)cfraont;
1386                                         ob->ipoflag= ipoflag;
1387                                 }
1388                                 else {
1389                                         ObjectToTransData(td, ob);
1390                                         td->tdi = NULL;
1391                                         td->val = NULL;
1392                                 }
1393                         }
1394                         else {
1395                                 ObjectToTransData(td, ob);
1396                                 td->tdi = NULL;
1397                                 td->val = NULL;
1398                         }
1399                         td++;
1400                         tx++;
1401                 }
1402         }
1403 }
1404
1405 static void createTransData(TransInfo *t) 
1406 {
1407         if (t->context == CTX_TEXTURE) {
1408                 t->flag |= T_TEXTURE;
1409                 createTransTexspace();
1410         }
1411         else if (G.obpose) {
1412                 t->flag |= T_POSE;
1413                 createTransPose();
1414         }
1415         else if (G.obedit) {
1416                 t->ext = NULL;
1417                 if (G.obedit->type == OB_MESH) {
1418                         if(t->mode==TFM_SHRINKFATTEN) vertexnormals(0);
1419                         createTransEditVerts(); 
1420                 }
1421                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1422                         createTransCurveVerts();
1423                 }
1424                 else if (G.obedit->type==OB_LATTICE) {
1425                         createTransLatticeVerts();
1426                 }
1427                 else if (G.obedit->type==OB_MBALL) {
1428                         createTransMBallVerts();
1429                 }
1430                 else if (G.obedit->type==OB_ARMATURE) {
1431                         createTransArmatureVerts();
1432                 }                                                       
1433                 else {
1434                         printf("not done yet! only have mesh surface curve\n");
1435                 }
1436                 
1437                 if(G.f & G_PROPORTIONAL) {
1438                         if (ELEM(G.obedit->type, OB_CURVE, OB_MESH)) {
1439                                 sort_trans_data(t);     // makes selected become first in array
1440                                 set_prop_dist(t, 0);
1441                                 sort_trans_data_dist(t);
1442                         }
1443                         else {
1444                                 sort_trans_data(t);     // makes selected become first in array
1445                                 set_prop_dist(t, 1);
1446                                 sort_trans_data_dist(t);
1447                         }
1448                 }
1449                 t->flag |= T_EDIT;
1450         }
1451         else {
1452                 createTransObject();
1453                 t->flag |= T_OBJECT;
1454         }
1455
1456         if((t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp>1) {
1457                 t->flag |= T_CAMERA;
1458         }
1459 }
1460
1461 #define TRANS_CANCEL    2
1462 #define TRANS_CONFIRM   1
1463
1464 /* ************************** TRANSFORMATIONS **************************** */
1465
1466 void Transform(int mode, int context) 
1467 {
1468         int ret_val = 0;
1469         short pmval[2] = {0, 0}, mval[2], val, oldprop;
1470         float mati[3][3];
1471         unsigned short event;
1472         char cmode = '\0';
1473
1474         /* STUPID HACK, but this needs fixing right now */
1475         if (G.f & G_PROPORTIONAL)
1476                 oldprop = 1;
1477         else
1478                 oldprop = 0;
1479
1480         if (context & CTX_NOPET) {
1481                 G.f &= ~G_PROPORTIONAL;
1482         }
1483
1484
1485         /*joeedh -> hopefully may be what makes the old transform() constant*/
1486         /* ton: I doubt, but it doesnt harm for now. shouldnt be needed though */
1487         areawinset(curarea->win);
1488
1489         Mat3One(mati);
1490
1491         /* stupid PET initialisation code */
1492         /* START */
1493         if (Trans.propsize == 0.0f) {
1494                 Trans.propsize = 1.0;
1495         }
1496         /* END */
1497
1498         if (mode == TFM_REPEAT) {
1499                 mode = LastMode;
1500         }
1501         else {
1502                 LastMode = mode;
1503         }
1504
1505         Trans.context = context;
1506         
1507         initTransModeFlags(&Trans, mode);       // modal settings in struct Trans
1508
1509         initTrans(&Trans);                                      // internal data, mouse, vectors
1510
1511         createTransData(&Trans);                        // make TransData structs from selection
1512
1513         if (Trans.total == 0)
1514                 return;
1515
1516         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1517         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1518         mode= Trans.mode;
1519         
1520         calculatePropRatio(&Trans);
1521         calculateCenter(&Trans);
1522
1523         switch (mode) {
1524         case TFM_TRANSLATION:
1525                 initTranslation(&Trans);
1526                 break;
1527         case TFM_ROTATION:
1528                 initRotation(&Trans);
1529                 break;
1530         case TFM_RESIZE:
1531                 initResize(&Trans);
1532                 break;
1533         case TFM_TOSPHERE:
1534                 initToSphere(&Trans);
1535                 break;
1536         case TFM_SHEAR:
1537                 initShear(&Trans);
1538                 break;
1539         case TFM_WARP:
1540                 initWarp(&Trans);
1541                 break;
1542         case TFM_SHRINKFATTEN:
1543                 initShrinkFatten(&Trans);
1544                 break;
1545         case TFM_TILT:
1546                 initTilt(&Trans);
1547                 break;
1548         case TFM_TRACKBALL:
1549                 initTrackball(&Trans);
1550                 break;
1551         }
1552
1553         initConstraint(&Trans);
1554
1555         // Emptying event queue
1556         while( qtest() ) {
1557                 event= extern_qread(&val);
1558         }
1559
1560         Trans.redraw = 1;
1561
1562         while (ret_val == 0) {
1563
1564                 getmouseco_areawin(mval);
1565                 
1566                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1567                         Trans.redraw = 1;
1568                 }
1569                 if (Trans.redraw) {
1570                         pmval[0] = mval[0];
1571                         pmval[1] = mval[1];
1572
1573                         selectConstraint(&Trans);
1574                         if (Trans.transform) {
1575                                 Trans.transform(&Trans, mval);
1576                         }
1577                         Trans.redraw = 0;
1578                 }
1579                 
1580                 /* essential for idling subloop */
1581                 if( qtest()==0) PIL_sleep_ms(2);
1582
1583                 while( qtest() ) {
1584                         event= extern_qread(&val);
1585
1586                         if (val) {
1587                                 switch (event){
1588                                 /* enforce redraw of transform when modifiers are used */
1589                                 case LEFTCTRLKEY:
1590                                 case RIGHTCTRLKEY:
1591                                         Trans.redraw = 1;
1592                                         break;
1593                                 case LEFTSHIFTKEY:
1594                                 case RIGHTSHIFTKEY:
1595                                         /* shift is modifier for higher resolution transform, works nice to store this mouse position */
1596                                         getmouseco_areawin(Trans.shiftmval);
1597                                         Trans.flag |= T_SHIFT_MOD;
1598                                         Trans.redraw = 1;
1599                                         break;
1600                                         
1601                                 case MIDDLEMOUSE:
1602                                         /* exception for switching to dolly, or trackball, in camera view */
1603                                         if (Trans.flag & T_CAMERA) {
1604                                                 if (Trans.mode==TFM_TRANSLATION)
1605                                                         setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
1606                                                 else if (Trans.mode==TFM_ROTATION) {
1607                                                         restoreTransObjects(&Trans);
1608                                                         initTransModeFlags(&Trans, TFM_TRACKBALL);
1609                                                         initTrackball(&Trans);
1610                                                 }
1611                                         }
1612                                         else 
1613                                                 initSelectConstraint(&Trans);
1614                                         Trans.redraw = 1;
1615                                         break;
1616                                 case ESCKEY:
1617                                 case RIGHTMOUSE:
1618                                         ret_val = TRANS_CANCEL;
1619                                         break;
1620                                 case LEFTMOUSE:
1621                                 case SPACEKEY:
1622                                 case PADENTER:
1623                                 case RETKEY:
1624                                         ret_val = TRANS_CONFIRM;
1625                                         break;
1626                                 case GKEY:
1627                                         restoreTransObjects(&Trans);
1628                                         initTransModeFlags(&Trans, TFM_TRANSLATION);
1629                                         initTranslation(&Trans);
1630                                         Trans.redraw = 1;
1631                                         break;
1632                                 case SKEY:
1633                                         restoreTransObjects(&Trans);
1634                                         initTransModeFlags(&Trans, TFM_RESIZE);
1635                                         initResize(&Trans);
1636                                         Trans.redraw = 1;
1637                                         break;
1638                                 case RKEY:
1639                                         if (Trans.mode == TFM_ROTATION) {
1640                                                 restoreTransObjects(&Trans);
1641                                                 initTransModeFlags(&Trans, TFM_TRACKBALL);
1642                                                 initTrackball(&Trans);
1643                                         }
1644                                         else {
1645                                                 restoreTransObjects(&Trans);
1646                                                 initTransModeFlags(&Trans, TFM_ROTATION);
1647                                                 initRotation(&Trans);
1648                                         }
1649                                         Trans.redraw = 1;
1650                                         break;
1651                                 case XKEY:
1652                                         if (cmode == 'X') {
1653                                                 stopConstraint(&Trans);
1654                                                 cmode = '\0';
1655                                         }
1656                                         else if(cmode == 'x') {
1657                                                 if (G.qual == 0)
1658                                                         setLocalConstraint(&Trans, (CON_AXIS0), "along local X");
1659                                                 else if (G.qual == LR_SHIFTKEY)
1660                                                         setLocalConstraint(&Trans, (CON_AXIS1|CON_AXIS2), "locking local X");
1661
1662                                                 cmode = 'X';
1663                                         }
1664                                         else {
1665                                                 if (G.qual == 0)
1666                                                         setConstraint(&Trans, mati, (CON_AXIS0), "along global X");
1667                                                 else if (G.qual == LR_SHIFTKEY)
1668                                                         setConstraint(&Trans, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
1669
1670                                                 cmode = 'x';
1671                                         }
1672                                         Trans.redraw = 1;
1673                                         break;
1674                                 case YKEY:
1675                                         if (cmode == 'Y') {
1676                                                 stopConstraint(&Trans);
1677                                                 cmode = '\0';
1678                                         }
1679                                         else if(cmode == 'y') {
1680                                                 if (G.qual == 0)
1681                                                         setLocalConstraint(&Trans, (CON_AXIS1), "along global Y");
1682                                                 else if (G.qual == LR_SHIFTKEY)
1683                                                         setLocalConstraint(&Trans, (CON_AXIS0|CON_AXIS2), "locking global Y");
1684
1685                                                 cmode = 'Y';
1686                                         }
1687                                         else {
1688                                                 if (G.qual == 0)
1689                                                         setConstraint(&Trans, mati, (CON_AXIS1), "along local Y");
1690                                                 else if (G.qual == LR_SHIFTKEY)
1691                                                         setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS2), "locking local Y");
1692
1693                                                 cmode = 'y';
1694                                         }
1695                                         Trans.redraw = 1;
1696                                         break;
1697                                 case ZKEY:
1698                                         if (cmode == 'Z') {
1699                                                 stopConstraint(&Trans);
1700                                                 cmode = '\0';
1701                                         }
1702                                         else if(cmode == 'z') {
1703                                                 if (G.qual == 0)
1704                                                         setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
1705                                                 else if (G.qual == LR_SHIFTKEY)
1706                                                         setLocalConstraint(&Trans, (CON_AXIS0|CON_AXIS1), "locking local Z");
1707
1708                                                 cmode = 'Z';
1709                                         }
1710                                         else {
1711                                                 if (G.qual == 0)
1712                                                         setConstraint(&Trans, mati, (CON_AXIS2), "along global Z");
1713                                                 else if (G.qual == LR_SHIFTKEY)
1714                                                         setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
1715
1716                                                 cmode = 'z';
1717                                         }
1718                                         Trans.redraw = 1;
1719                                         break;
1720                                 case OKEY:
1721                                         if (G.qual==LR_SHIFTKEY) {
1722                                                 extern int prop_mode;
1723                                                 prop_mode = (prop_mode+1)%5;
1724                                                 calculatePropRatio(&Trans);
1725                                                 Trans.redraw= 1;
1726                                         }
1727                                         break;
1728                                 case WHEELDOWNMOUSE:
1729                                 case PADPLUSKEY:
1730                                         if(G.f & G_PROPORTIONAL) {
1731                                                 Trans.propsize*= 1.1f;
1732                                                 calculatePropRatio(&Trans);
1733                                                 Trans.redraw= 1;
1734                                         }
1735                                         break;
1736                                 case WHEELUPMOUSE:
1737                                 case PADMINUS:
1738                                         if(G.f & G_PROPORTIONAL) {
1739                                                 Trans.propsize*= 0.90909090f;
1740                                                 calculatePropRatio(&Trans);
1741                                                 Trans.redraw= 1;
1742                                         }
1743                                         break;
1744                                 }
1745                                 Trans.redraw |= handleNumInput(&(Trans.num), event);
1746                                 arrows_move_cursor(event);
1747                         }
1748                         else {
1749                                 switch (event){
1750                                 /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still 
1751                                    after releasing modifer key */
1752                                 case MIDDLEMOUSE:
1753                                         postSelectConstraint(&Trans);
1754                                         Trans.redraw = 1;
1755                                         break;
1756                                 case LEFTMOUSE:
1757                                 case RIGHTMOUSE:
1758                                         /* commented out, doesn't work for actions started with menu */
1759                                         // ret_val = TRANS_CONFIRM;
1760                                         break;
1761                                 case LEFTSHIFTKEY:
1762                                 case RIGHTSHIFTKEY:
1763                                         /* shift is modifier for higher resolution transform */
1764                                         Trans.flag &= ~T_SHIFT_MOD;
1765                                         break;
1766                                 }
1767                         }
1768                 }
1769         }
1770         
1771         
1772         if(ret_val == TRANS_CANCEL) {
1773                 restoreTransObjects(&Trans);
1774         }
1775         else {
1776                 BIF_undo_push("Transform");
1777         }
1778         
1779         /* free data, reset vars */
1780         postTrans(&Trans);
1781         
1782         /* mess from old transform, just for now (ton) */
1783         {
1784                 char cmode='g';
1785                 
1786                 if(mode==TFM_RESIZE) cmode= 's';
1787                 else if(mode==TFM_ROTATION) cmode= 'r';
1788                 /* aftertrans does displists, ipos and action channels */
1789                 /* 7 = keyflags, meaning do loc/rot/scale ipos. Not sure if I like the old method to detect what changed (ton) */
1790                 special_aftertrans_update(cmode, 0, (short)(ret_val == TRANS_CANCEL), 7);
1791                 
1792                 if(G.obedit==NULL && G.obpose==NULL)
1793                         clear_trans_object_base_flags();
1794         }
1795         
1796         if (context & CTX_NOPET) {
1797                 if (oldprop)
1798                         G.f |= G_PROPORTIONAL;
1799         }
1800
1801         
1802         /* send events out for redraws */
1803         allqueue(REDRAWVIEW3D, 0);
1804         allqueue(REDRAWBUTSOBJECT, 0);
1805         scrarea_queue_headredraw(curarea);
1806 }
1807
1808 void ManipulatorTransform(int mode) 
1809 {
1810         int ret_val = 0;
1811         short pmval[2] = {0, 0}, mval[2], val;
1812         unsigned short event;
1813
1814
1815         /* stupid PET initialisation code */
1816         /* START */
1817         if (Trans.propsize == 0.0f) {
1818                 Trans.propsize = 1.0;
1819         }
1820         /* END */
1821
1822         Trans.context = CTX_NONE;
1823
1824         initTransModeFlags(&Trans, mode);       // modal settings in struct Trans
1825
1826         initTrans(&Trans);                                      // internal data, mouse, vectors
1827         G.moving |= G_TRANSFORM_MANIP;          // signal to draw manipuls while transform
1828         createTransData(&Trans);                        // make TransData structs from selection
1829
1830         if (Trans.total == 0)
1831                 return;
1832
1833         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1834         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1835         mode= Trans.mode;
1836         
1837         calculatePropRatio(&Trans);
1838         calculateCenter(&Trans);
1839
1840         switch (mode) {
1841         case TFM_TRANSLATION:
1842                 initTranslation(&Trans);
1843                 break;
1844         case TFM_ROTATION:
1845                 initRotation(&Trans);
1846                 break;
1847         case TFM_RESIZE:
1848                 initResize(&Trans);
1849                 break;
1850         case TFM_TRACKBALL:
1851                 initTrackball(&Trans);
1852                 break;
1853         }
1854
1855         initConstraint(&Trans);
1856         
1857         Trans.flag |= T_USES_MANIPULATOR;
1858         Trans.redraw = 1;
1859
1860         while (ret_val == 0) {
1861                 
1862                 getmouseco_areawin(mval);
1863                 
1864                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1865                         Trans.redraw = 1;
1866                 }
1867                 if (Trans.redraw) {
1868                         pmval[0] = mval[0];
1869                         pmval[1] = mval[1];
1870
1871                         //selectConstraint(&Trans);  needed?
1872                         if (Trans.transform) {
1873                                 Trans.transform(&Trans, mval);
1874                         }
1875                         Trans.redraw = 0;
1876                 }
1877                 
1878                 /* essential for idling subloop */
1879                 if( qtest()==0) PIL_sleep_ms(2);
1880
1881                 while( qtest() ) {
1882                         event= extern_qread(&val);
1883
1884                         switch (event){
1885                         /* enforce redraw of transform when modifiers are used */
1886                         case LEFTCTRLKEY:
1887                         case RIGHTCTRLKEY:
1888                                 if(val) Trans.redraw = 1;
1889                                 break;
1890                         case LEFTSHIFTKEY:
1891                         case RIGHTSHIFTKEY:
1892                                 /* shift is modifier for higher resolution transform, works nice to store this mouse position */
1893                                 if(val) {
1894                                         getmouseco_areawin(Trans.shiftmval);
1895                                         Trans.flag |= T_SHIFT_MOD;
1896                                         Trans.redraw = 1;
1897                                 }
1898                                 else Trans.flag &= ~T_SHIFT_MOD; 
1899                                 break;
1900                                 
1901                         case ESCKEY:
1902                         case RIGHTMOUSE:
1903                                 ret_val = TRANS_CANCEL;
1904                                 break;
1905                         case LEFTMOUSE:
1906                         case SPACEKEY:
1907                         case PADENTER:
1908                         case RETKEY:
1909                                 ret_val = TRANS_CONFIRM;
1910                                 break;
1911                         }
1912                         if(val) {
1913                                 switch(event) {
1914                                 case WHEELDOWNMOUSE:
1915                                 case PADPLUSKEY:
1916                                         if(G.f & G_PROPORTIONAL) {
1917                                                 Trans.propsize*= 1.1f;
1918                                                 calculatePropRatio(&Trans);
1919                                                 Trans.redraw= 1;
1920                                         }
1921                                         break;
1922                                 case WHEELUPMOUSE:
1923                                 case PADMINUS:
1924                                         if(G.f & G_PROPORTIONAL) {
1925                                                 Trans.propsize*= 0.90909090f;
1926                                                 calculatePropRatio(&Trans);
1927                                                 Trans.redraw= 1;
1928                                         }
1929                                         break;
1930                                 }                       
1931                         }
1932                 }
1933         }
1934         
1935         if(ret_val == TRANS_CANCEL) {
1936                 restoreTransObjects(&Trans);
1937         }
1938         else {
1939                 BIF_undo_push("Transform");
1940         }
1941         
1942         /* free data, reset vars */
1943         postTrans(&Trans);
1944         
1945         /* mess from old transform, just for now (ton) */
1946         {
1947                 char cmode='g';
1948                 
1949                 if(mode==TFM_RESIZE) cmode= 's';
1950                 else if(mode==TFM_ROTATION) cmode= 'r';
1951                 /* aftertrans does displists, ipos and action channels */
1952                 /* 7 = keyflags, meaning do loc/rot/scale ipos. Not sure if I like the old method to detect what changed (ton) */
1953                 special_aftertrans_update(cmode, 0, (short)(ret_val == TRANS_CANCEL), 7);
1954                 
1955                 if(G.obedit==NULL && G.obpose==NULL)
1956                         clear_trans_object_base_flags();
1957         }
1958         
1959         /* send events out for redraws */
1960         allqueue(REDRAWVIEW3D, 0);
1961         allqueue(REDRAWBUTSOBJECT, 0);
1962         scrarea_queue_headredraw(curarea);
1963 }
1964
1965
1966
1967 /* ************************** WRAP *************************** */
1968
1969 /* warp is done fully in view space */
1970 void initWarp(TransInfo *t) 
1971 {
1972         float max[3], min[3];
1973         int i;
1974         
1975         calculateCenterCursor(t);
1976         t->idx_max = 0;
1977         t->num.idx_max = 0;
1978         t->transform = Warp;
1979         t->snap[0] = 0.0f;
1980         t->snap[1] = 5.0f;
1981         t->snap[2] = 1.0f;
1982         
1983         t->fac = (float)(t->center2d[0] - t->imval[0]);
1984         
1985         /* we need min/max in view space */
1986         for(i = 0; i < t->total; i++) {
1987                 float center[3];
1988                 VECCOPY(center, t->data[i].center);
1989                 Mat3MulVecfl(t->data[i].mtx, center);
1990                 Mat4MulVecfl(G.vd->viewmat, center);
1991                 VecSubf(center, center, G.vd->viewmat[3]);
1992                 if (i)
1993                         MinMax3(min, max, center);
1994                 else {
1995                         VECCOPY(max, center);
1996                         VECCOPY(min, center);
1997                 }
1998         }
1999
2000         t->center[0]= (min[0]+max[0])/2.0f;
2001         t->center[1]= (min[1]+max[1])/2.0f;
2002         t->center[2]= (min[2]+max[2])/2.0f;
2003         
2004         t->val= (max[0]-min[0])/2.0f;   // t->val is free variable
2005 }
2006
2007
2008 int Warp(TransInfo *t, short mval[2])
2009 {
2010         TransData *td = t->data;
2011         float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
2012         int i;
2013         char str[50];
2014         
2015         curs= give_cursor();
2016         /*
2017          * gcursor is the one used for helpline.
2018          * It has to be in the same space as the drawing loop
2019          * (that means it needs to be in the object's space when in edit mode and
2020          *  in global space in object mode)
2021          *
2022          * cursor is used for calculations.
2023          * It needs to be in view space, but we need to take object's offset
2024          * into account if in Edit mode.
2025          */
2026         VECCOPY(cursor, curs);
2027         VECCOPY(gcursor, cursor);       
2028         if (t->flag & T_EDIT) {
2029                 VecSubf(cursor, cursor, G.obedit->obmat[3]);
2030                 VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
2031                 Mat3MulVecfl(t->data->smtx, gcursor);
2032         }
2033         Mat4MulVecfl(G.vd->viewmat, cursor);
2034         VecSubf(cursor, cursor, G.vd->viewmat[3]);
2035
2036         // amount of degrees for warp, 450 = allow to create 360 degree warp
2037         circumfac= 450.0f*(mval[1] - t->imval[1]) / (float)(curarea->winy);
2038         circumfac+= 90.0f;
2039
2040         snapGrid(t, &circumfac);
2041         applyNumInput(&t->num, &circumfac);
2042         
2043         /* header print for NumInput */
2044         if (hasNumInput(&t->num)) {
2045                 char c[20];
2046                 
2047                 outputNumInput(&(t->num), c);
2048                 
2049                 sprintf(str, "Warp: %s", c);
2050         }
2051         else {
2052                 /* default header print */
2053                 sprintf(str, "Warp: %.3f", circumfac);
2054         }
2055         
2056         circumfac*= (float)(-M_PI/360.0);
2057         
2058         for(i = 0 ; i < t->total; i++, td++) {
2059                 float loc[3];
2060                 if (td->flag & TD_NOACTION)
2061                         break;
2062
2063                 /* translate point to centre, rotate in such a way that outline==distance */
2064                 
2065                 VECCOPY(vec, td->iloc);
2066                 Mat3MulVecfl(td->mtx, vec);
2067                 Mat4MulVecfl(G.vd->viewmat, vec);
2068                 VecSubf(vec, vec, G.vd->viewmat[3]);
2069                 
2070                 dist= vec[0]-cursor[0];
2071
2072                 phi0= (circumfac*dist/t->val);  // t->val is X dimension projected boundbox
2073                 
2074                 vec[1]= (vec[1]-cursor[1]);
2075                 
2076                 co= (float)cos(phi0);
2077                 si= (float)sin(phi0);
2078                 loc[0]= -si*vec[1]+cursor[0];
2079                 loc[1]= co*vec[1]+cursor[1];
2080                 loc[2]= vec[2];
2081                 
2082                 Mat4MulVecfl(G.vd->viewinv, loc);
2083                 VecSubf(loc, loc, G.vd->viewinv[3]);
2084                 Mat3MulVecfl(td->smtx, loc);
2085
2086                 VecSubf(loc, loc, td->iloc);
2087                 VecMulf(loc, td->factor);
2088                 VecAddf(td->loc, td->iloc, loc);
2089         }
2090
2091         recalcData(t);
2092         
2093         headerprint(str);
2094         
2095         force_draw(0);
2096         
2097         helpline(gcursor);
2098         
2099         return 1;
2100 }
2101
2102 /* ************************** SHEAR *************************** */
2103
2104 void initShear(TransInfo *t) 
2105 {
2106         t->idx_max = 0;
2107         t->num.idx_max = 0;
2108         t->snap[0] = 0.0f;
2109         t->snap[1] = 0.1f;
2110         t->snap[2] = t->snap[1] * 0.1f;
2111         t->transform = Shear;
2112         t->fac = (float)(t->center2d[0] - t->imval[0]);
2113 }
2114
2115 int Shear(TransInfo *t, short mval[2]) 
2116 {
2117         TransData *td = t->data;
2118         float vec[3];
2119         float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
2120         float value;
2121         int i;
2122         char str[50];
2123
2124         Mat3CpyMat4(persmat, G.vd->viewmat);
2125         Mat3Inv(persinv, persmat);
2126
2127         value = -0.005f * ((float)(t->center2d[0] - mval[0]) - t->fac);
2128
2129         snapGrid(t, &value);
2130
2131         applyNumInput(&t->num, &value);
2132
2133         /* header print for NumInput */
2134         if (hasNumInput(&t->num)) {
2135                 char c[20];
2136
2137                 outputNumInput(&(t->num), c);
2138
2139                 sprintf(str, "Shear: %s %s", c, t->proptext);
2140         }
2141         else {
2142                 /* default header print */
2143                 sprintf(str, "Shear: %.3f %s", value, t->proptext);
2144         }
2145         
2146         Mat3One(smat);
2147         smat[1][0] = value;
2148         Mat3MulMat3(tmat, smat, persmat);
2149         Mat3MulMat3(totmat, persinv, tmat);
2150         
2151         for(i = 0 ; i < t->total; i++, td++) {
2152                 if (td->flag & TD_NOACTION)
2153                         break;
2154
2155                 if (G.obedit) {
2156                         float mat3[3][3];
2157                         Mat3MulMat3(mat3, totmat, td->mtx);
2158                         Mat3MulMat3(tmat, td->smtx, mat3);
2159                 }
2160                 else {
2161                         Mat3CpyMat3(tmat, totmat);
2162                 }
2163                 VecSubf(vec, td->center, t->center);
2164
2165                 Mat3MulVecfl(tmat, vec);
2166
2167                 VecAddf(vec, vec, t->center);
2168                 VecSubf(vec, vec, td->center);
2169
2170                 VecMulf(vec, td->factor);
2171
2172                 VecAddf(td->loc, td->iloc, vec);
2173         }
2174
2175         recalcData(t);
2176
2177         headerprint(str);
2178
2179         force_draw(0);
2180
2181         helpline (t->center);
2182
2183         return 1;
2184 }
2185
2186 /* ************************** RESIZE *************************** */
2187
2188 void initResize(TransInfo *t) 
2189 {
2190         t->fac = (float)sqrt( (float)
2191                 (
2192                         (t->center2d[1] - t->imval[1])*(t->center2d[1] - t->imval[1])
2193                 +
2194                         (t->center2d[0] - t->imval[0])*(t->center2d[0] - t->imval[0])
2195                 ) );
2196
2197         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2198         
2199         t->idx_max = 2;
2200         t->num.idx_max = 2;
2201         t->snap[0] = 0.0f;
2202         t->snap[1] = 0.1f;
2203         t->snap[2] = t->snap[1] * 0.1f;
2204         t->transform = Resize;
2205 }
2206
2207 static void headerResize(TransInfo *t, float vec[3], char *str) {
2208         char tvec[60];
2209         if (hasNumInput(&t->num)) {
2210                 outputNumInput(&(t->num), tvec);
2211         }
2212         else {
2213                 sprintf(&tvec[0], "%.4f", vec[0]);
2214                 sprintf(&tvec[20], "%.4f", vec[1]);
2215                 sprintf(&tvec[40], "%.4f", vec[2]);
2216         }
2217
2218         if (t->con.mode & CON_APPLY) {
2219                 switch(t->num.idx_max) {
2220                 case 0:
2221                         sprintf(str, "Size: %s%s %s", &tvec[0], t->con.text, t->proptext);
2222                         break;
2223                 case 1:
2224                         sprintf(str, "Size: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2225                         break;
2226                 case 2:
2227                         sprintf(str, "Size: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2228                 }
2229         }
2230         else {
2231                 sprintf(str, "Size X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2232         }
2233 }
2234
2235 int Resize(TransInfo *t, short mval[2]) 
2236 {
2237         TransData *td = t->data;
2238         float vec[3];
2239         float size[3], mat[3][3], tmat[3][3];
2240         float ratio;
2241         int i;
2242         char str[50];
2243
2244         /* for manipulator, center handle, the scaling can't be done relative to center */
2245         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
2246                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
2247         }
2248         else {
2249                 
2250                 if(t->flag & T_SHIFT_MOD) {
2251                         /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2252                         float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2253                         float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2254                         ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2255                         
2256                         dx= (float)(t->center2d[0] - mval[0]);
2257                         dy= (float)(t->center2d[1] - mval[1]);
2258                         ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
2259                         
2260                 }
2261                 else {
2262                         float dx= (float)(t->center2d[0] - mval[0]);
2263                         float dy= (float)(t->center2d[1] - mval[1]);
2264                         ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2265                 }
2266                 
2267                 /* flip scale, but not for manipulator center handle */
2268                 if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
2269                          (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
2270                                 ratio *= -1.0f;
2271         }
2272         
2273         size[0] = size[1] = size[2] = ratio;
2274
2275         snapGrid(t, size);
2276
2277         if (hasNumInput(&t->num)) {
2278                 applyNumInput(&t->num, size);
2279                 constraintNumInput(t, size);
2280         }
2281
2282         SizeToMat3(size, mat);
2283
2284         if (t->con.applySize) {
2285                 t->con.applySize(t, NULL, mat);
2286         }
2287
2288         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2289         
2290         headerResize(t, size, str);
2291
2292         for(i = 0 ; i < t->total; i++, td++) {
2293                 float smat[3][3];
2294                 if (td->flag & TD_NOACTION)
2295                         break;
2296
2297
2298                 if (t->flag & T_EDIT) {
2299                         Mat3MulMat3(smat, mat, td->mtx);
2300                         Mat3MulMat3(tmat, td->smtx, smat);
2301                 }
2302                 else {
2303                         Mat3CpyMat3(tmat, mat);
2304                 }
2305
2306                 if (t->con.applySize) {
2307                         t->con.applySize(t, td, tmat);
2308                 }
2309
2310                 if (G.vd->around == V3D_LOCAL) {
2311                         VECCOPY(t->center, td->center);
2312                 }
2313
2314                 if (td->ext) {
2315                         float fsize[3];
2316
2317                         if (t->flag & T_OBJECT) {
2318                                 float obsizemat[3][3];
2319                                 // Reorient the size mat to fit the oriented object.
2320                                 Mat3MulMat3(obsizemat, tmat, td->axismtx);
2321                                 Mat3ToSize(obsizemat, fsize);
2322                         }
2323                         else {
2324                                 Mat3ToSize(tmat, fsize);
2325                         }
2326                         
2327                         if ((G.vd->flag & V3D_ALIGN)==0) {      // align mode doesn't rotate objects itself
2328                                 /* handle ipokeys? */
2329                                 if(td->tdi) {
2330                                         TransDataIpokey *tdi= td->tdi;
2331                                         /* calculate delta size (equal for size and dsize) */
2332                                         
2333                                         vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
2334                                         vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
2335                                         vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
2336                                         
2337                                         add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
2338                                         add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
2339                                         add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
2340                                         
2341                                 }
2342                                 else {
2343                                         td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
2344                                         td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
2345                                         td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
2346                                 }
2347                         }
2348                 }
2349                 VecSubf(vec, td->center, t->center);
2350
2351                 Mat3MulVecfl(tmat, vec);
2352
2353                 VecAddf(vec, vec, t->center);
2354                 VecSubf(vec, vec, td->center);
2355
2356                 VecMulf(vec, td->factor);
2357
2358                 if (t->flag & T_OBJECT) {
2359                         Mat3MulVecfl(td->smtx, vec);
2360                 }
2361
2362                 VecAddf(td->loc, td->iloc, vec);
2363         }
2364
2365         recalcData(t);
2366
2367         headerprint(str);
2368
2369         force_draw(0);
2370
2371         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
2372
2373         return 1;
2374 }
2375
2376 /* ************************** TOSPHERE *************************** */
2377
2378 void initToSphere(TransInfo *t) 
2379 {
2380         TransData *td = t->data;
2381         int i;
2382
2383         // Calculate average radius
2384         for(i = 0 ; i < t->total; i++, td++) {
2385                 t->val += VecLenf(t->center, td->iloc);
2386         }
2387
2388         t->val /= (float)t->total;
2389
2390         Trans.fac = (float)sqrt( (float)
2391                 (
2392                         (Trans.center2d[1] - Trans.imval[1])*(Trans.center2d[1] - Trans.imval[1])
2393                 +
2394                         (Trans.center2d[0] - Trans.imval[0])*(Trans.center2d[0] - Trans.imval[0])
2395                 ) );
2396
2397         t->idx_max = 0;
2398         t->num.idx_max = 0;
2399         t->snap[0] = 0.0f;
2400         t->snap[1] = 0.1f;
2401         t->snap[2] = t->snap[1] * 0.1f;
2402         t->transform = ToSphere;
2403 }
2404
2405
2406
2407 int ToSphere(TransInfo *t, short mval[2]) 
2408 {
2409         float vec[3];
2410         float ratio, radius;
2411         int i;
2412         char str[50];
2413         TransData *td = t->data;
2414
2415         ratio = (float)sqrt( (float)
2416                 (
2417                         (t->center2d[1] - mval[1])*(t->center2d[1] - mval[1])
2418                 +
2419                         (t->center2d[0] - mval[0])*(t->center2d[0] - mval[0])
2420                 ) ) / t->fac;
2421
2422         snapGrid(t, &ratio);
2423
2424         applyNumInput(&t->num, &ratio);
2425
2426         if (ratio > 1.0f)
2427                 ratio = 1.0f;
2428
2429         /* header print for NumInput */
2430         if (hasNumInput(&t->num)) {
2431                 char c[20];
2432
2433                 outputNumInput(&(t->num), c);
2434
2435                 sprintf(str, "To Sphere: %s %s", c, t->proptext);
2436         }
2437         else {
2438                 /* default header print */
2439                 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
2440         }
2441         
2442         
2443         for(i = 0 ; i < t->total; i++, td++) {
2444                 float tratio;
2445                 if (td->flag & TD_NOACTION)
2446                         break;
2447
2448                 VecSubf(vec, td->iloc, t->center);
2449
2450                 radius = Normalise(vec);
2451
2452                 tratio = 1.0f - ((1.0f - ratio) * td->factor);
2453
2454                 VecMulf(vec, radius * tratio + t->val * (1.0f - tratio));
2455
2456                 VecAddf(td->loc, t->center, vec);
2457         }
2458
2459         recalcData(t);
2460
2461         headerprint(str);
2462
2463         force_draw(0);
2464
2465         helpline (t->center);
2466
2467         return 1;
2468 }
2469
2470 /* ************************** ROTATION *************************** */
2471
2472
2473 void initRotation(TransInfo *t) 
2474 {
2475         t->idx_max = 0;
2476         t->num.idx_max = 0;
2477         t->snap[0] = 0.0f;
2478         t->snap[1] = (float)((5.0/180)*M_PI);
2479         t->snap[2] = t->snap[1] * 0.2f;
2480         t->fac = 0;
2481         t->transform = Rotation;
2482 }
2483
2484 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
2485         float vec[3], totmat[3][3], smat[3][3];
2486         float eul[3], fmat[3][3], quat[4];
2487
2488         if (t->flag & T_EDIT) {
2489                 Mat3MulMat3(totmat, mat, td->mtx);
2490                 Mat3MulMat3(smat, td->smtx, totmat);
2491                 
2492                 VecSubf(vec, td->iloc, t->center);
2493                 Mat3MulVecfl(smat, vec);
2494                 
2495                 VecAddf(td->loc, vec, t->center);
2496
2497                 if(td->flag & TD_USEQUAT) {
2498                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2499                         Mat3ToQuat(fmat, quat); // Actual transform
2500                         QuatMul(td->ext->quat, quat, td->ext->iquat);
2501                 }
2502         }
2503         else {
2504                 /* translation */
2505                 VecSubf(vec, td->center, t->center);
2506                 Mat3MulVecfl(mat, vec);
2507                 VecAddf(vec, vec, t->center);
2508                 /* vec now is the location where the object has to be */
2509                 VecSubf(vec, vec, td->center);
2510                 Mat3MulVecfl(td->smtx, vec);
2511                 
2512                 VecAddf(td->loc, td->iloc, vec);
2513                 
2514                 if(td->flag & TD_USEQUAT) {
2515                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2516                         Mat3ToQuat(fmat, quat); // Actual transform
2517                         QuatMul(td->ext->quat, quat, td->ext->iquat);
2518                 }
2519                 else if ((G.vd->flag & V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2520                         float obmat[3][3];
2521                         
2522                         /* are there ipo keys? */
2523                         if(td->tdi) {
2524                                 TransDataIpokey *tdi= td->tdi;
2525                                 float rot[3];
2526                                 
2527                                 /* calculate the total rotatation in eulers */
2528                                 VecAddf(eul, td->ext->irot, td->ext->drot);
2529                                 EulToMat3(eul, obmat);
2530                                 /* mat = transform, obmat = object rotation */
2531                                 Mat3MulMat3(fmat, mat, obmat);
2532                                 Mat3ToEul(fmat, eul);
2533                                 compatible_eul(eul, td->ext->irot);
2534                                 
2535                                 /* correct back for delta rot */
2536                                 if(tdi->flag & TOB_IPODROT) {
2537                                         VecSubf(rot, eul, td->ext->irot);
2538                                 }
2539                                 else {
2540                                         VecSubf(rot, eul, td->ext->drot);
2541                                 }
2542                                 
2543                                 VecMulf(rot, (float)(9.0/M_PI_2));
2544                                 VecSubf(rot, rot, tdi->oldrot);
2545                                 
2546                                 add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
2547                                 add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
2548                                 add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
2549                         }
2550                         else {
2551                                 
2552                                 /* calculate the total rotatation in eulers */
2553                                 VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
2554                                 EulToMat3(eul, obmat);
2555                                 /* mat = transform, obmat = object rotation */
2556                                 Mat3MulMat3(fmat, mat, obmat);
2557                                 Mat3ToEul(fmat, eul);
2558                                 compatible_eul(eul, td->ext->irot);
2559                                 
2560                                 /* correct back for delta rot */
2561                                 VecSubf(eul, eul, td->ext->drot);
2562                                 /* and apply */
2563                                 VECCOPY(td->ext->rot, eul);
2564                         }
2565                 }
2566         }
2567 }
2568
2569 static void applyRotation(TransInfo *t, float angle, float axis[3]) 
2570 {
2571         TransData *td = t->data;
2572         float mat[3][3];
2573         int i;
2574
2575         VecRotToMat3(axis, angle, mat);
2576
2577         for(i = 0 ; i < t->total; i++, td++) {
2578                 if (td->flag & TD_NOACTION)
2579                         break;
2580                 
2581                 if (G.vd->around == V3D_LOCAL) {
2582                         VECCOPY(t->center, td->center);
2583                 }
2584                 
2585                 if (t->con.applyRot) {
2586                         t->con.applyRot(t, td, axis);
2587                         VecRotToMat3(axis, angle * td->factor, mat);
2588                 }
2589                 else if (G.f & G_PROPORTIONAL) {
2590                         VecRotToMat3(axis, angle * td->factor, mat);
2591                 }
2592
2593                 ElementRotation(t, td, mat);
2594         }
2595 }
2596
2597 int Rotation(TransInfo *t, short mval[2]) 
2598 {
2599         TransData *td = t->data;
2600         char str[50];
2601
2602         float final;
2603
2604         int dx2 = t->center2d[0] - mval[0];
2605         int dy2 = t->center2d[1] - mval[1];
2606         float B = (float)sqrt(dx2*dx2+dy2*dy2);
2607
2608         int dx1 = t->center2d[0] - t->imval[0];
2609         int dy1 = t->center2d[1] - t->imval[1];
2610         float A = (float)sqrt(dx1*dx1+dy1*dy1);
2611
2612         int dx3 = mval[0] - t->imval[0];
2613         int dy3 = mval[1] - t->imval[1];
2614
2615         float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
2616                 / (2 * (A*B?A*B:1.0f));
2617         /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
2618
2619         float dphi;
2620
2621         float axis[3];
2622         float mat[3][3];
2623
2624         VECCOPY(axis, t->persinv[2]);
2625         Normalise(axis);
2626
2627         dphi = saacos(deler);
2628         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
2629
2630         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2631         else t->fac += dphi;
2632
2633         /*
2634         clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
2635         if (t->fac >= 2 * M_PI)
2636                 t->fac -= 2 * M_PI;
2637         else if (t->fac <= -2 * M_PI)
2638                 t->fac -= -2 * M_PI;
2639         */
2640
2641         final = t->fac;
2642
2643         snapGrid(t, &final);
2644
2645         t->imval[0] = mval[0];
2646         t->imval[1] = mval[1];
2647
2648         if (t->con.applyRot) {
2649                 t->con.applyRot(t, NULL, axis);
2650         }
2651
2652         if (hasNumInput(&t->num)) {
2653                 char c[20];
2654
2655                 applyNumInput(&t->num, &final);
2656
2657                 outputNumInput(&(t->num), c);
2658
2659                 sprintf(str, "Rot: %s %s", &c[0], t->proptext);
2660
2661                 final *= (float)(M_PI / 180.0);
2662         }
2663         else {
2664                 sprintf(str, "Rot: %.2f %s", 180.0*final/M_PI, t->proptext);
2665         }
2666
2667         VecRotToMat3(axis, final * td->factor, mat);
2668
2669         t->val = final;                         // used in manipulator
2670         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2671         
2672         applyRotation(t, final, axis);
2673         
2674         recalcData(t);
2675
2676         headerprint(str);
2677
2678         force_draw(0);
2679
2680         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
2681
2682         return 1;
2683 }
2684
2685
2686 /* ************************** TRACKBALL *************************** */
2687
2688 void initTrackball(TransInfo *t) 
2689 {
2690         t->idx_max = 1;
2691         t->num.idx_max = 1;
2692         t->snap[0] = 0.0f;
2693         t->snap[1] = (float)((5.0/180)*M_PI);
2694         t->snap[2] = t->snap[1] * 0.2f;
2695         t->fac = 0;
2696         t->transform = Trackball;
2697 }
2698
2699 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
2700 {
2701         TransData *td = t->data;
2702         float mat[3][3], smat[3][3], totmat[3][3];
2703         int i;
2704
2705         VecRotToMat3(axis1, angles[0], smat);
2706         VecRotToMat3(axis2, angles[1], totmat);
2707         
2708         Mat3MulMat3(mat, smat, totmat);
2709
2710         for(i = 0 ; i < t->total; i++, td++) {
2711                 if (td->flag & TD_NOACTION)
2712                         break;
2713                 
2714                 if (G.vd->around == V3D_LOCAL) {
2715                         VECCOPY(t->center, td->center);
2716                 }
2717                 
2718                 if (G.f & G_PROPORTIONAL) {
2719                         VecRotToMat3(axis1, td->factor * angles[0], smat);
2720                         VecRotToMat3(axis2, td->factor * angles[1], totmat);
2721                         
2722                         Mat3MulMat3(mat, smat, totmat);
2723                 }
2724
2725                 ElementRotation(t, td, mat);
2726         }
2727 }
2728
2729 int Trackball(TransInfo *t, short mval[2]) 
2730 {
2731         char str[80];
2732         float axis1[3], axis2[3];
2733         float mat[3][3], totmat[3][3], smat[3][3];
2734         float phi[2];
2735         
2736         VECCOPY(axis1, t->persinv[0]);
2737         VECCOPY(axis2, t->persinv[1]);
2738         Normalise(axis1);
2739         Normalise(axis2);
2740         
2741         /* factore has to become setting or so */
2742         phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
2743         phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
2744         
2745         //if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2746         //else t->fac += dphi;
2747         
2748         snapGrid(t, phi);
2749         
2750         if (hasNumInput(&t->num)) {
2751                 char c[40];
2752                 
2753                 applyNumInput(&t->num, phi);
2754                 
2755                 outputNumInput(&(t->num), c);
2756                 
2757                 sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
2758                 
2759                 phi[0] *= (float)(M_PI / 180.0);
2760                 phi[1] *= (float)(M_PI / 180.0);
2761         }
2762         else {
2763                 sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
2764         }
2765         
2766         VecRotToMat3(axis1, phi[0], smat);
2767         VecRotToMat3(axis2, phi[1], totmat);
2768         
2769         Mat3MulMat3(mat, smat, totmat);
2770         
2771         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2772         
2773         applyTrackball(t, axis1, axis2, phi);
2774         
2775         recalcData(t);
2776         
2777         headerprint(str);
2778         
2779         force_draw(0);
2780         
2781         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
2782         
2783         return 1;
2784 }
2785
2786 /* ************************** TRANSLATION *************************** */
2787         
2788 void initTranslation(TransInfo *t) 
2789 {
2790         t->idx_max = 2;
2791         t->num.idx_max = 2;
2792         t->snap[0] = 0.0f;
2793         t->snap[1] = G.vd->gridview * 1.0f;
2794         t->snap[2] = t->snap[1] * 0.1f;
2795         t->transform = Translation;
2796         
2797         /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
2798         if (G.obedit) {
2799                 float vec[3];
2800                 
2801                 VECCOPY(vec, t->center);
2802                 Mat4MulVecfl(G.obedit->obmat, vec);
2803                 initgrabz(vec[0], vec[1], vec[2]);
2804         }
2805         else initgrabz(t->center[0], t->center[1], t->center[2]); 
2806 }
2807
2808 static void headerTranslation(TransInfo *t, float vec[3], char *str) {
2809         char tvec[60];
2810         if (hasNumInput(&t->num)) {
2811                 outputNumInput(&(t->num), tvec);
2812         }
2813         else {
2814                 sprintf(&tvec[0], "%.4f", vec[0]);
2815                 sprintf(&tvec[20], "%.4f", vec[1]);
2816                 sprintf(&tvec[40], "%.4f", vec[2]);
2817         }
2818
2819         if (t->con.mode & CON_APPLY) {
2820                 switch(t->num.idx_max) {
2821                 case 0:
2822                         sprintf(str, "D: %s%s %s", &tvec[0], t->con.text, t->proptext);
2823                         break;
2824                 case 1:
2825                         sprintf(str, "D: %s   D: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2826                         break;
2827                 case 2:
2828                         sprintf(str, "D: %s   D: %s  D: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2829                 }
2830         }
2831         else {
2832                 sprintf(str, "Dx: %s   Dy: %s  Dz: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2833         }
2834 }
2835
2836 static void applyTranslation(TransInfo *t, float vec[3]) {
2837         TransData *td = t->data;
2838         float tvec[3];
2839         int i;
2840
2841         for(i = 0 ; i < t->total; i++, td++) {
2842                 if (td->flag & TD_NOACTION)
2843                         break;
2844
2845                 if (t->con.applyVec) {
2846                         float pvec[3];
2847                         t->con.applyVec(t, td, vec, tvec, pvec);
2848                 }
2849                 else {
2850                         VECCOPY(tvec, vec);
2851                 }
2852
2853                 Mat3MulVecfl(td->smtx, tvec);
2854                 VecMulf(tvec, td->factor);
2855                 
2856                 /* transdata ipokey */
2857                 if(td->tdi) {
2858                         TransDataIpokey *tdi= td->tdi;
2859                         add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
2860                         add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
2861                         add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
2862                 }
2863                 else VecAddf(td->loc, td->iloc, tvec);
2864         }
2865 }
2866
2867 /* uses t->vec to store actual translation in */
2868 int Translation(TransInfo *t, short mval[2]) 
2869 {
2870         float tvec[3];
2871         char str[200];
2872         
2873         if(t->flag & T_SHIFT_MOD) {
2874                 float dvec[3];
2875                 /* calculate the main translation and the precise one separate */
2876                 window_to_3d(dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
2877                 VecMulf(dvec, 0.1f);
2878                 window_to_3d(t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
2879                 VecAddf(t->vec, t->vec, dvec);
2880         }
2881         else window_to_3d(t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2882
2883         if (t->con.mode & CON_APPLY) {
2884                 float pvec[3] = {0.0f, 0.0f, 0.0f};
2885                 t->con.applyVec(t, NULL, t->vec, tvec, pvec);
2886                 VECCOPY(t->vec, tvec);
2887                 headerTranslation(t, pvec, str);
2888         }
2889         else {
2890                 snapGrid(t, t->vec);
2891                 applyNumInput(&t->num, t->vec);
2892                 headerTranslation(t, t->vec, str);
2893         }
2894
2895         applyTranslation(t, t->vec);
2896
2897         recalcData(t);
2898
2899         headerprint(str);
2900
2901         force_draw(0);
2902
2903         return 1;
2904 }
2905
2906 /* ************************** SHRINK/FATTEN *************************** */
2907
2908 void initShrinkFatten(TransInfo *t) 
2909 {
2910         if (G.obedit==NULL || G.obedit->type != OB_MESH) {
2911                 initTransModeFlags(t, TFM_RESIZE);
2912                 initResize(t);
2913                 return;
2914         }
2915
2916         t->idx_max = 0;
2917         t->num.idx_max = 0;
2918         t->snap[0] = 0.0f;
2919         t->snap[1] = 1.0f;
2920         t->snap[2] = t->snap[1] * 0.1f;
2921         t->transform = ShrinkFatten;
2922 }
2923
2924
2925
2926 int ShrinkFatten(TransInfo *t, short mval[2]) 
2927 {
2928         float vec[3];
2929         float ratio;
2930         int i;
2931         char str[50];
2932         TransData *td = t->data;
2933
2934         window_to_3d(t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2935         Projf(vec, t->vec, G.vd->viewinv[1]);
2936         ratio = Normalise(vec);
2937
2938         if (mval[1] < t->imval[1])
2939                 ratio *= -1;
2940
2941         snapGrid(t, &ratio);
2942
2943         applyNumInput(&t->num, &ratio);
2944
2945         /* header print for NumInput */
2946         if (hasNumInput(&t->num)) {
2947                 char c[20];
2948
2949                 outputNumInput(&(t->num), c);
2950
2951                 sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
2952         }
2953         else {
2954                 /* default header print */
2955                 sprintf(str, "Shrink/Fatten: %.4f %s", ratio, t->proptext);
2956         }
2957         
2958         
2959         for(i = 0 ; i < t->total; i++, td++) {
2960                 if (td->flag & TD_NOACTION)
2961                         break;
2962
2963                 VECCOPY(vec, td->axismtx[2]);
2964                 VecMulf(vec, ratio);
2965                 VecMulf(vec, td->factor);
2966
2967                 VecAddf(td->loc, td->iloc, vec);
2968         }
2969
2970         recalcData(t);
2971
2972         headerprint(str);
2973
2974         force_draw(0);
2975
2976         return 1;
2977 }
2978
2979 /* ************************** TILT *************************** */
2980
2981 void initTilt(TransInfo *t) 
2982 {
2983         t->idx_max = 0;
2984         t->num.idx_max = 0;
2985         t->snap[0] = 0.0f;
2986         t->snap[1] = (float)((5.0/180)*M_PI);
2987         t->snap[2] = t->snap[1] * 0.2f;
2988         t->fac = 0;
2989         t->transform = Tilt;
2990 }
2991
2992
2993
2994 int Tilt(TransInfo *t, short mval[2]) 
2995 {
2996         TransData *td = t->data;
2997         int i;
2998         char str[50];
2999
3000         float final;
3001
3002         int dx2 = t->center2d[0] - mval[0];
3003         int dy2 = t->center2d[1] - mval[1];
3004         float B = (float)sqrt(dx2*dx2+dy2*dy2);
3005
3006         int dx1 = t->center2d[0] - t->imval[0];
3007         int dy1 = t->center2d[1] - t->imval[1];
3008         float A = (float)sqrt(dx1*dx1+dy1*dy1);
3009
3010         int dx3 = mval[0] - t->imval[0];
3011         int dy3 = mval[1] - t->imval[1];
3012
3013         float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
3014                 / (2 * A * B);
3015
3016         float dphi;
3017
3018         dphi = saacos(deler);
3019         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
3020
3021         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
3022         else t->fac += dphi;
3023
3024         final = t->fac;
3025
3026         snapGrid(t, &final);
3027
3028         t->imval[0] = mval[0];
3029         t->imval[1] = mval[1];
3030
3031         if (hasNumInput(&t->num)) {
3032                 char c[20];
3033
3034                 applyNumInput(&t->num, &final);
3035
3036                 outputNumInput(&(t->num), c);
3037
3038                 sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
3039
3040                 final *= (float)(M_PI / 180.0);
3041         }
3042         else {
3043                 sprintf(str, "Tilt: %.2f %s", 180.0*final/M_PI, t->proptext);
3044         }
3045
3046         for(i = 0 ; i < t->total; i++, td++) {
3047                 if (td->flag & TD_NOACTION)
3048                         break;
3049
3050                 if (td->val) {
3051                         *td->val = td->ival + final * td->factor;
3052                 }
3053         }
3054
3055         recalcData(t);
3056
3057         headerprint(str);
3058
3059         force_draw(0);
3060
3061         helpline (t->center);
3062
3063         return 1;
3064 }
3065