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