Transform project.
[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 #include "BLI_winstuff.h"
46 #endif
47
48 #include "MEM_guardedalloc.h"
49
50 #include "DNA_action_types.h"
51 #include "DNA_armature_types.h"
52 #include "DNA_camera_types.h"
53 #include "DNA_curve_types.h"
54 #include "DNA_effect_types.h"
55 #include "DNA_ika_types.h"
56 #include "DNA_image_types.h"
57 #include "DNA_ipo_types.h"
58 #include "DNA_key_types.h"
59 #include "DNA_lamp_types.h"
60 #include "DNA_lattice_types.h"
61 #include "DNA_mesh_types.h"
62 #include "DNA_meshdata_types.h"
63 #include "DNA_meta_types.h"
64 #include "DNA_object_types.h"
65 #include "DNA_scene_types.h"
66 #include "DNA_screen_types.h"
67 #include "DNA_texture_types.h"
68 #include "DNA_view3d_types.h"
69 #include "DNA_world_types.h"
70 #include "DNA_userdef_types.h"
71 #include "DNA_property_types.h"
72 #include "DNA_vfont_types.h"
73 #include "DNA_constraint_types.h"
74
75 #include "BIF_editview.h"
76 #include "BIF_resources.h"
77 #include "BIF_mywindow.h"
78 #include "BIF_gl.h"
79 #include "BIF_editlattice.h"
80 #include "BIF_editarmature.h"
81 #include "BIF_editmesh.h"
82 #include "BIF_screen.h"
83 #include "BIF_space.h"
84 #include "BIF_toolbox.h"
85
86 #include "BKE_action.h"
87 #include "BKE_armature.h"
88 #include "BKE_blender.h"
89 #include "BKE_curve.h"
90 #include "BKE_displist.h"
91 #include "BKE_effect.h"
92 #include "BKE_global.h"
93 #include "BKE_ipo.h"
94 #include "BKE_lattice.h"
95 #include "BKE_mball.h"
96 #include "BKE_object.h"
97 #include "BKE_utildefines.h"
98
99 #include "BSE_view.h"
100 #include "BSE_edit.h"
101 #include "BSE_editipo.h"
102 #include "BSE_editipo_types.h"
103 #include "BDR_editobject.h"             // reset_slowparents()
104
105 #include "BLI_arithb.h"
106 #include "BLI_editVert.h"
107 #include "BLI_ghash.h"
108
109 #include "PIL_time.h"
110
111 #include "blendef.h"
112
113 #include "mydevice.h"
114
115 extern ListBase editNurb;
116 extern ListBase editelems;
117
118 extern void helpline(float *vec);
119
120
121 #include "transform.h"
122 #include "transform_generics.h"
123 #include "transform_constraints.h"
124 #include "transform_numinput.h"
125
126 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING  */
127 TransInfo Trans;
128 int     LastMode = TFM_TRANSLATION;
129
130 /* ************************** Functions *************************** */
131
132 /* ************************** CONVERSIONS ************************* */
133
134 static int allocTransData(void)
135 {
136         int count, mode=0;
137         countall();
138         
139         if(mode) count= G.totvert;
140         else count= G.totvertsel;
141         printf("count: %d\n", count);
142         if(G.totvertsel==0) {
143                 count= 0;
144                 return count;
145         }
146         
147         Trans.total = count;
148         Trans.data= MEM_mallocN(Trans.total*sizeof(TransData), "TransObData(EditMode)");
149         return count;
150 }
151
152 /* ********************* pose mode ************* */
153
154 /* callback, make sure it's identical structured as next one */
155 static void count_bone_select(ListBase *lb, int *counter) 
156 {
157         Bone *bone;
158         
159         for(bone= lb->first; bone; bone= bone->next) {
160                 if (bone->flag & BONE_SELECTED) {
161                         /* We don't let IK children get "grabbed" */
162                         /* ALERT! abusive global Trans here */
163                         if ( (Trans.mode!=TFM_TRANSLATION) || (bone->flag & BONE_IK_TOPARENT)==0 ) {
164                                 (*counter)++;
165                                 return; // no transform on children if one parent bone is selected
166                         }
167                 }
168                 count_bone_select( &bone->childbase, counter);
169         }
170 }
171
172 /* callback */
173 static void add_pose_transdata(ListBase *lb, Object *ob, TransData **tdp)
174 {
175         Bone *bone;
176         TransData *td= *tdp;
177         float   parmat[4][4], tempmat[4][4];
178         float tempobmat[4][4];
179         float vec[3];
180         
181         for(bone= lb->first; bone; bone= bone->next) {
182                 if (bone->flag & BONE_SELECTED) {
183                         /* We don't let IK children get "grabbed" */
184                         /* ALERT! abusive global Trans here */
185                         if ( (Trans.mode!=TFM_TRANSLATION) || (bone->flag & BONE_IK_TOPARENT)==0 ) {
186                                 
187                                 get_bone_root_pos (bone, vec, 1);
188                                 
189                                 //VecAddf (centroid, centroid, vec);
190                                 VECCOPY(td->center, vec);
191                                 
192                                 td->ob = ob;
193                                 td->dist= 0.0f;
194                                 td->flag= TD_SELECTED|TD_USEQUAT;
195                                 td->loc = bone->loc;
196                                 VECCOPY(td->iloc, bone->loc);
197                                 
198                                 td->ext->rot= NULL;
199                                 td->ext->quat= bone->quat;
200                                 td->ext->size= bone->size;
201                                 td->ext->bone= bone; // FIXME: Dangerous
202
203                                 QUATCOPY(td->ext->iquat, bone->quat);
204                                 VECCOPY(td->ext->isize, bone->size);
205                                 
206                                 /* Get the matrix of this bone minus the usertransform */
207                                 Mat4CpyMat4 (tempobmat, bone->obmat);
208                                 Mat4One (bone->obmat);
209                                 get_objectspace_bone_matrix(bone, tempmat, 1, 1);
210                                 Mat4CpyMat4 (bone->obmat, tempobmat);
211
212                                 Mat4MulMat4 (parmat, tempmat, ob->obmat);       /* Original */
213                                 
214                                 Mat3CpyMat4 (td->mtx, parmat);
215                                 Mat3Inv (td->smtx, td->mtx);
216                                 
217                                 (*tdp)++;
218                                 return; // see above function
219                         }
220                 }
221                 add_pose_transdata(&bone->childbase, ob, tdp);
222         }
223 }
224
225 static void createTransPose(void)
226 {
227         bArmature *arm;
228         TransData *td;
229         TransDataExtension *tdx;
230         int i;
231         
232         Trans.total= 0; // to be able to return
233         
234         /* check validity of state */
235         arm=get_armature (G.obpose);
236         if (arm==NULL) return;
237         
238         if (arm->flag & ARM_RESTPOS){
239                 notice ("Transformation not possible while Rest Position is enabled");
240                 return;
241         }
242         if (!(G.obpose->lay & G.vd->lay)) return;
243
244         /* copied from old code, no idea. we let linker solve it for now */
245         {
246                 extern void figure_bone_nocalc(Object *ob);
247                 extern void figure_pose_updating(void);
248
249                 /* figure out which bones need calculating */
250                 figure_bone_nocalc(G.obpose);
251                 figure_pose_updating();
252         }
253         
254         /* copied from old code, no idea... (ton) */
255         apply_pose_armature(arm, G.obpose->pose, 0);
256         where_is_armature (G.obpose);
257         
258         /* count total */
259         count_bone_select(&arm->bonebase, &Trans.total);
260         
261         if(Trans.total==0 && Trans.mode==TFM_TRANSLATION) {
262                 Trans.mode= TFM_ROTATION;
263                 count_bone_select(&arm->bonebase, &Trans.total);
264         }               
265         if(Trans.total==0) return;
266         
267         /* init trans data */
268     td = Trans.data = MEM_mallocN(Trans.total*sizeof(TransData), "TransPoseBone");
269     tdx = MEM_mallocN(Trans.total*sizeof(TransDataExtension), "TransPoseBoneExt");
270         for(i=0; i<Trans.total; i++, td++, tdx++) {
271                 td->ext= tdx;
272                 td->tdi = NULL;
273         }       
274         /* recursive fill trans data */
275         td= Trans.data;
276         add_pose_transdata(&arm->bonebase, G.obpose, &td);
277         
278 }
279
280 static void createTransArmatureVerts(void)
281 {
282         EditBone *ebo;
283         TransData *td;
284         float mtx[3][3], smtx[3][3];
285
286         Trans.total = 0;
287         for (ebo=G.edbo.first;ebo;ebo=ebo->next){
288                 if (ebo->flag & BONE_TIPSEL){
289                         Trans.total++;
290                 }
291                 if (ebo->flag & BONE_ROOTSEL){
292                         Trans.total++;
293                 }
294         }
295
296     if (!Trans.total) return;
297         
298         Mat3CpyMat4(mtx, G.obedit->obmat);
299         Mat3Inv(smtx, mtx);
300
301     td = Trans.data = MEM_mallocN(Trans.total*sizeof(TransData), "TransEditBone");
302         
303         for (ebo=G.edbo.first;ebo;ebo=ebo->next){
304                 if (ebo->flag & BONE_TIPSEL){
305                         VECCOPY (td->iloc, ebo->tail);
306                         td->loc= ebo->tail;
307                         td->flag= TD_SELECTED;
308
309                         Mat3CpyMat3(td->smtx, smtx);
310                         Mat3CpyMat3(td->mtx, mtx);
311
312                         td->ext = NULL;
313                         td->tdi = NULL;
314
315                         td->dist = 0.0f;
316                         
317                         td++;
318                 }
319                 if (ebo->flag & BONE_ROOTSEL){
320                         VECCOPY (td->iloc, ebo->head);
321                         td->loc= ebo->head;
322                         td->flag= TD_SELECTED;
323
324                         Mat3CpyMat3(td->smtx, smtx);
325                         Mat3CpyMat3(td->mtx, mtx);
326
327                         td->ext = NULL;
328                         td->tdi = NULL;
329
330                         td->dist = 0.0f;
331                 
332                         td++;
333                 }
334                         
335         }
336 }
337
338 static void createTransMBallVerts(void)
339 {
340         MetaElem *ml;
341         TransData *td;
342         TransDataExtension *tx;
343         float mtx[3][3], smtx[3][3];
344         int count;
345
346         count = allocTransData();
347         if (!count) return;
348
349         tx = MEM_mallocN(Trans.total*sizeof(TransDataExtension), "MetaElement_TransExtension");
350
351         Mat3CpyMat4(mtx, G.obedit->obmat);
352         Mat3Inv(smtx, mtx);
353     
354         td = Trans.data;
355     ml= editelems.first;
356         while(ml) {
357                 if(ml->flag & SELECT) {
358                         td->loc= &ml->x;
359                         VECCOPY(td->iloc, td->loc);
360                         VECCOPY(td->center, td->loc);
361                         td->flag= TD_SELECTED;
362
363                         Mat3CpyMat3(td->smtx, smtx);
364                         Mat3CpyMat3(td->mtx, mtx);
365
366                         td->ext = tx;
367                         td->tdi = NULL;
368
369                         tx->size = &ml->expx;
370                         tx->isize[0] = ml->expx;
371                         tx->isize[1] = ml->expy;
372                         tx->isize[2] = ml->expz;
373
374                         tx->rot = NULL;
375
376                         td->dist = 0.0f;
377
378                         td++;
379                         tx++;
380                 }
381                 ml= ml->next;
382         }
383
384
385 static void createTransCurveVerts(void)
386 {
387         TransData *td = NULL;
388         Nurb *nu;
389         BezTriple *bezt;
390         BPoint *bp;
391         float mtx[3][3], smtx[3][3];
392         int a;
393         int count=0;
394         int mode = 0; /*This used for. . .what?*/
395         //int proptrans= 0;
396
397         count = allocTransData();
398         if (!count) return;
399
400         Mat3CpyMat4(mtx, G.obedit->obmat);
401         Mat3Inv(smtx, mtx);
402
403     td = Trans.data;
404         nu= editNurb.first;
405         while(nu) {
406                 if((nu->type & 7)==CU_BEZIER) {
407                         a= nu->pntsu;
408                         bezt= nu->bezt;
409                         while(a--) {
410                                 if(bezt->hide==0) {
411                                         if(mode==1 || (bezt->f1 & 1)) {
412                                                 VECCOPY(td->iloc, bezt->vec[0]);
413                                                 td->loc= bezt->vec[0];
414                                                 VECCOPY(td->center, td->loc);
415                                                 td->flag= TD_SELECTED;
416                                                 td->ext = NULL;
417                                                 td->tdi = NULL;
418
419                                                 Mat3CpyMat3(td->smtx, smtx);
420                                                 Mat3CpyMat3(td->mtx, mtx);
421
422                                                 td->dist = 0.0f;
423                         
424                                                 td++;
425                                                 count++;
426                                         }
427                                         if(mode==1 || (bezt->f2 & 1)) {
428                                                 VECCOPY(td->iloc, bezt->vec[1]);
429                                                 td->loc= bezt->vec[1];
430                                                 VECCOPY(td->center, td->loc);
431                                                 td->flag= TD_SELECTED;
432                                                 td->ext = NULL;
433                                                 td->tdi = NULL;
434
435                                                 Mat3CpyMat3(td->smtx, smtx);
436                                                 Mat3CpyMat3(td->mtx, mtx);
437
438                                                 td->dist = 0.0f;
439                         
440                                                 td++;
441                                                 count++;
442                                         }
443                                         if(mode==1 || (bezt->f3 & 1)) {
444                                                 VECCOPY(td->iloc, bezt->vec[2]);
445                                                 td->loc= bezt->vec[2];
446                                                 VECCOPY(td->center, td->loc);
447                                                 td->flag= TD_SELECTED;
448                                                 td->ext = NULL;
449                                                 td->tdi = NULL;
450
451                                                 Mat3CpyMat3(td->smtx, smtx);
452                                                 Mat3CpyMat3(td->mtx, mtx);
453
454                                                 td->dist = 0.0f;
455                         
456                                                 td++;
457                                                 count++;
458                                         }
459                                 }
460                                 bezt++;
461                         }
462                 }
463                 else {
464                         a= nu->pntsu*nu->pntsv;
465                         bp= nu->bp;
466                         while(a--) {
467                                 if(bp->hide==0) {
468                                         if(mode==1 || (bp->f1 & 1)) {
469                                                 VECCOPY(td->iloc, bp->vec);
470                                                 td->loc= bp->vec;
471                                                 VECCOPY(td->center, td->loc);
472                                                 td->flag= TD_SELECTED;
473                                                 td->ext = NULL;
474                                                 td->tdi = NULL;
475
476                                                 Mat3CpyMat3(td->smtx, smtx);
477                                                 Mat3CpyMat3(td->mtx, mtx);
478
479                                                 td->dist = 0.0f;
480                         
481                                                 td++;
482                                                 count++;
483                                         }
484                                 }
485                                 bp++;
486                         }
487                 }
488                 nu= nu->next;
489         }
490 }
491
492 static void createTransLatticeVerts(void)
493 {
494         TransData *td = NULL;
495         int count = 0;
496         BPoint *bp;
497         float mtx[3][3], smtx[3][3];
498         int mode = 0; /*This used for proportional editing*/
499         /*should find a function that does this. . . what else is this used for? I DONT KNOW!*/
500         int a;
501         //int proptrans= 0;
502
503         bp= editLatt->def;
504         
505         
506         count = allocTransData();
507         
508         if (!count) return;
509         
510         Mat3CpyMat4(mtx, G.obedit->obmat);
511         Mat3Inv(smtx, mtx);
512
513         td = Trans.data;
514         bp= editLatt->def;
515         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
516         while(a--) {
517                 if(mode==1 || (bp->f1 & 1)) {
518                         if(bp->hide==0) {
519                                 VECCOPY(td->iloc, bp->vec);
520                                 td->loc= bp->vec;
521                                 VECCOPY(td->center, td->loc);
522                                 td->flag= TD_SELECTED;
523
524                                 Mat3CpyMat3(td->smtx, smtx);
525                                 Mat3CpyMat3(td->mtx, mtx);
526
527                                 td->ext = NULL;
528                                 td->tdi = NULL;
529
530                                 td->dist = 0.0f;
531
532                                 td++;
533                                 count++;
534                         }
535                 }
536                 bp++;
537         }
538
539
540 static void VertsToTransData(TransData *td, EditVert *eve)
541 {
542         td->flag = 0;
543         td->loc = eve->co;
544         VECCOPY(td->center, td->loc);
545         VECCOPY(td->iloc, td->loc);
546         td->ext = NULL;
547         td->tdi = NULL;
548 }
549
550 static void createTransEditVerts(void)
551 {
552         TransData *tob = NULL;
553         int totsel = 0;
554         EditMesh *em = G.editMesh;
555         EditVert *eve;
556         float mtx[3][3], smtx[3][3];
557         /*should find a function that does this. . .*/
558         // int proptrans= 0;
559                 
560         // transform now requires awareness for select mode, so we tag the f1 flags in verts
561         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
562                 for(eve= em->verts.first; eve; eve= eve->next) {
563                         if(eve->h==0 && (eve->f & SELECT)) {
564                                 eve->f1= SELECT;
565                                 Trans.total++;
566                         }
567                         else
568                                 eve->f1= 0;
569                 }
570         }
571         else if(G.scene->selectmode & SCE_SELECT_EDGE) {
572                 EditEdge *eed;
573                 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
574                 for(eed= em->edges.first; eed; eed= eed->next) {
575                         if(eed->h==0 && (eed->f & SELECT))
576                                 eed->v1->f1= eed->v2->f1= SELECT;
577                 }
578                 for(eve= em->verts.first; eve; eve= eve->next)
579                         if(eve->f1)
580                                 Trans.total++;
581         }
582         else {
583                 EditFace *efa;
584                 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
585                 for(efa= em->faces.first; efa; efa= efa->next) {
586                         if(efa->h==0 && (efa->f & SELECT)) {
587                                 efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
588                                 if(efa->v4) efa->v4->f1= SELECT;
589                         }
590                 }
591                 for(eve= em->verts.first; eve; eve= eve->next)
592                         if(eve->f1)
593                                 Trans.total++;
594         }
595         
596         totsel = Trans.total;
597         /* proportional edit exception... */
598         if((G.f & G_PROPORTIONAL) && Trans.total) {
599                 for(eve= em->verts.first; eve; eve= eve->next) {
600                         if(eve->h==0 && (!(eve->f1 & SELECT))) {
601                                 eve->f1 = 2;
602                                 Trans.total++;
603                         }
604                 }
605         }
606         
607         /* and now make transverts */
608     if (!Trans.total) return;
609         
610         Mat3CpyMat4(mtx, G.obedit->obmat);
611         Mat3Inv(smtx, mtx);
612
613     tob = Trans.data = MEM_mallocN(Trans.total*sizeof(TransData), "TransEditVert");
614
615         for (eve=em->verts.first; eve; eve=eve->next)
616         {
617                 if (eve->f1 == SELECT) {
618                         VertsToTransData(tob, eve);
619
620                         tob->flag |= TD_SELECTED;
621
622                         Mat3CpyMat3(tob->smtx, smtx);
623                         Mat3CpyMat3(tob->mtx, mtx);
624
625                         tob->dist = 0.0f;
626
627                         tob++;
628                 }       
629         }       
630
631         /* PROPORTIONAL*/
632         if (G.f & G_PROPORTIONAL) {
633                 for (eve=em->verts.first; eve; eve=eve->next)
634                 {
635                         TransData *td;
636                         int i;
637                         float dist, vec[3];
638                         if (eve->f1 == 2) {
639
640                                 VertsToTransData(tob, eve);
641
642                                 Mat3CpyMat3(tob->smtx, smtx);
643                                 Mat3CpyMat3(tob->mtx, mtx);
644                         
645                                 tob->dist = -1;
646
647                                 td = Trans.data;
648                                 for (i = 0; i < totsel; i++, td++) {
649                                         VecSubf(vec, tob->center, td->center);
650                                         Mat3MulVecfl(mtx, vec);
651                                         dist = Normalise(vec);
652                                         if (tob->dist == -1) {
653                                                 tob->dist = dist;
654                                         }
655                                         else if (dist < tob->dist) {
656                                                 tob->dist = dist;
657                                         }
658                                 }
659
660                                 tob++;
661                         }       
662                 }       
663         }
664 }
665
666 /* **************** IpoKey stuff, for Object TransData ********** */
667
668 /* storage of bezier triple. thats why -3 and +3! */
669 static void set_tdi_old(float *old, float *poin)
670 {
671         old[0]= *(poin);
672         old[3]= *(poin-3);
673         old[6]= *(poin+3);
674 }
675
676 /* while transforming */
677 static void add_tdi_poin(float *poin, float *old, float delta)
678 {
679         if(poin) {
680                 poin[0]= old[0]+delta;
681                 poin[-3]= old[3]+delta;
682                 poin[3]= old[6]+delta;
683         }
684 }
685
686 /* fill ipokey transdata with old vals and pointers */
687 static void ipokey_to_transdata(IpoKey *ik, TransData *td)
688 {
689         extern int ob_ar[];             // blenkernel ipo.c
690         TransDataIpokey *tdi= td->tdi;
691         BezTriple *bezt;
692         int a, delta= 0;
693         
694         for(a=0; a<OB_TOTIPO; a++) {
695                 if(ik->data[a]) {
696                         bezt= ik->data[a];
697                         
698                         switch( ob_ar[a] ) {
699                                 case OB_LOC_X:
700                                 case OB_DLOC_X:
701                                         tdi->locx= &(bezt->vec[1][1]); break;
702                                 case OB_LOC_Y:
703                                 case OB_DLOC_Y:
704                                         tdi->locy= &(bezt->vec[1][1]); break;
705                                 case OB_LOC_Z:
706                                 case OB_DLOC_Z:
707                                         tdi->locz= &(bezt->vec[1][1]); break;
708                                         
709                                 case OB_DROT_X:
710                                         delta= 1;
711                                 case OB_ROT_X:
712                                         tdi->rotx= &(bezt->vec[1][1]); break;
713                                 case OB_DROT_Y:
714                                         delta= 1;
715                                 case OB_ROT_Y:
716                                         tdi->roty= &(bezt->vec[1][1]); break;
717                                 case OB_DROT_Z:
718                                         delta= 1;
719                                 case OB_ROT_Z:
720                                         tdi->rotz= &(bezt->vec[1][1]); break;
721                                         
722                                 case OB_SIZE_X:
723                                 case OB_DSIZE_X:
724                                         tdi->sizex= &(bezt->vec[1][1]); break;
725                                 case OB_SIZE_Y:
726                                 case OB_DSIZE_Y:
727                                         tdi->sizey= &(bezt->vec[1][1]); break;
728                                 case OB_SIZE_Z:
729                                 case OB_DSIZE_Z:
730                                         tdi->sizez= &(bezt->vec[1][1]); break;          
731                         }       
732                 }
733         }
734         
735         /* oldvals for e.g. undo */
736         if(tdi->locx) set_tdi_old(tdi->oldloc, tdi->locx);
737         if(tdi->locy) set_tdi_old(tdi->oldloc+1, tdi->locy);
738         if(tdi->locz) set_tdi_old(tdi->oldloc+2, tdi->locz);
739         
740         /* remember, for mapping curves ('1'=10 degrees)  */
741         if(tdi->rotx) set_tdi_old(tdi->oldrot, tdi->rotx);
742         if(tdi->roty) set_tdi_old(tdi->oldrot+1, tdi->roty);
743         if(tdi->rotz) set_tdi_old(tdi->oldrot+2, tdi->rotz);
744         
745         /* this is not allowed to be dsize! */
746         if(tdi->sizex) set_tdi_old(tdi->oldsize, tdi->sizex);
747         if(tdi->sizey) set_tdi_old(tdi->oldsize+1, tdi->sizey);
748         if(tdi->sizez) set_tdi_old(tdi->oldsize+2, tdi->sizez);
749         
750         tdi->flag= TOB_IPO;
751         if(delta) tdi->flag |= TOB_IPODROT;
752 }
753
754
755 /* *************************** Object Transform data ******************* */
756
757 static void ObjectToTransData(TransData *td, Object *ob) 
758 {
759         float obmtx[3][3];
760         Object *tr;
761         void *cfirst, *clast;
762
763         cfirst = ob->constraints.first;
764         clast = ob->constraints.last;
765         ob->constraints.first=ob->constraints.last=NULL;
766
767         tr= ob->track;
768         ob->track= NULL;
769
770         where_is_object(ob);
771
772         ob->track= tr;
773
774         ob->constraints.first = cfirst;
775         ob->constraints.last = clast;
776
777         td->ob = ob;
778
779         td->loc = ob->loc;
780         VECCOPY(td->iloc, td->loc);
781         
782         td->ext->rot = ob->rot;
783         VECCOPY(td->ext->irot, ob->rot);
784         VECCOPY(td->ext->drot, ob->drot);
785         
786         td->ext->size = ob->size;
787         VECCOPY(td->ext->isize, ob->size);
788         VECCOPY(td->ext->dsize, ob->dsize);
789
790         VECCOPY(td->center, ob->obmat[3]);
791
792         Mat3CpyMat4(td->mtx, ob->obmat);
793
794         object_to_mat3(ob, obmtx);
795
796         /*
797         Mat3CpyMat4(totmat, ob->obmat);
798         Mat3Inv(obinv, totmat);
799         Mat3MulMat3(td->smtx, obmtx, obinv);
800         */
801         if (ob->parent)
802         {
803                 Mat3CpyMat4(td->mtx, ob->parent->obmat);
804                 Mat3Inv(td->smtx, td->mtx);
805         }
806         else
807         {
808                 Mat3One(td->smtx);
809                 Mat3One(td->mtx);
810         }
811 }
812
813 /* only used in function below, stuff to be removed */
814 static Object *is_a_parent_selected_int(Object *startob, Object *ob, GHash *done_hash) 
815 {
816         if (ob!=startob && TESTBASE(ob))
817                 return ob;
818         
819         if (BLI_ghash_haskey(done_hash, ob))
820                 return NULL;
821         else
822                 BLI_ghash_insert(done_hash, ob, NULL);
823         
824         if (ob->parent) {
825                 Object *par= is_a_parent_selected_int(startob, ob->parent, done_hash);
826                 if (par)
827                         return par;
828         }
829         return NULL;
830 }
831
832 /* only used in function below, stuff to be removed */
833 static Object *is_a_parent_selected(Object *ob) 
834 {
835         GHash *gh= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
836         Object *res= is_a_parent_selected_int(ob, ob, gh);
837         BLI_ghash_free(gh, NULL, NULL);
838         
839         return res;
840 }
841
842
843
844 /* sets flags in Bases to define whether they take part in transform */
845 /* it deselects Bases, so we have to call the clear function always after */
846 static void set_trans_object_base_flags(TransInfo *t)
847 {
848         /*
849          if Base selected and has parent selected:
850          base->flag= BA_WASSEL+BA_PARSEL
851          if base not selected and parent selected:
852          base->flag= BA_PARSEL
853          */
854         GHash *object_to_base_hash= NULL; 
855         Base *base;
856         
857         /* moved to start of function, it is needed for hooks now too */
858         if (!object_to_base_hash) {
859                 Base *b;
860                 object_to_base_hash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
861                 
862                 for (b= FIRSTBASE; b; b= b->next)
863                         BLI_ghash_insert(object_to_base_hash, b->object, b);
864         }
865         
866         /* makes sure base flags and object flags are identical */
867         copy_baseflags();
868         
869         for (base= FIRSTBASE; base; base= base->next) {
870                 base->flag &= ~(BA_PARSEL+BA_WASSEL);
871                 
872                 if( (base->lay & G.vd->lay) && base->object->id.lib==0) {
873                         Object *ob= base->object;
874                         Object *parsel= is_a_parent_selected(ob);
875                         
876                         /* parentkey here? */
877                         
878                         if(parsel) {
879                                 if(base->flag & SELECT) {
880                                         base->flag &= ~SELECT;
881                                         base->flag |= (BA_PARSEL+BA_WASSEL);
882                                 }
883                                 else base->flag |= BA_PARSEL;
884                         }
885                         
886                         if(t->mode==TFM_TRANSLATION)  {
887                                 if(ob->track && TESTBASE(ob->track) && (base->flag & SELECT)==0)  
888                                         base->flag |= BA_PARSEL;
889                         }
890                         
891                         /* updates? */
892                         if(ob->hooks.first) {
893                                 Base *b;
894                                 ObHook *hook= ob->hooks.first;
895                                 
896                                 while(hook) {
897                                         if(hook->parent) {
898                                                 Object *parsel= is_a_parent_selected(hook->parent);
899                                                 
900                                                 b= BLI_ghash_lookup(object_to_base_hash, hook->parent);
901                                                 if(parsel || ((base->flag | b->flag) & (SELECT | BA_PARSEL)) ) {
902                                                         base->flag |= BA_DISP_UPDATE;
903                                                 }
904                                         }
905                                         hook= hook->next;
906                                 }
907                         }
908                         
909                         if(ob->parent && ob->parent->type==OB_LATTICE)
910                                 if(ob->parent->hooks.first) base->flag |= BA_DISP_UPDATE;
911                         
912                         if(base->flag & (SELECT | BA_PARSEL)) {
913                                 
914                                 base->flag |= BA_WHERE_UPDATE;
915                                 
916                                 if(ob->parent) {
917                                         if(ob->parent->type==OB_LATTICE) base->flag |= BA_DISP_UPDATE;
918                                         else if(ob->partype==PARSKEL) {
919                                                 if ELEM3(ob->parent->type, OB_IKA, OB_CURVE, OB_ARMATURE) 
920                                                         base->flag |= BA_DISP_UPDATE;
921                                         }
922                                 }
923                                 if(ob->track) {
924                                         ;
925                                 }
926                                 
927                                 if( give_parteff(ob) ) base->flag |= BA_DISP_UPDATE;
928                                 
929                                 if(ob->type==OB_MBALL) {
930                                         Base *b;
931                                         
932                                         b= BLI_ghash_lookup(object_to_base_hash, find_basis_mball(ob));
933                                         b->flag |= BA_DISP_UPDATE;
934                                 }
935                         }
936                 }
937         }
938         
939         if (object_to_base_hash)
940                 BLI_ghash_free(object_to_base_hash, NULL, NULL);
941         
942 }
943
944 static void clear_trans_object_base_flags(void)
945 {
946         Base *base;
947         
948         base= FIRSTBASE;
949         while(base) {
950                 if(base->flag & BA_WASSEL) base->flag |= SELECT;
951                 base->flag &= ~(BA_PARSEL+BA_WASSEL);
952                 
953                 base->flag &= ~(BA_DISP_UPDATE+BA_WHERE_UPDATE+BA_DO_IPO);
954                 
955                 /* pose here? */
956                 if (base->object->pose) {
957                         Object *ob= base->object;
958                         bPoseChannel *chan;
959                         for (chan = ob->pose->chanbase.first; chan; chan=chan->next) {
960                                 chan->flag &= ~PCHAN_TRANS_UPDATE;
961                         }
962                 }
963                 
964                 base= base->next;
965         }
966         copy_baseflags();
967 }
968
969
970 static void createTransObject(void)
971 {
972         TransData *td = NULL;
973         TransDataExtension *tx;
974         Object *ob;
975         Base *base;
976         IpoKey *ik;
977         ListBase elems;
978         
979         /* hackish... but we have to do it somewhere */
980         reset_slowparents();
981         
982         set_trans_object_base_flags(&Trans);
983         
984         /* count */     
985         for(base= FIRSTBASE; base; base= base->next) {
986                 if TESTBASELIB(base) {
987                         ob= base->object;
988                         
989                         /* store ipo keys? */
990                         if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) {
991                                 elems.first= elems.last= NULL;
992                                 make_ipokey_transform(ob, &elems, 1); /* '1' only selected keys */
993                                 
994                                 pushdata(&elems, sizeof(ListBase));
995                                 
996                                 for(ik= elems.first; ik; ik= ik->next) Trans.total++;
997
998                                 if(elems.first==NULL) Trans.total++;
999                         }
1000                         else {
1001                                 Trans.total++;
1002                         }
1003                 }
1004         }
1005
1006         if(!Trans.total) {
1007                 /* clear here, main transform function escapes too */
1008                 clear_trans_object_base_flags();
1009                 return;
1010         }
1011         
1012         td = Trans.data = MEM_mallocN(Trans.total*sizeof(TransData), "TransOb");
1013         tx = MEM_mallocN(Trans.total*sizeof(TransDataExtension), "TransObExtension");
1014
1015         for(base= FIRSTBASE; base; base= base->next) {
1016                 if TESTBASELIB(base) {
1017                         ob= base->object;
1018                         
1019                         td->flag= TD_SELECTED|TD_OBJECT;
1020                         td->ext = tx;
1021                         td->dist = 0.0f;
1022
1023                         /* store ipo keys? */
1024                         if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) {
1025                                 
1026                                 popfirst(&elems);       // bring back pushed listbase
1027                                 
1028                                 if(elems.first) {
1029                                         float cfraont;
1030                                         int ipoflag;
1031                                         
1032                                         base->flag |= BA_DO_IPO+BA_WASSEL;
1033                                         base->flag &= ~SELECT;
1034                                         
1035                                         cfraont= CFRA;
1036                                         set_no_parent_ipo(1);
1037                                         ipoflag= ob->ipoflag;
1038                                         ob->ipoflag &= ~OB_OFFS_OB;
1039                                         
1040                                         pushdata(ob->loc, 7*3*4); // tsk! tsk!
1041                                         
1042                                         for(ik= elems.first; ik; ik= ik->next) {
1043                                                 
1044                                                 /* weak... this doesn't correct for floating values, giving small errors */
1045                                                 CFRA= ik->val/G.scene->r.framelen;
1046                                                 
1047                                                 do_ob_ipo(ob);
1048                                                 ObjectToTransData(td, ob);      // does where_is_object()
1049                                                 
1050                                                 td->tdi= MEM_callocN(sizeof(TransDataIpokey), "TransDataIpokey");
1051                                                 /* also does tdi->flag and oldvals, needs to be after ob_to_transob()! */
1052                                                 ipokey_to_transdata(ik, td);
1053                                                 
1054                                                 td++;
1055                                                 tx++;
1056                                                 if(ik->next) td->ext= tx;       // prevent corrupting mem!
1057                                         }
1058                                         free_ipokey(&elems);
1059                                         
1060                                         poplast(ob->loc);
1061                                         set_no_parent_ipo(0);
1062                                         
1063                                         CFRA= cfraont;
1064                                         ob->ipoflag= ipoflag;
1065                                 }
1066                                 else {
1067                                         ObjectToTransData(td, ob);
1068                                         td->tdi= NULL;
1069                                 }
1070                         }
1071                         else {
1072                                 ObjectToTransData(td, ob);
1073                                 td->tdi= NULL;
1074                         }
1075                         td++;
1076                         tx++;
1077                 }
1078         }
1079 }
1080
1081 static void createTransData(void) 
1082 {
1083         if (G.obpose) {
1084                 createTransPose();
1085         }
1086         else if (G.obedit) {
1087                 if (G.obedit->type == OB_MESH) {
1088                         createTransEditVerts(); 
1089                 }
1090                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1091                         createTransCurveVerts();
1092                 }
1093                 else if (G.obedit->type==OB_LATTICE) {
1094                         createTransLatticeVerts();
1095                 }
1096                 else if (G.obedit->type==OB_MBALL) {
1097                         createTransMBallVerts();
1098                 }
1099                 else if (G.obedit->type==OB_ARMATURE) {
1100                         createTransArmatureVerts();
1101                 }                                                       
1102                 else {
1103                         printf("not done yet! only have mesh surface curve\n");
1104                 }
1105         }
1106         else {
1107                 createTransObject();
1108         }
1109 }
1110
1111 #define TRANS_CANCEL    2
1112 #define TRANS_CONFIRM   1
1113
1114 /* ************************** TRANSFORMATIONS **************************** */
1115
1116 void Transform(int mode) 
1117 {
1118         int ret_val = 0;
1119         short pmval[2] = {0, 0}, mval[2], val;
1120         float mati[3][3];
1121         unsigned short event;
1122
1123         /*joeedh -> hopefully may be what makes the old transform() constant*/
1124         /* ton: I doubt, but it doesnt harm for now. shouldnt be needed though */
1125         areawinset(curarea->win);
1126
1127         Mat3One(mati);
1128
1129         /* stupid PET initialisation code */
1130         /* START */
1131         if (Trans.propsize == 0.0f) {
1132                 Trans.propsize = 1.0;
1133         }
1134         /* END */
1135
1136         if (mode == TFM_REPEAT) {
1137                 mode = LastMode;
1138         }
1139         else {
1140                 LastMode = mode;
1141         }
1142         
1143         initTransModeFlags(&Trans, mode);       // modal settings in struct Trans
1144
1145         initTrans(&Trans);                                      // data, mouse, vectors
1146
1147         createTransData();                                      // make TransData structs from selection
1148
1149         if (Trans.total == 0)
1150                 return;
1151
1152         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1153         mode= Trans.mode;
1154         
1155         calculatePropRatio(&Trans);
1156         calculateCenter(&Trans);
1157
1158         switch (mode) {
1159         case TFM_TRANSLATION:
1160                 initTranslation(&Trans);
1161                 break;
1162         case TFM_ROTATION:
1163                 initRotation(&Trans);
1164                 break;
1165         case TFM_RESIZE:
1166                 initResize(&Trans);
1167                 break;
1168         case TFM_TOSPHERE:
1169                 initToSphere(&Trans);
1170                 break;
1171         case TFM_SHEAR:
1172                 initShear(&Trans);
1173                 break;
1174         }
1175
1176         // Emptying event queue
1177         while( qtest() ) {
1178                 event= extern_qread(&val);
1179         }
1180
1181         Trans.redraw = 1;
1182
1183         while (ret_val == 0) {
1184                 
1185                 getmouseco_areawin(mval);
1186                 
1187                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1188                         Trans.redraw = 1;
1189                 }
1190                 if (Trans.redraw) {
1191                         pmval[0] = mval[0];
1192                         pmval[1] = mval[1];
1193
1194                         if (Trans.transform) {
1195                                 Trans.transform(&Trans, mval);
1196                         }
1197                         Trans.redraw = 0;
1198                 }
1199                 
1200                 /* essential for idling subloop */
1201                 if( qtest()==0) PIL_sleep_ms(2);
1202
1203                 while( qtest() ) {
1204                         event= extern_qread(&val);
1205
1206                         if(val) {
1207                                 switch (event){
1208                                 case MIDDLEMOUSE:
1209                                         selectConstraint(&Trans);
1210                                         Trans.redraw = 1;
1211                                         break;
1212                                 case ESCKEY:
1213                                 case RIGHTMOUSE:
1214                                         ret_val = TRANS_CANCEL;
1215                                         break;
1216                                 case LEFTMOUSE:
1217                                 case SPACEKEY:
1218                                 case PADENTER:
1219                                 case RETKEY:
1220                                         ret_val = TRANS_CONFIRM;
1221                                         break;
1222                                 case GKEY:
1223                                 case SKEY:
1224                                 case RKEY:
1225                                         if (G.qual == LR_CTRLKEY)
1226                                                 applyTransObjects(&Trans);
1227                                         else
1228                                                 restoreTransObjects(&Trans);
1229                                         break;
1230                                 case XKEY:
1231                                         if (G.qual == 0)
1232                                                 setConstraint(&Trans, mati, (APPLYCON|CONAXIS0));
1233                                         else if (G.qual == LR_CTRLKEY)
1234                                                 setConstraint(&Trans, mati, (APPLYCON|CONAXIS1|CONAXIS2));
1235                                         break;
1236                                 case YKEY:
1237                                         if (G.qual == 0)
1238                                                 setConstraint(&Trans, mati, (APPLYCON|CONAXIS1));
1239                                         else if (G.qual == LR_CTRLKEY)
1240                                                 setConstraint(&Trans, mati, (APPLYCON|CONAXIS0|CONAXIS2));
1241                                         break;
1242                                 case ZKEY:
1243                                         if (G.qual == 0)
1244                                                 setConstraint(&Trans, mati, (APPLYCON|CONAXIS2));
1245                                         else if (G.qual == LR_CTRLKEY)
1246                                                 setConstraint(&Trans, mati, (APPLYCON|CONAXIS0|CONAXIS1));
1247                                         break;
1248                                 case OKEY:
1249                                         if (G.qual==LR_SHIFTKEY) {
1250                                                 extern int prop_mode;
1251                                                 prop_mode = (prop_mode+1)%5;
1252                                                 calculatePropRatio(&Trans);
1253                                                 Trans.redraw= 1;
1254                                         }
1255                                         break;
1256                                 case WHEELDOWNMOUSE:
1257                                 case PADPLUSKEY:
1258                                         if(G.f & G_PROPORTIONAL) {
1259                                                 Trans.propsize*= 1.1f;
1260                                                 calculatePropRatio(&Trans);
1261                                                 Trans.redraw= 1;
1262                                         }
1263                                         break;
1264                                 case WHEELUPMOUSE:
1265                                 case PADMINUS:
1266                                         if(G.f & G_PROPORTIONAL) {
1267                                                 Trans.propsize*= 0.90909090f;
1268                                                 calculatePropRatio(&Trans);
1269                                                 Trans.redraw= 1;
1270                                         }
1271                                         break;
1272                                 }
1273                                 Trans.redraw |= handleNumInput(&(Trans.num), event);
1274                                 arrows_move_cursor(event);
1275                         }
1276                         else {
1277                                 switch (event){
1278                                 case MIDDLEMOUSE:
1279                                         chooseConstraint(&Trans);
1280                                         Trans.redraw = 1;
1281                                         break;
1282                                 case LEFTMOUSE:
1283                                 case RIGHTMOUSE:
1284                                         ret_val = TRANS_CONFIRM;
1285                                         break;
1286                                 }
1287                         }
1288                 }
1289         }
1290
1291         if(ret_val == TRANS_CANCEL) {
1292                 restoreTransObjects(&Trans);
1293         }
1294         else {
1295                 BIF_undo_push("Transform");
1296         }
1297         
1298         /* free data, reset vars */
1299         postTrans(&Trans);
1300         
1301         /* mess from old transform, just for now (ton) */
1302         {
1303                 char cmode='g';
1304                 
1305                 if(mode==TFM_RESIZE) cmode= 's';
1306                 else if(mode==TFM_ROTATION) cmode= 'r';
1307                 /* aftertrans does displists, ipos and action channels */
1308                 special_aftertrans_update(cmode, 0, ret_val == TRANS_CANCEL, 0 /*keyflags*/);
1309                 
1310                 if(G.obedit==NULL && G.obpose==NULL)
1311                         clear_trans_object_base_flags();
1312         }
1313         
1314         
1315         /* send events out for redraws */
1316         allqueue(REDRAWVIEW3D, 0);
1317         allqueue(REDRAWBUTSOBJECT, 0);
1318         scrarea_queue_headredraw(curarea);
1319 }
1320
1321 /* ************************** WRAP *************************** */
1322
1323 void initWrap(TransInfo *t) 
1324 {
1325         float min[3], max[3], loc[3];
1326         int i;
1327         calculateCenterCursor(t);
1328         t->num.idx_max = 0;
1329         t->transform = Wrap;
1330
1331         for(i = 0; i < t->total; i++) {
1332                 VECCOPY(loc, t->data[i].iloc);
1333                 if (G.obedit) {
1334                         Mat4MulVecfl(G.obedit->obmat, loc);
1335                 }
1336                 Mat4MulVecfl(G.vd->viewmat, loc);
1337                 if (i) {
1338                         MinMax3(min, max, loc);
1339                 }
1340                 else {
1341                         VECCOPY(max, loc);
1342                         VECCOPY(min, loc);
1343                 }
1344         }
1345
1346
1347         t->fac = (float)(t->center2d[0] - t->imval[0]);
1348 }
1349
1350
1351 int Wrap(TransInfo *t, short mval[2])
1352 {
1353         return 1;
1354 }
1355
1356 /* ************************** SHEAR *************************** */
1357
1358 void initShear(TransInfo *t) 
1359 {
1360         t->num.idx_max = 0;
1361         t->transform = Shear;
1362         t->fac = (float)(t->center2d[0] - t->imval[0]);
1363 }
1364
1365 int Shear(TransInfo *t, short mval[2]) 
1366 {
1367         float vec[3];
1368         float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
1369         float value;
1370         int i;
1371         char str[50];
1372         TransData *td = t->data;
1373
1374         Mat3CpyMat4(persmat, G.vd->viewmat);
1375         Mat3Inv(persinv, persmat);
1376
1377         value = -0.005f * ((float)(t->center2d[0] - mval[0]) - t->fac);
1378
1379         apply_grid1(&value, t->num.idx_max, 0.1f);
1380
1381         applyNumInput(&t->num, &value);
1382
1383         /* header print for NumInput */
1384         if (hasNumInput(&t->num)) {
1385                 char c[20];
1386
1387                 outputNumInput(&(t->num), c);
1388
1389                 sprintf(str, "Shear: %s %s", c, t->proptext);
1390         }
1391         else {
1392                 /* default header print */
1393                 sprintf(str, "Shear: %.3f %s", value, t->proptext);
1394         }
1395         
1396         Mat3One(smat);
1397         smat[1][0] = value;
1398         Mat3MulMat3(tmat, smat, persmat);
1399         Mat3MulMat3(totmat, persinv, tmat);
1400         
1401         for(i = 0 ; i < t->total; i++, td++) {
1402                 if (td->flag & TD_NOACTION)
1403                         continue;
1404                 if (G.obedit) {
1405                         float mat3[3][3];
1406                         Mat3MulMat3(mat3, totmat, td->mtx);
1407                         Mat3MulMat3(tmat, td->smtx, mat3);
1408                 }
1409                 else {
1410                         Mat3CpyMat3(tmat, totmat);
1411                 }
1412                 VecSubf(vec, td->center, t->center);
1413
1414                 Mat3MulVecfl(tmat, vec);
1415
1416                 VecAddf(vec, vec, t->center);
1417                 VecSubf(vec, vec, td->center);
1418
1419                 VecMulf(vec, td->factor);
1420
1421                 VecAddf(td->loc, td->iloc, vec);
1422         }
1423
1424         recalcData(t);
1425
1426         headerprint(str);
1427
1428         force_draw(0);
1429
1430         helpline (t->center);
1431
1432         return 1;
1433 }
1434
1435 /* ************************** RESIZE *************************** */
1436
1437 void initResize(TransInfo *t) 
1438 {
1439         Trans.fac = (float)sqrt( (float)
1440                 (
1441                         (Trans.center2d[1] - Trans.imval[1])*(Trans.center2d[1] - Trans.imval[1])
1442                 +
1443                         (Trans.center2d[0] - Trans.imval[0])*(Trans.center2d[0] - Trans.imval[0])
1444                 ) );
1445
1446         t->num.idx_max = 2;
1447         t->transform = Resize;
1448 }
1449
1450 int Resize(TransInfo *t, short mval[2]) 
1451 {
1452         TransData *td = t->data;
1453         float vec[3];
1454         float size[3], tsize[3], mat[3][3], tmat[3][3];
1455         float ratio;
1456         int i;
1457         char str[50];
1458
1459         ratio = (float)sqrt( (float)
1460                 (
1461                         (t->center2d[1] - mval[1])*(t->center2d[1] - mval[1])
1462                 +
1463                         (t->center2d[0] - mval[0])*(t->center2d[0] - mval[0])
1464                 ) ) / t->fac;
1465
1466         size[0] = size[1] = size[2] = ratio;
1467
1468         apply_grid1(size, t->num.idx_max, 0.1f);
1469
1470         if (t->con.applyVec) {
1471                 t->con.applyVec(t, NULL, size, tsize);
1472                 VECCOPY(size, tsize);
1473         }
1474
1475         applyNumInput(&t->num, size);
1476
1477         /* header print for NumInput */
1478         if (hasNumInput(&t->num)) {
1479                 char c[60];
1480
1481                 outputNumInput(&(t->num), c);
1482
1483                 sprintf(str, "Size X: %s Y: %s Z: %s %s", &c[0], &c[20], &c[40], t->proptext);
1484         }
1485         else {
1486                 /* default header print */
1487                 sprintf(str, "Size X: %.3f Y: %.3f Z: %.3f %s", size[0], size[1], size[2], t->proptext);
1488         }
1489         
1490         SizeToMat3(size, mat);
1491         for(i = 0 ; i < t->total; i++, td++) {
1492                 float smat[3][3];
1493                 if (td->flag & TD_NOACTION)
1494                         continue;
1495
1496                 if (!(td->flag & TD_OBJECT)) {
1497                         Mat3MulMat3(smat, mat, td->smtx);
1498                         Mat3MulMat3(tmat, td->mtx, smat);
1499                 }
1500                 else {
1501                         Mat3CpyMat3(tmat, mat);
1502                 }
1503
1504                 if (td->ext) {
1505                         float fsize[3];
1506
1507                         if (td->flag & TD_OBJECT) {
1508                                 float obsizemat[3][3];
1509                                 Mat3MulMat3(obsizemat, td->smtx, tmat);
1510                                 Mat3ToSize(obsizemat, fsize);
1511                         }
1512                         else {
1513                                 Mat3ToSize(tmat, fsize);
1514                         }
1515                         
1516                         /* handle ipokeys? */
1517                         if(td->tdi) {
1518                                 TransDataIpokey *tdi= td->tdi;
1519                                 /* calculate delta size (equal for size and dsize) */
1520                                 
1521                                 // commented out for now
1522                                 vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
1523                                 vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
1524                                 vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
1525                                 
1526                                 add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
1527                                 add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
1528                                 add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
1529                                 
1530                         }
1531                         else {
1532                                 // TEMPORARY NAIVE CODE
1533                                 td->ext->size[0] = td->ext->isize[0] + td->ext->isize[0] * (fsize[0] - 1.0f) * td->factor;
1534                                 td->ext->size[1] = td->ext->isize[1] + td->ext->isize[1] * (fsize[1] - 1.0f) * td->factor;
1535                                 td->ext->size[2] = td->ext->isize[2] + td->ext->isize[2] * (fsize[2] - 1.0f) * td->factor;
1536                         }
1537                 }
1538                 VecSubf(vec, td->center, t->center);
1539
1540                 Mat3MulVecfl(tmat, vec);
1541
1542                 VecAddf(vec, vec, t->center);
1543                 VecSubf(vec, vec, td->center);
1544
1545                 VecMulf(vec, td->factor);
1546
1547                 if (td->flag & TD_OBJECT) {
1548                         Mat3MulVecfl(td->smtx, vec);
1549                 }
1550
1551                 VecAddf(td->loc, td->iloc, vec);
1552         }
1553
1554         recalcData(t);
1555
1556         headerprint(str);
1557
1558         force_draw(0);
1559
1560         helpline (t->center);
1561
1562         return 1;
1563 }
1564
1565 /* ************************** TOSPHERE *************************** */
1566
1567 void initToSphere(TransInfo *t) 
1568 {
1569         TransData *td = t->data;
1570         int i;
1571
1572         // Calculate average radius
1573         for(i = 0 ; i < t->total; i++, td++) {
1574                 t->val += VecLenf(t->center, td->iloc);
1575         }
1576
1577         t->val /= (float)t->total;
1578
1579         Trans.fac = (float)sqrt( (float)
1580                 (
1581                         (Trans.center2d[1] - Trans.imval[1])*(Trans.center2d[1] - Trans.imval[1])
1582                 +
1583                         (Trans.center2d[0] - Trans.imval[0])*(Trans.center2d[0] - Trans.imval[0])
1584                 ) );
1585
1586         t->num.idx_max = 0;
1587         t->transform = ToSphere;
1588 }
1589
1590
1591
1592 int ToSphere(TransInfo *t, short mval[2]) 
1593 {
1594         float vec[3];
1595         float ratio, radius;
1596         int i;
1597         char str[50];
1598         TransData *td = t->data;
1599
1600         ratio = (float)sqrt( (float)
1601                 (
1602                         (t->center2d[1] - mval[1])*(t->center2d[1] - mval[1])
1603                 +
1604                         (t->center2d[0] - mval[0])*(t->center2d[0] - mval[0])
1605                 ) ) / t->fac;
1606
1607         apply_grid1(&ratio, t->num.idx_max, 0.1f);
1608
1609         applyNumInput(&t->num, &ratio);
1610
1611         if (ratio > 1.0f)
1612                 ratio = 1.0f;
1613
1614         /* header print for NumInput */
1615         if (hasNumInput(&t->num)) {
1616                 char c[20];
1617
1618                 outputNumInput(&(t->num), c);
1619
1620                 sprintf(str, "To Sphere: %s %s", c, t->proptext);
1621         }
1622         else {
1623                 /* default header print */
1624                 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
1625         }
1626         
1627         
1628         for(i = 0 ; i < t->total; i++, td++) {
1629                 float tratio;
1630                 if (td->flag & TD_NOACTION)
1631                         continue;
1632                 VecSubf(vec, td->iloc, t->center);
1633
1634                 radius = Normalise(vec);
1635
1636                 tratio = 1.0f - ((1.0f - ratio) * td->factor);
1637
1638                 VecMulf(vec, radius * tratio + t->val * (1.0f - tratio));
1639
1640                 VecAddf(td->loc, t->center, vec);
1641         }
1642
1643         recalcData(t);
1644
1645         headerprint(str);
1646
1647         force_draw(0);
1648
1649         helpline (t->center);
1650
1651         return 1;
1652 }
1653
1654 /* ************************** ROTATION *************************** */
1655
1656 void initRotation(TransInfo *t) 
1657 {
1658         t->num.idx_max = 0;
1659         t->fac = 0;
1660         t->transform = Rotation;
1661 }
1662
1663 int Rotation(TransInfo *t, short mval[2]) 
1664 {
1665         TransData *td = t->data;
1666         int i;
1667         char str[50];
1668
1669         float final;
1670
1671         int dx2 = t->center2d[0] - mval[0];
1672         int dy2 = t->center2d[1] - mval[1];
1673         float B = (float)sqrt(dx2*dx2+dy2*dy2);
1674
1675         int dx1 = t->center2d[0] - t->imval[0];
1676         int dy1 = t->center2d[1] - t->imval[1];
1677         float A = (float)sqrt(dx1*dx1+dy1*dy1);
1678
1679         int dx3 = mval[0] - t->imval[0];
1680         int dy3 = mval[1] - t->imval[1];
1681
1682         float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
1683                 / (2 * A * B);
1684
1685         float dphi;
1686
1687         float vec[3], axis[3];
1688         float mat[3][3], totmat[3][3], omat[3][3], smat[3][3];
1689
1690         if (G.obedit) {
1691                 Mat3CpyMat4(omat, G.obedit->obmat);
1692         }
1693
1694         VECCOPY(axis, G.vd->persinv[2]);
1695         Normalise(axis);
1696
1697         dphi = saacos(deler);
1698         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
1699
1700         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
1701         else t->fac += dphi;
1702
1703         final = t->fac;
1704
1705         apply_grid2(&final, t->num.idx_max, (float)((5.0/180)*M_PI), 0.2f);
1706
1707         t->imval[0] = mval[0];
1708         t->imval[1] = mval[1];
1709
1710         if (t->con.applyRot) {
1711                 t->con.applyRot(t, NULL, axis);
1712         }
1713
1714         if (hasNumInput(&t->num)) {
1715                 char c[20];
1716
1717                 applyNumInput(&t->num, &final);
1718
1719                 outputNumInput(&(t->num), c);
1720
1721                 sprintf(str, "Rot: %s %s", &c[0], t->proptext);
1722
1723                 final *= (float)(M_PI / 180.0);
1724         }
1725         else {
1726                 sprintf(str, "Rot: %.2f %s", 180.0*final/M_PI, t->proptext);
1727         }
1728
1729         //printf("Axis %f %f %f\n", axis[0], axis[1], axis[2]);
1730         VecRotToMat3(axis, final * td->factor, mat);
1731
1732         for(i = 0 ; i < t->total; i++, td++) {
1733                 if (td->flag & TD_NOACTION)
1734                         continue;
1735
1736                 if (t->con.applyRot) {
1737                         t->con.applyRot(t, td, axis);
1738                         VecRotToMat3(axis, final * td->factor, mat);
1739                 }
1740                 else if (G.f & G_PROPORTIONAL) {
1741                         VecRotToMat3(axis, final * td->factor, mat);
1742                 }
1743
1744                 if (G.obedit) {
1745                         Mat3MulMat3(totmat, mat, omat);
1746                         Mat3MulMat3(smat, td->smtx, totmat);
1747
1748                         VecSubf(vec, td->iloc, t->center);
1749                         Mat3MulVecfl(smat, vec);
1750
1751                         VecAddf(td->loc, vec, t->center);
1752                 }
1753                 else {
1754                         float eul[3], fmat[3][3];
1755
1756                         /* translation */
1757                         VecSubf(vec, td->center, t->center);
1758                         Mat3MulVecfl(mat, vec);
1759                         VecAddf(vec, vec, t->center);
1760                         /* vec now is the location where the object has to be */
1761                         VecSubf(vec, vec, td->center);
1762                         Mat3MulVecfl(td->smtx, vec);
1763
1764                         VecAddf(td->loc, td->iloc, vec);
1765                         
1766                         if(td->flag & TD_USEQUAT) {
1767                                 float quat[4];
1768                                 
1769                                 Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
1770                                 
1771                                 Mat3ToQuat(fmat, quat); // Actual transform
1772                                 
1773                                 QuatMul(td->ext->quat, quat, td->ext->iquat);
1774                         }
1775                         else {
1776                                 float obmat[3][3];
1777                                 
1778                                 /* are there ipo keys? */
1779                                 if(td->tdi) {
1780                                         TransDataIpokey *tdi= td->tdi;
1781                                         float rot[3];
1782                                         
1783                                         /* calculate the total rotatation in eulers */
1784                                         VecAddf(eul, td->ext->irot, td->ext->drot);
1785                                         EulToMat3(eul, obmat);
1786                                         /* mat = transform, obmat = object rotation */
1787                                         Mat3MulMat3(fmat, mat, obmat);
1788                                         Mat3ToEul(fmat, eul);
1789                                         compatible_eul(eul, td->ext->irot);
1790                                         
1791                                         /* correct back for delta rot */
1792                                         if(tdi->flag & TOB_IPODROT) {
1793                                                 VecSubf(rot, eul, td->ext->irot);
1794                                         }
1795                                         else {
1796                                                 VecSubf(rot, eul, td->ext->drot);
1797                                         }
1798                                         
1799                                         VecMulf(rot, 9.0/M_PI_2);
1800                                         VecSubf(rot, rot, tdi->oldrot);
1801                                         
1802                                         add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
1803                                         add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
1804                                         add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
1805                                 }
1806                                 else {
1807                                         
1808                                         /* calculate the total rotatation in eulers */
1809                                         VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
1810                                         EulToMat3(eul, obmat);
1811                                         /* mat = transform, obmat = object rotation */
1812                                         Mat3MulMat3(fmat, mat, obmat);
1813                                         Mat3ToEul(fmat, eul);
1814                                         compatible_eul(eul, td->ext->irot);
1815                                         
1816                                         /* correct back for delta rot */
1817                                         VecSubf(eul, eul, td->ext->drot);
1818                                         /* and apply */
1819                                         VECCOPY(td->ext->rot, eul);
1820                                 }
1821                         }
1822                 }
1823         }
1824
1825         recalcData(t);
1826
1827         headerprint(str);
1828
1829         force_draw(0);
1830
1831         helpline (t->center);
1832
1833         return 1;
1834 }
1835
1836 /* ************************** TRANSLATION *************************** */
1837         
1838 void initTranslation(TransInfo *t) 
1839 {
1840         t->num.idx_max = 2;
1841         t->transform = Translation;
1842 }
1843
1844 int Translation(TransInfo *t, short mval[2]) 
1845 {
1846         float vec[3], tvec[3];
1847         int i;
1848         char str[70];
1849         TransData *td = t->data;
1850
1851         window_to_3d(vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
1852
1853         if (t->con.applyVec) {
1854                 t->con.applyVec(t, NULL, vec, tvec);
1855                 VECCOPY(vec, tvec);
1856         }
1857
1858         apply_grid1(vec, t->num.idx_max, 1.0f);
1859
1860         applyNumInput(&t->num, vec);
1861
1862         /* header print for NumInput */
1863         if (hasNumInput(&t->num)) {
1864                 char c[60];
1865
1866                 outputNumInput(&(t->num), c);
1867
1868                 sprintf(str, "Dx: %s   Dy: %s  Dz: %s %s", &c[0], &c[20], &c[40], t->proptext);
1869         }
1870         else {
1871                 /* default header print */
1872                 sprintf(str, "Dx: %.4f   Dy: %.4f  Dz: %.4f %s", vec[0], vec[1], vec[2], t->proptext);
1873         }
1874
1875
1876         for(i = 0 ; i < t->total; i++, td++) {
1877                 if (td->flag & TD_NOACTION)
1878                         continue;
1879
1880                 if (t->con.applyVec) {
1881                         t->con.applyVec(t, td, vec, tvec);
1882                 }
1883                 else {
1884                         VECCOPY(tvec, vec);
1885                 }
1886
1887                 Mat3MulVecfl(td->smtx, tvec);
1888                 VecMulf(tvec, td->factor);
1889                 
1890                 /* transdata ipokey */
1891                 if(td->tdi) {
1892                         TransDataIpokey *tdi= td->tdi;
1893                         add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
1894                         add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
1895                         add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
1896                 }
1897                 else VecAddf(td->loc, td->iloc, tvec);
1898         }
1899
1900
1901         recalcData(t);
1902
1903         headerprint(str);
1904
1905         force_draw(0);
1906
1907         return 1;
1908 }