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