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