6a4fefde029b78d243e3de269628c82572c2ed09
[blender-staging.git] / source / blender / src / transform_generics.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifndef WIN32
42 #include <unistd.h>
43 #else
44 #include <io.h>
45 #endif
46
47 #include "MEM_guardedalloc.h"
48
49 #include "DNA_action_types.h"
50 #include "DNA_armature_types.h"
51 #include "DNA_camera_types.h"
52 #include "DNA_curve_types.h"
53 #include "DNA_effect_types.h"
54 #include "DNA_ika_types.h"
55 #include "DNA_image_types.h"
56 #include "DNA_ipo_types.h"
57 #include "DNA_key_types.h"
58 #include "DNA_lamp_types.h"
59 #include "DNA_lattice_types.h"
60 #include "DNA_mesh_types.h"
61 #include "DNA_meshdata_types.h"
62 #include "DNA_meta_types.h"
63 #include "DNA_object_types.h"
64 #include "DNA_scene_types.h"
65 #include "DNA_screen_types.h"
66 #include "DNA_texture_types.h"
67 #include "DNA_view3d_types.h"
68 #include "DNA_world_types.h"
69 #include "DNA_userdef_types.h"
70 #include "DNA_property_types.h"
71 #include "DNA_vfont_types.h"
72 #include "DNA_constraint_types.h"
73
74 #include "BIF_screen.h"
75 #include "BIF_space.h"
76 #include "BIF_editview.h"
77 #include "BIF_resources.h"
78 #include "BIF_mywindow.h"
79 #include "BIF_gl.h"
80 #include "BIF_editlattice.h"
81 #include "BIF_editarmature.h"
82 #include "BIF_editmesh.h"
83
84 #include "BKE_action.h"
85 #include "BKE_anim.h"
86 #include "BKE_armature.h"
87 #include "BKE_curve.h"
88 #include "BKE_displist.h"
89 #include "BKE_global.h"
90 #include "BKE_ipo.h"
91 #include "BKE_lattice.h"
92 #include "BKE_object.h"
93 #include "BKE_utildefines.h"
94
95 #include "BSE_edit.h"
96 #include "BSE_view.h"
97
98 #include "BLI_arithb.h"
99 #include "BLI_editVert.h"
100
101 #include "blendef.h"
102
103 #include "mydevice.h"
104
105 #include "transform.h"
106
107 extern ListBase editNurb;
108 extern ListBase editelems;
109
110 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING  */
111 extern TransInfo Trans;
112
113 /* ************************** Functions *************************** */
114
115
116 void getViewVector(float coord[3], float vec[3]) {
117         if (G.vd->persp)
118         {
119                 float p1[4], p2[4];
120
121                 VECCOPY(p1, coord);
122                 p1[3] = 1.0f;
123                 VECCOPY(p2, p1);
124                 p2[3] = 1.0f;
125                 Mat4MulVec4fl(G.vd->viewmat, p2);
126
127                 p2[0] = 2.0f * p2[0];
128                 p2[1] = 2.0f * p2[1];
129                 p2[2] = 2.0f * p2[2];
130
131                 Mat4MulVec4fl(G.vd->viewinv, p2);
132
133                 VecSubf(vec, p1, p2);
134         }
135         else {
136                 VECCOPY(vec, G.vd->viewinv[2]);
137         }
138         Normalise(vec);
139 }
140
141 /* ************************** GENERICS **************************** */
142
143 static int pose_flags_reset_done(Object *ob) {
144         /* Clear the constraint done status for every pose channe;
145         * that has been flagged as needing constant updating
146         */
147         bPoseChannel *chan;
148         int numreset = 0;
149         
150         if (ob->pose) {
151                 for (chan = ob->pose->chanbase.first; chan; chan=chan->next){
152                         if (chan->flag & PCHAN_TRANS_UPDATE) {
153                                 chan->flag &= ~PCHAN_DONE;
154                                 numreset++;
155                         }
156                         
157                 }
158         }
159         return numreset;
160 }
161
162
163 /* called for objects updating while transform acts, once per redraw */
164 void recalcData(TransInfo *t)
165 {
166         Base *base;
167         
168         if(G.obpose) {
169                 TransData *td= t->data;
170                 bPoseChannel    *chan;
171                 int     i;
172                 
173                 if (!G.obpose->pose) G.obpose->pose= MEM_callocN(sizeof(bPose), "pose");
174                 
175                 /*      Make channels for the transforming bones (in posemode) */
176                 for (i=0; i<t->total; i++, td++) {
177                         chan = MEM_callocN (sizeof (bPoseChannel), "transPoseChannel");
178                         
179                         if (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL) {
180                                 chan->flag |= POSE_ROT;
181                                 memcpy (chan->quat, td->ext->quat, sizeof (chan->quat));
182                         }
183                         if (t->mode == TFM_TRANSLATION) {
184                                 chan->flag |= POSE_LOC;
185                                 memcpy (chan->loc, td->loc, sizeof (chan->loc));
186                         }
187                         if (t->mode == TFM_RESIZE) {
188                                 chan->flag |= POSE_SIZE;
189                                 memcpy (chan->size, td->ext->size, sizeof (chan->size));
190                         }
191                         
192                         strcpy (chan->name, ((Bone*) td->ext->bone)->name);
193                         
194                         set_pose_channel (G.obpose->pose, chan);
195
196                 }
197                 
198                 clear_pose_constraint_status(G.obpose);
199                 
200                 if (!is_delay_deform()) make_displists_by_armature(G.obpose);
201                 
202         }
203         else if (G.obedit) {
204                 if (G.obedit->type == OB_MESH) {
205                         recalc_editnormals();
206                         makeDispList(G.obedit);
207                 }
208                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
209                         Nurb *nu= editNurb.first;
210                         while(nu) {
211                                 test2DNurb(nu);
212                                 testhandlesNurb(nu); /* test for bezier too */
213                                 nu= nu->next;
214                         }
215                         makeDispList(G.obedit);
216
217                         makeBevelList(G.obedit); // might be needed for deform
218                         calc_curvepath(G.obedit);
219                         
220                         // deform, bevel, taper
221                         base= FIRSTBASE;
222                         while(base) {
223                                 if(base->lay & G.vd->lay) {
224                                         if(base->object->parent==G.obedit && base->object->partype==PARSKEL)
225                                                 makeDispList(base->object);
226                                         else if(base->object->type==OB_CURVE) {
227                                                 Curve *cu= base->object->data;
228                                                 if(G.obedit==cu->bevobj || G.obedit==cu->taperobj)
229                                                         makeDispList(base->object);
230                                         }
231                                 }
232                                 base= base->next;
233                         }
234                 }
235                 else if(G.obedit->type==OB_ARMATURE){
236                         EditBone *ebo;
237                         
238                         /* Ensure all bones are correctly adjusted */
239                         for (ebo=G.edbo.first; ebo; ebo=ebo->next){
240                                 
241                                 if ((ebo->flag & BONE_IK_TOPARENT) && ebo->parent){
242                                         /* If this bone has a parent tip that has been moved */
243                                         if (ebo->parent->flag & BONE_TIPSEL){
244                                                 VECCOPY (ebo->head, ebo->parent->tail);
245                                         }
246                                         /* If this bone has a parent tip that has NOT been moved */
247                                         else{
248                                                 VECCOPY (ebo->parent->tail, ebo->head);
249                                         }
250                                 }
251                         }
252                 }
253                 else if(G.obedit->type==OB_LATTICE) {
254                         
255                         if(editLatt->flag & LT_OUTSIDE) outside_lattice(editLatt);
256                         
257                         base= FIRSTBASE;
258                         while(base) {
259                                 if(base->lay & G.vd->lay) {
260                                         if(base->object->parent==G.obedit) {
261                                                 makeDispList(base->object);
262                                         }
263                                 }
264                                 base= base->next;
265                         }
266                 }
267                 else if (G.obedit->type == OB_MBALL) {
268                         makeDispList(G.obedit); 
269                 }       
270         }
271         else {
272                 
273                 base= FIRSTBASE;
274                 while(base) {
275                         if(base->flag & BA_DO_IPO) {
276                                 if(base->object->ipo) {
277                                         IpoCurve *icu;
278                                         
279                                         base->object->ctime= -1234567.0;
280                                         
281                                         icu= base->object->ipo->curve.first;
282                                         while(icu) {
283                                                 calchandles_ipocurve(icu);
284                                                 icu= icu->next;
285                                         }
286                                 }                               
287                         }
288                         if(base->object->partype & PARSLOW) {
289                                 base->object->partype -= PARSLOW;
290                                 where_is_object(base->object);
291                                 base->object->partype |= PARSLOW;
292                         }
293                         else if(base->flag & BA_WHERE_UPDATE) {
294                                 where_is_object(base->object);
295                         }
296                         
297                         base= base->next;
298                 } 
299                 
300                 base= FIRSTBASE;
301                 while(base) {
302                         
303                         if(base->flag & BA_DISP_UPDATE) makeDispList(base->object);
304                         
305                         base= base->next;
306                 }
307         }
308         
309         /* ugly stuff for posemode, copied from old system */
310         base= FIRSTBASE;
311         while(base) {
312                 
313                 if (pose_flags_reset_done(base->object)) {
314                         if (!is_delay_deform())
315                                 make_displists_by_armature(base->object);
316                 }
317                 
318                 base= base->next;
319         }
320         
321         if (G.obpose && G.obpose->type == OB_ARMATURE)
322                 clear_pose_constraint_status(G.obpose);
323         
324         if (!is_delay_deform()) make_displists_by_armature(G.obpose);
325
326         
327         /* update shaded drawmode while transform */
328         if(G.vd->drawtype == OB_SHADED) reshadeall_displist();
329         
330 }
331
332 void initTransModeFlags(TransInfo *t, int mode) 
333 {
334         t->mode = mode;
335         t->num.flag = 0;
336
337         /* REMOVING RESTRICTIONS FLAGS */
338         t->flag &= ~T_ALL_RESTRICTIONS;
339         
340         switch (mode) {
341         case TFM_RESIZE:
342                 t->flag |= T_NULL_ONE;
343                 t->num.flag |= NUM_NULL_ONE;
344                 t->num.flag |= NUM_AFFECT_ALL;
345                 if (!G.obedit) {
346                         t->flag |= T_NO_ZERO;
347                         t->num.flag |= NUM_NO_ZERO;
348                 }
349                 break;
350         case TFM_TOSPHERE:
351                 t->num.flag |= NUM_NULL_ONE;
352                 t->num.flag |= NUM_NO_NEGATIVE;
353                 t->flag |= T_NO_CONSTRAINT;
354                 break;
355         case TFM_SHEAR:
356                 t->flag |= T_NO_CONSTRAINT;
357                 break;
358         case TFM_CREASE:
359                 t->flag |= T_NO_CONSTRAINT;
360                 break;
361         }
362 }
363
364 void drawLine(float *center, float *dir, char axis, short options)
365 {
366         extern void make_axis_color(char *col, char *col2, char axis);  // drawview.c
367         float v1[3], v2[3], v3[3];
368         char col[3], col2[3];
369         
370         //if(G.obedit) mymultmatrix(G.obedit->obmat);   // sets opengl viewing
371
372         VecCopyf(v3, dir);
373         VecMulf(v3, G.vd->far);
374         
375         VecSubf(v2, center, v3);
376         VecAddf(v1, center, v3);
377
378         if (options & DRAWLIGHT) {
379                 col[0] = col[1] = col[2] = 220;
380         }
381         else {
382                 BIF_GetThemeColor3ubv(TH_GRID, col);
383         }
384         make_axis_color(col, col2, axis);
385         glColor3ubv(col2);
386
387         setlinestyle(0);
388         glBegin(GL_LINE_STRIP); 
389                 glVertex3fv(v1); 
390                 glVertex3fv(v2); 
391         glEnd();
392         
393         myloadmatrix(G.vd->viewmat);
394 }
395
396 void initTrans (TransInfo *t)
397 {
398
399         /* moving: is shown in drawobject() (transform color) */
400         if(G.obedit || G.obpose) G.moving= G_TRANSFORM_EDIT;
401         else G.moving= G_TRANSFORM_OBJ;
402
403         t->data = NULL;
404         t->ext = NULL;
405
406         t->flag = 0;
407
408         /* setting PET flag */
409         if ((t->context & CTX_NO_PET) == 0 && (G.scene->proportional)) {
410                 t->flag |= T_PROP_EDIT;
411                 if(G.scene->proportional==2) t->flag |= T_PROP_CONNECTED;       // yes i know, has to become define
412         }
413
414         getmouseco_areawin(t->imval);
415         t->con.imval[0] = t->imval[0];
416         t->con.imval[1] = t->imval[1];
417
418         t->transform            = NULL;
419
420         t->total                        =
421                 t->num.idx              =
422                 t->num.idx_max  =
423                 t->num.ctrl[0]  = 
424                 t->num.ctrl[1]  = 
425                 t->num.ctrl[2]  = 0;
426
427         t->val = 0.0f;
428
429         t->num.val[0]           = 
430                 t->num.val[1]   = 
431                 t->num.val[2]   = 0.0f;
432
433         t->vec[0]                       =
434                 t->vec[1]               =
435                 t->vec[2]               = 0.0f;
436         
437         Mat3One(t->mat);
438         
439         Mat4CpyMat4(t->viewmat, G.vd->viewmat);
440         Mat4CpyMat4(t->viewinv, G.vd->viewinv);
441         Mat4CpyMat4(t->persinv, G.vd->persinv);
442 }
443
444 /* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
445 void postTrans (TransInfo *t) 
446 {
447         G.moving = 0; // Set moving flag off (display as usual)
448
449         stopConstraint(t);
450         /* Not needed anymore but will keep there in case it will be
451         t->con.drawExtra = NULL;
452         t->con.applyVec = NULL;
453         t->con.applySize= NULL;
454         t->con.applyRot = NULL;
455         t->con.mode             = 0;
456         */
457
458         
459         /* postTrans can be called when nothing is selected, so data is NULL already */
460         if (t->data) {
461                 TransData *td;
462                 int a;
463
464                 /* since ipokeys are optional on objects, we mallocced them per trans-data */
465                 for(a=0, td= t->data; a<t->total; a++, td++) {
466                         if(td->tdi) MEM_freeN(td->tdi);
467                 }
468                 MEM_freeN(t->data);
469         }
470
471         if (t->ext) MEM_freeN(t->ext);
472         
473 }
474
475 void apply_grid3(float *val, int max_index, float fac1, float fac2, float fac3)
476 {
477         /* fac1 is for 'nothing', fac2 for CTRL, fac3 for SHIFT */
478         int invert = U.flag & USER_AUTOGRABGRID;
479         int ctrl;
480         int i;
481
482         for (i=0; i<=max_index; i++) {
483
484                 if(invert) {
485                         if(G.qual & LR_CTRLKEY) ctrl= 0;
486                         else ctrl= 1;
487                 }
488                 else ctrl= (G.qual & LR_CTRLKEY);
489
490                 if(ctrl && (G.qual & LR_SHIFTKEY)) {
491                         if(fac3!= 0.0) {
492                                 for (i=0; i<=max_index; i++) {
493                                         val[i]= fac3*(float)floor(val[i]/fac3 +.5);
494                                 }
495                         }
496                 }
497                 else if(ctrl) {
498                         if(fac2!= 0.0) {
499                                 for (i=0; i<=max_index; i++) {
500                                         val[i]= fac2*(float)floor(val[i]/fac2 +.5);
501                                 }
502                         }
503                 }
504                 else {
505                         if(fac1!= 0.0) {
506                                 for (i=0; i<=max_index; i++) {
507                                         val[i]= fac1*(float)floor(val[i]/fac1 +.5);
508                                 }
509                         }
510                 }
511         }
512 }
513
514 void snapGrid(TransInfo *t, float *val) {
515         apply_grid3(val, t->idx_max, t->snap[0], t->snap[1], t->snap[2]);
516 }
517
518 void applyTransObjects(TransInfo *t)
519 {
520         TransData *td;
521         
522         for (td = t->data; td < t->data + t->total; td++) {
523                 VECCOPY(td->iloc, td->loc);
524                 if (td->ext->rot) {
525                         VECCOPY(td->ext->irot, td->ext->rot);
526                 }
527                 if (td->ext->size) {
528                         VECCOPY(td->ext->isize, td->ext->size);
529                 }
530         }       
531         recalcData(t);
532
533
534 /* helper for below */
535 static void restore_ipokey(float *poin, float *old)
536 {
537         if(poin) {
538                 poin[0]= old[0];
539                 poin[-3]= old[3];
540                 poin[3]= old[6];
541         }
542 }
543
544 void restoreElement(TransData *td) {
545         /* TransData for crease has no loc */
546         if (td->loc) {
547                 VECCOPY(td->loc, td->iloc);
548         }
549         if (td->val) {
550                 *td->val = td->ival;
551         }
552         if (td->ext) {
553                 if (td->ext->rot) {
554                         VECCOPY(td->ext->rot, td->ext->irot);
555                 }
556                 if (td->ext->size) {
557                         VECCOPY(td->ext->size, td->ext->isize);
558                 }
559                 if(td->flag & TD_USEQUAT) {
560                         if (td->ext->quat) {
561                                 QUATCOPY(td->ext->quat, td->ext->iquat);
562                         }
563                 }
564         }
565         if(td->tdi) {
566                 TransDataIpokey *tdi= td->tdi;
567                 
568                 restore_ipokey(tdi->locx, tdi->oldloc);
569                 restore_ipokey(tdi->locy, tdi->oldloc+1);
570                 restore_ipokey(tdi->locz, tdi->oldloc+2);
571
572                 restore_ipokey(tdi->rotx, tdi->oldrot);
573                 restore_ipokey(tdi->roty, tdi->oldrot+1);
574                 restore_ipokey(tdi->rotz, tdi->oldrot+2);
575                 
576                 restore_ipokey(tdi->sizex, tdi->oldsize);
577                 restore_ipokey(tdi->sizey, tdi->oldsize+1);
578                 restore_ipokey(tdi->sizez, tdi->oldsize+2);
579         }
580 }
581
582 void restoreTransObjects(TransInfo *t)
583 {
584         TransData *td;
585         
586         for (td = t->data; td < t->data + t->total; td++) {
587                 restoreElement(td);
588         }       
589         recalcData(t);
590
591
592 void calculateCenterCursor(TransInfo *t)
593 {
594         float *cursor;
595
596         cursor = give_cursor();
597         VECCOPY(t->center, cursor);
598
599         if(t->flag & (T_EDIT|T_POSE)) {
600                 Object *ob= G.obedit?G.obedit:G.obpose;
601                 float mat[3][3], imat[3][3];
602                 float vec[3];
603                 
604                 VecSubf(t->center, t->center, ob->obmat[3]);
605                 Mat3CpyMat4(mat, ob->obmat);
606                 Mat3Inv(imat, mat);
607                 Mat3MulVecfl(imat, t->center);
608                 
609                 VECCOPY(vec, t->center);
610                 Mat4MulVecfl(ob->obmat, vec);
611                 project_short_noclip(vec, t->center2d);
612         }
613         else {
614                 project_short_noclip(t->center, t->center2d);
615         }
616 }
617
618 void calculateCenterMedian(TransInfo *t)
619 {
620         float partial[3] = {0.0f, 0.0f, 0.0f};
621         int i;
622         for(i = 0; i < t->total; i++) {
623                 if (t->data[i].flag & TD_SELECTED) {
624                         VecAddf(partial, partial, t->data[i].center);
625                 }
626                 else {
627                         /* 
628                            All the selected elements are at the head of the array 
629                            which means we can stop when it finds unselected data
630                         */
631                         break;
632                 }
633         }
634         VecMulf(partial, 1.0f / i);
635         VECCOPY(t->center, partial);
636
637         if (t->flag & (T_EDIT|T_POSE)) {
638                 Object *ob= G.obedit?G.obedit:G.obpose;
639                 float vec[3];
640                 
641                 VECCOPY(vec, t->center);
642                 Mat4MulVecfl(ob->obmat, vec);
643                 project_short_noclip(vec, t->center2d);
644         }
645         else {
646                 project_short_noclip(t->center, t->center2d);
647         }
648 }
649
650 void calculateCenterBound(TransInfo *t)
651 {
652         float max[3];
653         float min[3];
654         int i;
655         for(i = 0; i < t->total; i++) {
656                 if (i) {
657                         if (t->data[i].flag & TD_SELECTED) {
658                                 MinMax3(min, max, t->data[i].center);
659                         }
660                         else {
661                                 /* 
662                                    All the selected elements are at the head of the array 
663                                    which means we can stop when it finds unselected data
664                                 */
665                                 break;
666                         }
667                 }
668                 else {
669                         VECCOPY(max, t->data[i].center);
670                         VECCOPY(min, t->data[i].center);
671                 }
672         }
673         VecAddf(t->center, min, max);
674         VecMulf(t->center, 0.5);
675
676         if (t->flag & (T_EDIT|T_POSE)) {
677                 Object *ob= G.obedit?G.obedit:G.obpose;
678                 float vec[3];
679                 
680                 VECCOPY(vec, t->center);
681                 Mat4MulVecfl(ob->obmat, vec);
682                 project_short_noclip(vec, t->center2d);
683         }
684         else {
685                 project_short_noclip(t->center, t->center2d);
686         }
687 }
688
689 void calculateCenter(TransInfo *t) 
690 {
691         switch(G.vd->around) {
692         case V3D_CENTRE:
693                 calculateCenterBound(t);
694                 break;
695         case V3D_CENTROID:
696                 calculateCenterMedian(t);
697                 break;
698         case V3D_CURSOR:
699                 calculateCenterCursor(t);
700                 break;
701         case V3D_LOCAL:
702                 /* Individual element center uses median center for helpline and such */
703                 calculateCenterMedian(t);
704                 break;
705         case V3D_ACTIVE:
706                 /* set median, and if if if... do object center */
707                 calculateCenterMedian(t);
708                 if((t->flag & (T_EDIT|T_POSE))==0) {
709                         Object *ob= OBACT;
710                         if(ob) {
711                                 VECCOPY(t->center, ob->obmat[3]);
712                                 project_short_noclip(t->center, t->center2d);
713                         }
714                 }
715                 
716         }
717
718         /* setting constraint center */
719         VECCOPY(t->con.center, t->center);
720         if(t->flag & (T_EDIT|T_POSE)) {
721                 Object *ob= G.obedit?G.obedit:G.obpose;
722                 Mat4MulVecfl(ob->obmat, t->con.center);
723         }
724
725         /* voor panning from cameraview */
726         if(t->flag & T_OBJECT) {
727                 if( G.vd->camera==OBACT && G.vd->persp>1) {
728                         float axis[3];
729                         /* persinv is nasty, use viewinv instead, always right */
730                         VECCOPY(axis, G.vd->viewinv[2]);
731                         Normalise(axis);
732
733                         /* 6.0 = 6 grid units */
734                         axis[0]= t->center[0]- 6.0f*axis[0];
735                         axis[1]= t->center[1]- 6.0f*axis[1];
736                         axis[2]= t->center[2]- 6.0f*axis[2];
737                         
738                         project_short_noclip(axis, t->center2d);
739                         
740                         /* rotate only needs correct 2d center, grab needs initgrabz() value */
741                         if(t->mode==TFM_TRANSLATION) VECCOPY(t->center, axis);
742                 }
743         }       
744         initgrabz(t->center[0], t->center[1], t->center[2]);
745 }
746
747 void calculatePropRatio(TransInfo *t)
748 {
749         TransData *td = t->data;
750         int i;
751         float dist;
752         short connected = t->flag & T_PROP_CONNECTED;
753
754         if (t->flag & T_PROP_EDIT) {
755                 for(i = 0 ; i < t->total; i++, td++) {
756                         if (td->flag & TD_SELECTED) {
757                                 td->factor = 1.0f;
758                         }
759                         else if ((connected && 
760                                                 (td->flag & TD_NOTCONNECTED || td->dist > t->propsize))
761                                 ||
762                                         (connected == 0 &&
763                                                 td->rdist > t->propsize)) {
764                                 /* 
765                                    The elements are sorted according to their dist member in the array,
766                                    that means we can stop when it finds one element outside of the propsize.
767                                 */
768                                 td->flag |= TD_NOACTION;
769                                 td->factor = 0.0f;
770                                 restoreElement(td);
771                         }
772                         else {
773                                 /* Use rdist for falloff calculations, it is the real distance */
774                                 td->flag &= ~TD_NOACTION;
775                                 dist= (t->propsize-td->rdist)/t->propsize;
776                                 switch(G.scene->prop_mode) {
777                                 case PROP_SHARP:
778                                         td->factor= dist*dist;
779                                         break;
780                                 case PROP_SMOOTH:
781                                         td->factor= 3.0f*dist*dist - 2.0f*dist*dist*dist;
782                                         break;
783                                 case PROP_ROOT:
784                                         td->factor = (float)sqrt(dist);
785                                         break;
786                                 case PROP_LIN:
787                                         td->factor = dist;
788                                         break;
789                                 case PROP_CONST:
790                                         td->factor = 1.0f;
791                                         break;
792                                 case PROP_SPHERE:
793                                         td->factor = (float)sqrt(2*dist - dist * dist);
794                                         break;
795                                 default:
796                                         td->factor = 1;
797                                 }
798                         }
799                 }
800                 switch(G.scene->prop_mode) {
801                 case PROP_SHARP:
802                         strcpy(t->proptext, "(Sharp)");
803                         break;
804                 case PROP_SMOOTH:
805                         strcpy(t->proptext, "(Smooth)");
806                         break;
807                 case PROP_ROOT:
808                         strcpy(t->proptext, "(Root)");
809                         break;
810                 case PROP_LIN:
811                         strcpy(t->proptext, "(Linear)");
812                         break;
813                 case PROP_CONST:
814                         strcpy(t->proptext, "(Constant)");
815                         break;
816                 case PROP_SPHERE:
817                         strcpy(t->proptext, "(Sphere)");
818                         break;
819                 default:
820                         strcpy(t->proptext, "");
821                 }
822         }
823         else {
824                 for(i = 0 ; i < t->total; i++, td++) {
825                         td->factor = 1.0;
826                 }
827                 strcpy(t->proptext, "");
828         }
829 }
830
831 TransInfo * BIF_GetTransInfo() {
832         return &Trans;
833 }
834