svn merge -r41638:41648 ^/trunk/blender
[blender.git] / source / blender / editors / transform / transform_generics.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/transform/transform_generics.c
29  *  \ingroup edtransform
30  */
31
32
33 #include <string.h>
34 #include <math.h>
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLO_sys_types.h" // for intptr_t support
39
40 #include "DNA_anim_types.h"
41 #include "DNA_armature_types.h"
42 #include "DNA_lattice_types.h"
43 #include "DNA_screen_types.h"
44 #include "DNA_space_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_meshdata_types.h"
48 #include "DNA_view3d_types.h"
49 #include "DNA_modifier_types.h"
50 #include "DNA_movieclip_types.h"
51
52 #include "RNA_access.h"
53
54 //#include "BIF_screen.h"
55 //#include "BIF_mywindow.h"
56 #include "BIF_gl.h"
57 #include "BIF_glutil.h"
58 //#include "BIF_editmesh.h"
59 //#include "BIF_editsima.h"
60 //#include "BIF_editparticle.h"
61 //#include "BIF_meshtools.h"
62
63 #include "BKE_animsys.h"
64 #include "BKE_action.h"
65 #include "BKE_armature.h"
66 #include "BKE_curve.h"
67 #include "BKE_depsgraph.h"
68 #include "BKE_displist.h"
69 #include "BKE_fcurve.h"
70 #include "BKE_lattice.h"
71 #include "BKE_mesh.h"
72 #include "BKE_nla.h"
73 #include "BKE_context.h"
74 #include "BKE_tessmesh.h"
75 #include "BKE_tracking.h"
76
77 #include "ED_anim_api.h"
78 #include "ED_armature.h"
79 #include "ED_image.h"
80 #include "ED_keyframing.h"
81 #include "ED_markers.h"
82 #include "ED_mesh.h"
83 #include "ED_particle.h"
84 #include "ED_screen_types.h"
85 #include "ED_space_api.h"
86 #include "ED_uvedit.h"
87 #include "ED_view3d.h"
88 #include "ED_curve.h" /* for curve_editnurbs */
89 #include "ED_clip.h"
90
91 //#include "BDR_unwrapper.h"
92
93 #include "BLI_math.h"
94 #include "BLI_blenlib.h"
95 #include "BLI_editVert.h"
96 #include "BLI_rand.h"
97 #include "BLI_utildefines.h"
98
99 #include "WM_types.h"
100 #include "WM_api.h"
101
102 #include "UI_resources.h"
103
104 //#include "blendef.h"
105 //
106 //#include "mydevice.h"
107
108 #include "transform.h"
109
110 extern ListBase editelems;
111
112 /* ************************** Functions *************************** */
113
114 void getViewVector(TransInfo *t, float coord[3], float vec[3])
115 {
116         if (t->persp != RV3D_ORTHO)
117         {
118                 float p1[4], p2[4];
119                 
120                 copy_v3_v3(p1, coord);
121                 p1[3] = 1.0f;
122                 copy_v3_v3(p2, p1);
123                 p2[3] = 1.0f;
124                 mul_m4_v4(t->viewmat, p2);
125                 
126                 p2[0] = 2.0f * p2[0];
127                 p2[1] = 2.0f * p2[1];
128                 p2[2] = 2.0f * p2[2];
129                 
130                 mul_m4_v4(t->viewinv, p2);
131                 
132                 sub_v3_v3v3(vec, p1, p2);
133         }
134         else {
135                 copy_v3_v3(vec, t->viewinv[2]);
136         }
137         normalize_v3(vec);
138 }
139
140 /* ************************** GENERICS **************************** */
141
142 static void clipMirrorModifier(TransInfo *t, Object *ob)
143 {
144         ModifierData *md= ob->modifiers.first;
145         float tolerance[3] = {0.0f, 0.0f, 0.0f};
146         int axis = 0;
147         
148         for (; md; md=md->next) {
149                 if ((md->type==eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
150                         MirrorModifierData *mmd = (MirrorModifierData*) md;
151                         
152                         if(mmd->flag & MOD_MIR_CLIPPING) {
153                                 axis = 0;
154                                 if(mmd->flag & MOD_MIR_AXIS_X) {
155                                         axis |= 1;
156                                         tolerance[0] = mmd->tolerance;
157                                 }
158                                 if(mmd->flag & MOD_MIR_AXIS_Y) {
159                                         axis |= 2;
160                                         tolerance[1] = mmd->tolerance;
161                                 }
162                                 if(mmd->flag & MOD_MIR_AXIS_Z) {
163                                         axis |= 4;
164                                         tolerance[2] = mmd->tolerance;
165                                 }
166                                 if (axis) {
167                                         float mtx[4][4], imtx[4][4];
168                                         int i;
169                                         TransData *td = t->data;
170                                         
171                                         if (mmd->mirror_ob) {
172                                                 float obinv[4][4];
173                                                 
174                                                 invert_m4_m4(obinv, mmd->mirror_ob->obmat);
175                                                 mul_m4_m4m4(mtx, ob->obmat, obinv);
176                                                 invert_m4_m4(imtx, mtx);
177                                         }
178                                         
179                                         for(i = 0 ; i < t->total; i++, td++) {
180                                                 int clip;
181                                                 float loc[3], iloc[3];
182                                                 
183                                                 if (td->flag & TD_NOACTION)
184                                                         break;
185                                                 if (td->loc==NULL)
186                                                         break;
187                                                 
188                                                 if (td->flag & TD_SKIP)
189                                                         continue;
190                                                 
191                                                 copy_v3_v3(loc,  td->loc);
192                                                 copy_v3_v3(iloc, td->iloc);
193                                                 
194                                                 if (mmd->mirror_ob) {
195                                                         mul_m4_v3(mtx, loc);
196                                                         mul_m4_v3(mtx, iloc);
197                                                 }
198                                                 
199                                                 clip = 0;
200                                                 if(axis & 1) {
201                                                         if(fabs(iloc[0])<=tolerance[0] ||
202                                                            loc[0]*iloc[0]<0.0f) {
203                                                                 loc[0]= 0.0f;
204                                                                 clip = 1;
205                                                         }
206                                                 }
207                                                 
208                                                 if(axis & 2) {
209                                                         if(fabs(iloc[1])<=tolerance[1] ||
210                                                            loc[1]*iloc[1]<0.0f) {
211                                                                 loc[1]= 0.0f;
212                                                                 clip = 1;
213                                                         }
214                                                 }
215                                                 if(axis & 4) {
216                                                         if(fabs(iloc[2])<=tolerance[2] ||
217                                                            loc[2]*iloc[2]<0.0f) {
218                                                                 loc[2]= 0.0f;
219                                                                 clip = 1;
220                                                         }
221                                                 }
222                                                 if (clip) {
223                                                         if (mmd->mirror_ob) {
224                                                                 mul_m4_v3(imtx, loc);
225                                                         }
226                                                         copy_v3_v3(td->loc, loc);
227                                                 }
228                                         }
229                                 }
230                                 
231                         }
232                 }
233         }
234 }
235
236 /* assumes obedit set to mesh object */
237 static void editbmesh_apply_to_mirror(TransInfo *t)
238 {
239         TransData *td = t->data;
240         BMVert *eve;
241         int i;
242         
243         for(i = 0 ; i < t->total; i++, td++) {
244                 if (td->flag & TD_NOACTION)
245                         break;
246                 if (td->loc==NULL)
247                         break;
248                 if (td->flag & TD_SKIP)
249                         continue;
250                 
251                 eve = td->extra;
252                 if (eve) {
253                         eve->co[0]= -td->loc[0];
254                         eve->co[1]= td->loc[1];
255                         eve->co[2]= td->loc[2];
256                 }
257                 
258                 if (td->flag & TD_MIRROR_EDGE)
259                 {
260                         td->loc[0] = 0;
261                 }
262         }
263 }
264
265 /* for the realtime animation recording feature, handle overlapping data */
266 static void animrecord_check_state (Scene *scene, ID *id, wmTimer *animtimer)
267 {
268         ScreenAnimData *sad= (animtimer) ? animtimer->customdata : NULL;
269         
270         /* sanity checks */
271         if ELEM3(NULL, scene, id, sad)
272                 return;
273         
274         /* check if we need a new strip if:
275          *      - if animtimer is running 
276          *      - we're not only keying for available channels
277          *      - the option to add new actions for each round is not enabled
278          */
279         if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)==0 && (scene->toolsettings->autokey_flag & ANIMRECORD_FLAG_WITHNLA)) {
280                 /* if playback has just looped around, we need to add a new NLA track+strip to allow a clean pass to occur */
281                 if ((sad) && (sad->flag & ANIMPLAY_FLAG_JUMPED)) {
282                         AnimData *adt= BKE_animdata_from_id(id);
283                         
284                         /* perform push-down manually with some differences 
285                          * NOTE: BKE_nla_action_pushdown() sync warning...
286                          */
287                         if ((adt->action) && !(adt->flag & ADT_NLA_EDIT_ON)) {
288                                 float astart, aend;
289                                 
290                                 /* only push down if action is more than 1-2 frames long */
291                                 calc_action_range(adt->action, &astart, &aend, 1);
292                                 if (aend > astart+2.0f) {
293                                         NlaStrip *strip= add_nlastrip_to_stack(adt, adt->action);
294                                         
295                                         /* clear reference to action now that we've pushed it onto the stack */
296                                         adt->action->id.us--;
297                                         adt->action= NULL;
298                                         
299                                         /* adjust blending + extend so that they will behave correctly */
300                                         strip->extendmode= NLASTRIP_EXTEND_NOTHING;
301                                         strip->flag &= ~(NLASTRIP_FLAG_AUTO_BLENDS|NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_ACTIVE);
302                                         
303                                         /* also, adjust the AnimData's action extend mode to be on 
304                                          * 'nothing' so that previous result still play 
305                                          */
306                                         adt->act_extendmode= NLASTRIP_EXTEND_NOTHING;
307                                 }
308                         }
309                 }
310         }
311 }
312
313 static int fcu_test_selected(FCurve *fcu)
314 {
315         BezTriple *bezt= fcu->bezt;
316         unsigned int i;
317
318         if (bezt==NULL) /* ignore baked */
319                 return 0;
320
321         for (i=0; i < fcu->totvert; i++, bezt++) {
322                 if (BEZSELECTED(bezt)) return 1;
323         }
324
325         return 0;
326 }
327
328 /* helper for recalcData() - for Action Editor transforms */
329 static void recalcData_actedit(TransInfo *t)
330 {
331         Scene *scene= t->scene;
332         SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first;
333         
334         bAnimContext ac= {NULL};
335         ListBase anim_data = {NULL, NULL};
336         bAnimListElem *ale;
337         int filter;
338         
339         /* initialise relevant anim-context 'context' data from TransInfo data */
340                 /* NOTE: sync this with the code in ANIM_animdata_get_context() */
341         ac.scene= t->scene;
342         ac.obact= OBACT;
343         ac.sa= t->sa;
344         ac.ar= t->ar;
345         ac.sl= (t->sa)? t->sa->spacedata.first : NULL;
346         ac.spacetype= (t->sa)? t->sa->spacetype : 0;
347         ac.regiontype= (t->ar)? t->ar->regiontype : 0;
348         
349         ANIM_animdata_context_getdata(&ac);
350         
351         /* perform flush */
352         if (ac.datatype == ANIMCONT_GPENCIL) {
353                 /* flush transform values back to actual coordinates */
354                 flushTransGPactionData(t);
355         }
356         else {
357                 /* get animdata blocks visible in editor, assuming that these will be the ones where things changed */
358                 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
359                 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
360                 
361                 /* just tag these animdata-blocks to recalc, assuming that some data there changed 
362                  * BUT only do this if realtime updates are enabled
363                  */
364                 if ((saction->flag & SACTION_NOREALTIMEUPDATES) == 0) {
365                         for (ale= anim_data.first; ale; ale= ale->next) {
366                                 /* set refresh tags for objects using this animation */
367                                 ANIM_list_elem_update(t->scene, ale);
368                         }
369                 }
370                 
371                 /* now free temp channels */
372                 BLI_freelistN(&anim_data);
373         }
374 }
375 /* helper for recalcData() - for Graph Editor transforms */
376 static void recalcData_graphedit(TransInfo *t)
377 {
378         SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first;
379         Scene *scene;
380         
381         ListBase anim_data = {NULL, NULL};
382         bAnimContext ac= {NULL};
383         int filter;
384         
385         bAnimListElem *ale;
386         int dosort = 0;
387         
388         
389         /* initialise relevant anim-context 'context' data from TransInfo data */
390                 /* NOTE: sync this with the code in ANIM_animdata_get_context() */
391         scene= ac.scene= t->scene;
392         ac.obact= OBACT;
393         ac.sa= t->sa;
394         ac.ar= t->ar;
395         ac.sl= (t->sa)? t->sa->spacedata.first : NULL;
396         ac.spacetype= (t->sa)? t->sa->spacetype : 0;
397         ac.regiontype= (t->ar)? t->ar->regiontype : 0;
398         
399         ANIM_animdata_context_getdata(&ac);
400         
401         /* do the flush first */
402         flushTransGraphData(t);
403         
404         /* get curves to check if a re-sort is needed */
405         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
406         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
407         
408         /* now test if there is a need to re-sort */
409         for (ale= anim_data.first; ale; ale= ale->next) {
410                 FCurve *fcu= (FCurve *)ale->key_data;
411                 
412                 /* ignore unselected fcurves */
413                 if (!fcu_test_selected(fcu))
414                         continue;
415                 
416                 // fixme: only do this for selected verts...
417                 ANIM_unit_mapping_apply_fcurve(ac.scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYSEL|ANIM_UNITCONV_SELVERTS|ANIM_UNITCONV_RESTORE);
418                 
419                 
420                 /* watch it: if the time is wrong: do not correct handles yet */
421                 if (test_time_fcurve(fcu))
422                         dosort++;
423                 else
424                         calchandles_fcurve(fcu);
425                 
426                 /* set refresh tags for objects using this animation,
427                  * BUT only if realtime updates are enabled  
428                  */
429                 if ((sipo->flag & SIPO_NOREALTIMEUPDATES) == 0)
430                         ANIM_list_elem_update(t->scene, ale);
431         }
432         
433         /* do resort and other updates? */
434         if (dosort) remake_graph_transdata(t, &anim_data);
435         
436         /* now free temp channels */
437         BLI_freelistN(&anim_data);
438 }
439
440 /* helper for recalcData() - for NLA Editor transforms */
441 static void recalcData_nla(TransInfo *t)
442 {
443         TransDataNla *tdn= (TransDataNla *)t->customData;
444         SpaceNla *snla= (SpaceNla *)t->sa->spacedata.first;
445         Scene *scene= t->scene;
446         double secf= FPS;
447         int i;
448         
449         /* for each strip we've got, perform some additional validation of the values that got set before
450          * using RNA to set the value (which does some special operations when setting these values to make
451          * sure that everything works ok)
452          */
453         for (i = 0; i < t->total; i++, tdn++) {
454                 NlaStrip *strip= tdn->strip;
455                 PointerRNA strip_ptr;
456                 short pExceeded, nExceeded, iter;
457                 int delta_y1, delta_y2;
458                 
459                 /* if this tdn has no handles, that means it is just a dummy that should be skipped */
460                 if (tdn->handle == 0)
461                         continue;
462                 
463                 /* set refresh tags for objects using this animation,
464                  * BUT only if realtime updates are enabled  
465                  */
466                 if ((snla->flag & SNLA_NOREALTIMEUPDATES) == 0)
467                         ANIM_id_update(t->scene, tdn->id);
468                 
469                 /* if cancelling transform, just write the values without validating, then move on */
470                 if (t->state == TRANS_CANCEL) {
471                         /* clear the values by directly overwriting the originals, but also need to restore
472                          * endpoints of neighboring transition-strips
473                          */
474                         
475                         /* start */
476                         strip->start= tdn->h1[0];
477                         
478                         if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION))
479                                 strip->prev->end= tdn->h1[0];
480                         
481                         /* end */
482                         strip->end= tdn->h2[0];
483                         
484                         if ((strip->next) && (strip->next->type == NLASTRIP_TYPE_TRANSITION))
485                                 strip->next->start= tdn->h2[0];
486                         
487                         /* flush transforms to child strips (since this should be a meta) */
488                         BKE_nlameta_flush_transforms(strip);
489                         
490                         /* restore to original track (if needed) */
491                         if (tdn->oldTrack != tdn->nlt) {
492                                 /* just append to end of list for now, since strips get sorted in special_aftertrans_update() */
493                                 BLI_remlink(&tdn->nlt->strips, strip);
494                                 BLI_addtail(&tdn->oldTrack->strips, strip);
495                         }
496                         
497                         continue;
498                 }
499                 
500                 /* firstly, check if the proposed transform locations would overlap with any neighbouring strips
501                  * (barring transitions) which are absolute barriers since they are not being moved
502                  *
503                  * this is done as a iterative procedure (done 5 times max for now)
504                  */
505                 for (iter=0; iter < 5; iter++) {
506                         pExceeded= ((strip->prev) && (strip->prev->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h1[0] < strip->prev->end));
507                         nExceeded= ((strip->next) && (strip->next->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h2[0] > strip->next->start));
508                         
509                         if ((pExceeded && nExceeded) || (iter == 4) ) {
510                                 /* both endpoints exceeded (or iteration ping-pong'd meaning that we need a compromise)
511                                  *      - simply crop strip to fit within the bounds of the strips bounding it
512                                  *      - if there were no neighbours, clear the transforms (make it default to the strip's current values)
513                                  */
514                                 if (strip->prev && strip->next) {
515                                         tdn->h1[0]= strip->prev->end;
516                                         tdn->h2[0]= strip->next->start;
517                                 }
518                                 else {
519                                         tdn->h1[0]= strip->start;
520                                         tdn->h2[0]= strip->end;
521                                 }
522                         }
523                         else if (nExceeded) {
524                                 /* move backwards */
525                                 float offset= tdn->h2[0] - strip->next->start;
526                                 
527                                 tdn->h1[0] -= offset;
528                                 tdn->h2[0] -= offset;
529                         }
530                         else if (pExceeded) {
531                                 /* more forwards */
532                                 float offset= strip->prev->end - tdn->h1[0];
533                                 
534                                 tdn->h1[0] += offset;
535                                 tdn->h2[0] += offset;
536                         }
537                         else /* all is fine and well */
538                                 break;
539                 }
540                 
541                 /* handle auto-snapping */
542                 switch (snla->autosnap) {
543                         case SACTSNAP_FRAME: /* snap to nearest frame/time  */
544                                 if (snla->flag & SNLA_DRAWTIME) {
545                                         tdn->h1[0]= (float)( floor((tdn->h1[0]/secf) + 0.5f) * secf );
546                                         tdn->h2[0]= (float)( floor((tdn->h2[0]/secf) + 0.5f) * secf );
547                                 }
548                                 else {
549                                         tdn->h1[0]= (float)( floor(tdn->h1[0]+0.5f) );
550                                         tdn->h2[0]= (float)( floor(tdn->h2[0]+0.5f) );
551                                 }
552                                 break;
553                         
554                         case SACTSNAP_MARKER: /* snap to nearest marker */
555                                 tdn->h1[0]= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h1[0]);
556                                 tdn->h2[0]= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h2[0]);
557                                 break;
558                 }
559                 
560                 /* use RNA to write the values... */
561                 // TODO: do we need to write in 2 passes to make sure that no truncation goes on?
562                 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
563                 
564                 RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
565                 RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
566                 
567                 /* flush transforms to child strips (since this should be a meta) */
568                 BKE_nlameta_flush_transforms(strip);
569                 
570                 
571                 /* now, check if we need to try and move track
572                  *      - we need to calculate both, as only one may have been altered by transform if only 1 handle moved
573                  */
574                 delta_y1= ((int)tdn->h1[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
575                 delta_y2= ((int)tdn->h2[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
576                 
577                 if (delta_y1 || delta_y2) {
578                         NlaTrack *track;
579                         int delta = (delta_y2) ? delta_y2 : delta_y1;
580                         int n;
581                         
582                         /* move in the requested direction, checking at each layer if there's space for strip to pass through,
583                          * stopping on the last track available or that we're able to fit in
584                          */
585                         if (delta > 0) {
586                                 for (track=tdn->nlt->next, n=0; (track) && (n < delta); track=track->next, n++) {
587                                         /* check if space in this track for the strip */
588                                         if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
589                                                 /* move strip to this track */
590                                                 BLI_remlink(&tdn->nlt->strips, strip);
591                                                 BKE_nlatrack_add_strip(track, strip);
592                                                 
593                                                 tdn->nlt= track;
594                                                 tdn->trackIndex++;
595                                         }
596                                         else /* can't move any further */
597                                                 break;
598                                 }
599                         }
600                         else {
601                                 /* make delta 'positive' before using it, since we now know to go backwards */
602                                 delta= -delta;
603                                 
604                                 for (track=tdn->nlt->prev, n=0; (track) && (n < delta); track=track->prev, n++) {
605                                         /* check if space in this track for the strip */
606                                         if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
607                                                 /* move strip to this track */
608                                                 BLI_remlink(&tdn->nlt->strips, strip);
609                                                 BKE_nlatrack_add_strip(track, strip);
610                                                 
611                                                 tdn->nlt= track;
612                                                 tdn->trackIndex--;
613                                         }
614                                         else /* can't move any further */
615                                                 break;
616                                 }
617                         }
618                 }
619         }
620 }
621
622 /* helper for recalcData() - for Image Editor transforms */
623 static void recalcData_image(TransInfo *t)
624 {
625         if (t->obedit && t->obedit->type == OB_MESH) {
626                 SpaceImage *sima= t->sa->spacedata.first;
627                 
628                 flushTransUVs(t);
629                 if(sima->flag & SI_LIVE_UNWRAP)
630                         ED_uvedit_live_unwrap_re_solve();
631                 
632                 DAG_id_tag_update(t->obedit->data, 0);
633         }
634 }
635
636 /* helper for recalcData() - for Movie Clip transforms */
637 static void recalcData_clip(TransInfo *t)
638 {
639         SpaceClip *sc= t->sa->spacedata.first;
640         MovieClip *clip= ED_space_clip(sc);
641         MovieTrackingTrack *track;
642         
643         if(t->state == TRANS_CANCEL) {
644                 track= clip->tracking.tracks.first;
645                 while(track) {
646                         if(TRACK_VIEW_SELECTED(sc, track)) {
647                                 MovieTrackingMarker *marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
648                                 
649                                 marker->flag= track->transflag;
650                         }
651                         
652                         track= track->next;
653                 }
654         }
655         
656         flushTransTracking(t);
657         
658         track= clip->tracking.tracks.first;
659         while(track) {
660                 if(TRACK_VIEW_SELECTED(sc, track)) {
661                         if (t->mode == TFM_TRANSLATION) {
662                                 if(TRACK_AREA_SELECTED(track, TRACK_AREA_PAT))
663                                         BKE_tracking_clamp_track(track, CLAMP_PAT_POS);
664                                 if(TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH))
665                                         BKE_tracking_clamp_track(track, CLAMP_SEARCH_POS);
666                         }
667                         else if (t->mode == TFM_RESIZE) {
668                                 if(TRACK_AREA_SELECTED(track, TRACK_AREA_PAT))
669                                         BKE_tracking_clamp_track(track, CLAMP_PAT_DIM);
670                                 if(TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH))
671                                         BKE_tracking_clamp_track(track, CLAMP_SEARCH_DIM);
672                         }
673                 }
674                 
675                 track= track->next;
676         }
677         
678         DAG_id_tag_update(&clip->id, 0);
679 }
680
681 /* helper for recalcData() - for 3d-view transforms */
682 static void recalcData_view3d(TransInfo *t)
683 {
684         Base *base = t->scene->basact;
685         
686         if (t->obedit) {
687                 if ELEM(t->obedit->type, OB_CURVE, OB_SURF) {
688                         Curve *cu= t->obedit->data;
689                         ListBase *nurbs= curve_editnurbs(cu);
690                         Nurb *nu= nurbs->first;
691                         
692                         if(t->state != TRANS_CANCEL) {
693                                 clipMirrorModifier(t, t->obedit);
694                                 applyProject(t);
695                         }
696                         
697                         DAG_id_tag_update(t->obedit->data, 0);  /* sets recalc flags */
698                                 
699                         if (t->state == TRANS_CANCEL) {
700                                 while(nu) {
701                                         calchandlesNurb(nu); /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
702                                         nu= nu->next;
703                                 }
704
705                         } 
706                         else {
707                                 /* Normal updating */
708                                 while(nu) {
709                                         test2DNurb(nu);
710                                         calchandlesNurb(nu);
711                                         nu= nu->next;
712                                 }
713                         }
714                 }
715                 else if(t->obedit->type==OB_LATTICE) {
716                         Lattice *la= t->obedit->data;
717                         
718                         if(t->state != TRANS_CANCEL) {
719                                 applyProject(t);
720                         }
721                         
722                         DAG_id_tag_update(t->obedit->data, 0);  /* sets recalc flags */
723                         
724                         if(la->editlatt->latt->flag & LT_OUTSIDE) outside_lattice(la->editlatt->latt);
725                 }
726                 else if (t->obedit->type == OB_MESH) {
727                         BMEditMesh *em = ((Mesh*)t->obedit->data)->edit_btmesh;
728                         /* mirror modifier clipping? */
729                         if(t->state != TRANS_CANCEL) {
730                                 /* apply clipping after so we never project past the clip plane [#25423] */
731                                 applyProject(t);
732                                 clipMirrorModifier(t, t->obedit);
733                         }
734                         if((t->options & CTX_NO_MIRROR) == 0 && (t->flag & T_MIRROR))
735                                 editbmesh_apply_to_mirror(t);
736                                 
737                         DAG_id_tag_update(t->obedit->data, 0);  /* sets recalc flags */
738                         
739                         EDBM_RecalcNormals(em);
740                         BMEdit_RecalcTesselation(em);
741                 }
742                 else if(t->obedit->type==OB_ARMATURE) { /* no recalc flag, does pose */
743                         bArmature *arm= t->obedit->data;
744                         ListBase *edbo = arm->edbo;
745                         EditBone *ebo;
746                         TransData *td = t->data;
747                         int i;
748                         
749                         if(t->state != TRANS_CANCEL) {
750                                 applyProject(t);
751                         }
752                         
753                         /* Ensure all bones are correctly adjusted */
754                         for (ebo = edbo->first; ebo; ebo = ebo->next){
755                                 
756                                 if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
757                                         /* If this bone has a parent tip that has been moved */
758                                         if (ebo->parent->flag & BONE_TIPSEL){
759                                                 copy_v3_v3 (ebo->head, ebo->parent->tail);
760                                                 if(t->mode==TFM_BONE_ENVELOPE) ebo->rad_head= ebo->parent->rad_tail;
761                                         }
762                                         /* If this bone has a parent tip that has NOT been moved */
763                                         else{
764                                                 copy_v3_v3 (ebo->parent->tail, ebo->head);
765                                                 if(t->mode==TFM_BONE_ENVELOPE) ebo->parent->rad_tail= ebo->rad_head;
766                                         }
767                                 }
768                                 
769                                 /* on extrude bones, oldlength==0.0f, so we scale radius of points */
770                                 ebo->length= len_v3v3(ebo->head, ebo->tail);
771                                 if(ebo->oldlength==0.0f) {
772                                         ebo->rad_head= 0.25f*ebo->length;
773                                         ebo->rad_tail= 0.10f*ebo->length;
774                                         ebo->dist= 0.25f*ebo->length;
775                                         if(ebo->parent) {
776                                                 if(ebo->rad_head > ebo->parent->rad_tail)
777                                                         ebo->rad_head= ebo->parent->rad_tail;
778                                         }
779                                 }
780                                 else if(t->mode!=TFM_BONE_ENVELOPE) {
781                                         /* if bones change length, lets do that for the deform distance as well */
782                                         ebo->dist*= ebo->length/ebo->oldlength;
783                                         ebo->rad_head*= ebo->length/ebo->oldlength;
784                                         ebo->rad_tail*= ebo->length/ebo->oldlength;
785                                         ebo->oldlength= ebo->length;
786                                 }
787                         }
788                         
789                         
790                         if (t->mode != TFM_BONE_ROLL)
791                         {
792                                 /* fix roll */
793                                 for(i = 0; i < t->total; i++, td++)
794                                 {
795                                         if (td->extra)
796                                         {
797                                                 float vec[3], up_axis[3];
798                                                 float qrot[4];
799                                                 
800                                                 ebo = td->extra;
801                                                 copy_v3_v3(up_axis, td->axismtx[2]);
802                                                 
803                                                 if (t->mode != TFM_ROTATION)
804                                                 {
805                                                         sub_v3_v3v3(vec, ebo->tail, ebo->head);
806                                                         normalize_v3(vec);
807                                                         rotation_between_vecs_to_quat(qrot, td->axismtx[1], vec);
808                                                         mul_qt_v3(qrot, up_axis);
809                                                 }
810                                                 else
811                                                 {
812                                                         mul_m3_v3(t->mat, up_axis);
813                                                 }
814                                                 
815                                                 ebo->roll = ED_rollBoneToVector(ebo, up_axis, FALSE);
816                                         }
817                                 }
818                         }
819                         
820                         if(arm->flag & ARM_MIRROR_EDIT)
821                                 transform_armature_mirror_update(t->obedit);
822                         
823                 }
824                 else
825                 {
826                         if(t->state != TRANS_CANCEL) {
827                                 applyProject(t);
828                         }
829                         DAG_id_tag_update(t->obedit->data, 0);  /* sets recalc flags */
830                 }
831         }
832         else if( (t->flag & T_POSE) && t->poseobj) {
833                 Object *ob= t->poseobj;
834                 bArmature *arm= ob->data;
835                 
836                 /* if animtimer is running, and the object already has animation data,
837                  * check if the auto-record feature means that we should record 'samples'
838                  * (i.e. uneditable animation values)
839                  *
840                  * context is needed for keying set poll() functions.
841                  */
842                 // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
843                 if ((t->animtimer) && (t->context) && IS_AUTOKEY_ON(t->scene)) {
844                         int targetless_ik= (t->flag & T_AUTOIK); // XXX this currently doesn't work, since flags aren't set yet!
845                         
846                         animrecord_check_state(t->scene, &ob->id, t->animtimer);
847                         autokeyframe_pose_cb_func(t->context, t->scene, (View3D *)t->view, ob, t->mode, targetless_ik);
848                 }
849                 
850                 /* old optimize trick... this enforces to bypass the depgraph */
851                 if (!(arm->flag & ARM_DELAYDEFORM)) {
852                         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);  /* sets recalc flags */
853                 }
854                 else
855                         where_is_pose(t->scene, ob);
856         }
857         else if(base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, base->object)) {
858                 if(t->state != TRANS_CANCEL) {
859                         applyProject(t);
860                 }
861                 flushTransParticles(t);
862         }
863         else {
864                 int i;
865                 
866                 if(t->state != TRANS_CANCEL) {
867                         applyProject(t);
868                 }
869                 
870                 for (i = 0; i < t->total; i++) {
871                         TransData *td = t->data + i;
872                         Object *ob = td->ob;
873                         
874                         if (td->flag & TD_NOACTION)
875                                 break;
876                         
877                         if (td->flag & TD_SKIP)
878                                 continue;
879                         
880                         /* if animtimer is running, and the object already has animation data,
881                          * check if the auto-record feature means that we should record 'samples'
882                          * (i.e. uneditable animation values)
883                          */
884                         // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
885                         if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
886                                 animrecord_check_state(t->scene, &ob->id, t->animtimer);
887                                 autokeyframe_ob_cb_func(t->context, t->scene, (View3D *)t->view, ob, t->mode);
888                         }
889                         
890                         /* sets recalc flags fully, instead of flushing existing ones 
891                          * otherwise proxies don't function correctly
892                          */
893                         DAG_id_tag_update(&ob->id, OB_RECALC_OB);
894                 }
895         }
896 }
897
898 /* called for updating while transform acts, once per redraw */
899 void recalcData(TransInfo *t)
900 {
901         if (t->spacetype==SPACE_NODE) {
902                 flushTransNodes(t);
903         }
904         else if (t->spacetype==SPACE_SEQ) {
905                 flushTransSeq(t);
906         }
907         else if (t->spacetype == SPACE_ACTION) {
908                 recalcData_actedit(t);
909         }
910         else if (t->spacetype == SPACE_IPO) {
911                 recalcData_graphedit(t);
912         }
913         else if (t->spacetype == SPACE_NLA) {
914                 recalcData_nla(t);
915         }
916         else if (t->spacetype == SPACE_IMAGE) {
917                 recalcData_image(t);
918         }
919         else if (t->spacetype == SPACE_VIEW3D) {
920                 recalcData_view3d(t);
921         }
922         else if (t->spacetype == SPACE_CLIP) {
923                 recalcData_clip(t);
924         }
925 }
926
927 void drawLine(TransInfo *t, float *center, float *dir, char axis, short options)
928 {
929         float v1[3], v2[3], v3[3];
930         unsigned char col[3], col2[3];
931
932         if (t->spacetype == SPACE_VIEW3D)
933         {
934                 View3D *v3d = t->view;
935                 
936                 glPushMatrix();
937                 
938                 //if(t->obedit) glLoadMatrixf(t->obedit->obmat);        // sets opengl viewing
939                 
940                 
941                 copy_v3_v3(v3, dir);
942                 mul_v3_fl(v3, v3d->far);
943                 
944                 sub_v3_v3v3(v2, center, v3);
945                 add_v3_v3v3(v1, center, v3);
946                 
947                 if (options & DRAWLIGHT) {
948                         col[0] = col[1] = col[2] = 220;
949                 }
950                 else {
951                         UI_GetThemeColor3ubv(TH_GRID, col);
952                 }
953                 UI_make_axis_color(col, col2, axis);
954                 glColor3ubv(col2);
955                 
956                 setlinestyle(0);
957                 glBegin(GL_LINE_STRIP);
958                         glVertex3fv(v1);
959                         glVertex3fv(v2);
960                 glEnd();
961                 
962                 glPopMatrix();
963         }
964 }
965
966 void resetTransRestrictions(TransInfo *t)
967 {
968         t->flag &= ~T_ALL_RESTRICTIONS;
969 }
970
971 /* the *op can be NULL */
972 int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
973 {
974         Scene *sce = CTX_data_scene(C);
975         ToolSettings *ts = CTX_data_tool_settings(C);
976         ARegion *ar = CTX_wm_region(C);
977         ScrArea *sa = CTX_wm_area(C);
978         Object *obedit = CTX_data_edit_object(C);
979         
980         /* moving: is shown in drawobject() (transform color) */
981 //  TRANSFORM_FIX_ME
982 //      if(obedit || (t->flag & T_POSE) ) G.moving= G_TRANSFORM_EDIT;
983 //      else if(G.f & G_PARTICLEEDIT) G.moving= G_TRANSFORM_PARTICLE;
984 //      else G.moving= G_TRANSFORM_OBJ;
985         
986         t->scene = sce;
987         t->sa = sa;
988         t->ar = ar;
989         t->obedit = obedit;
990         t->settings = ts;
991         
992         t->data = NULL;
993         t->ext = NULL;
994         
995         t->helpline = HLP_NONE;
996         
997         t->flag = 0;
998         
999         t->redraw = 1; /* redraw first time */
1000         
1001         if (event)
1002         {
1003                 copy_v2_v2_int(t->imval, event->mval);
1004                 t->event_type = event->type;
1005         }
1006         else
1007         {
1008                 t->imval[0] = 0;
1009                 t->imval[1] = 0;
1010         }
1011         
1012         t->con.imval[0] = t->imval[0];
1013         t->con.imval[1] = t->imval[1];
1014         
1015         t->mval[0] = t->imval[0];
1016         t->mval[1] = t->imval[1];
1017         
1018         t->transform            = NULL;
1019         t->handleEvent          = NULL;
1020         
1021         t->total                        = 0;
1022         
1023         t->val = 0.0f;
1024         
1025         t->vec[0]                       =
1026                 t->vec[1]               =
1027                 t->vec[2]               = 0.0f;
1028         
1029         t->center[0]            =
1030                 t->center[1]    =
1031                 t->center[2]    = 0.0f;
1032         
1033         unit_m3(t->mat);
1034         
1035         /* if there's an event, we're modal */
1036         if (event) {
1037                 t->flag |= T_MODAL;
1038         }
1039
1040         /* Crease needs edge flag */
1041         if (t->mode == TFM_CREASE) {
1042                 t->options |= CTX_EDGE;
1043         }
1044
1045
1046         /* Assign the space type, some exceptions for running in different mode */
1047         if(sa == NULL) {
1048                 /* background mode */
1049                 t->spacetype= SPACE_EMPTY;
1050         }
1051         else if ((ar == NULL) && (sa->spacetype == SPACE_VIEW3D)) {
1052                 /* running in the text editor */
1053                 t->spacetype= SPACE_EMPTY;
1054         }
1055         else {
1056                 /* normal operation */
1057                 t->spacetype= sa->spacetype;
1058         }
1059
1060
1061         if(t->spacetype == SPACE_VIEW3D)
1062         {
1063                 View3D *v3d = sa->spacedata.first;
1064                 
1065                 t->view = v3d;
1066                 t->animtimer= CTX_wm_screen(C)->animtimer;
1067                 
1068                 /* turn manipulator off during transform */
1069                 // FIXME: but don't do this when USING the manipulator...
1070                 if (t->flag & T_MODAL) {
1071                         t->twtype = v3d->twtype;
1072                         v3d->twtype = 0;
1073                 }
1074
1075                 if(v3d->flag & V3D_ALIGN) t->flag |= T_V3D_ALIGN;
1076                 t->around = v3d->around;
1077                 
1078                 if (op && RNA_struct_find_property(op->ptr, "constraint_orientation") && RNA_property_is_set(op->ptr, "constraint_orientation"))
1079                 {
1080                         t->current_orientation = RNA_enum_get(op->ptr, "constraint_orientation");
1081                         
1082                         if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C))
1083                         {
1084                                 t->current_orientation = V3D_MANIP_GLOBAL;
1085                         }
1086                 }
1087                 else
1088                 {
1089                         t->current_orientation = v3d->twmode;
1090                 }
1091
1092                 /* exceptional case */
1093                 if(t->around==V3D_LOCAL && (t->settings->selectmode & SCE_SELECT_FACE)) {
1094                         if(ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
1095                                 t->options |= CTX_NO_PET;
1096                         }
1097                 }
1098
1099                 /* initialize UV transform from */
1100                 if (op && RNA_struct_find_property(op->ptr, "correct_uv")) {
1101                         if(RNA_property_is_set(op->ptr, "correct_uv")) {
1102                                 if(RNA_boolean_get(op->ptr, "correct_uv")) {
1103                                         t->settings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT;
1104                                 }
1105                                 else {
1106                                         t->settings->uvcalc_flag &= ~UVCALC_TRANSFORM_CORRECT;
1107                                 }
1108                         }
1109                         else {
1110                                 RNA_boolean_set(op->ptr, "correct_uv", t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT);
1111                         }
1112                 }
1113
1114         }
1115         else if(t->spacetype==SPACE_IMAGE)
1116         {
1117                 SpaceImage *sima = sa->spacedata.first;
1118                 // XXX for now, get View2D from the active region
1119                 t->view = &ar->v2d;
1120                 t->around = sima->around;
1121         }
1122         else if(t->spacetype==SPACE_NODE)
1123         {
1124                 // XXX for now, get View2D from the active region
1125                 t->view = &ar->v2d;
1126                 t->around = V3D_CENTER;
1127         }
1128         else if(t->spacetype==SPACE_IPO) 
1129         {
1130                 SpaceIpo *sipo= sa->spacedata.first;
1131                 t->view = &ar->v2d;
1132                 t->around = sipo->around;
1133         }
1134         else
1135         {
1136                 if(ar) {
1137                         // XXX for now, get View2D  from the active region
1138                         t->view = &ar->v2d;
1139                         // XXX for now, the center point is the midpoint of the data
1140                 }
1141                 else {
1142                         t->view= NULL;
1143                 }
1144                 t->around = V3D_CENTER;
1145         }
1146         
1147         if (op && RNA_property_is_set(op->ptr, "release_confirm"))
1148         {
1149                 if (RNA_boolean_get(op->ptr, "release_confirm"))
1150                 {
1151                         t->flag |= T_RELEASE_CONFIRM;
1152                 }
1153         }
1154         else
1155         {
1156                 if (U.flag & USER_RELEASECONFIRM)
1157                 {
1158                         t->flag |= T_RELEASE_CONFIRM;
1159                 }
1160         }
1161
1162         if (op && RNA_struct_find_property(op->ptr, "mirror") && RNA_property_is_set(op->ptr, "mirror"))
1163         {
1164                 if (RNA_boolean_get(op->ptr, "mirror"))
1165                 {
1166                         t->flag |= T_MIRROR;
1167                         t->mirror = 1;
1168                 }
1169         }
1170         // Need stuff to take it from edit mesh or whatnot here
1171         else if (t->spacetype == SPACE_VIEW3D)
1172         {
1173                 if (t->obedit && t->obedit->type == OB_MESH && (((Mesh *)t->obedit->data)->editflag & ME_EDIT_MIRROR_X))
1174                 {
1175                         t->flag |= T_MIRROR;
1176                         t->mirror = 1;
1177                 }
1178         }
1179         
1180         /* setting PET flag only if property exist in operator. Otherwise, assume it's not supported */
1181         if (op && RNA_struct_find_property(op->ptr, "proportional"))
1182         {
1183                 if (RNA_property_is_set(op->ptr, "proportional"))
1184                 {
1185                         switch(RNA_enum_get(op->ptr, "proportional"))
1186                         {
1187                         case PROP_EDIT_CONNECTED:
1188                                 t->flag |= T_PROP_CONNECTED;
1189                         case PROP_EDIT_ON:
1190                                 t->flag |= T_PROP_EDIT;
1191                                 break;
1192                         }
1193                 }
1194                 else
1195                 {
1196                         /* use settings from scene only if modal */
1197                         if (t->flag & T_MODAL)
1198                         {
1199                                 if ((t->options & CTX_NO_PET) == 0)
1200                                 {
1201                                         if (t->obedit && ts->proportional != PROP_EDIT_OFF)
1202                                         {
1203                                                 t->flag |= T_PROP_EDIT;
1204
1205                                                 if(ts->proportional == PROP_EDIT_CONNECTED)
1206                                                         t->flag |= T_PROP_CONNECTED;
1207                                         }
1208                                         else if (t->obedit == NULL && ts->proportional_objects)
1209                                         {
1210                                                 t->flag |= T_PROP_EDIT;
1211                                         }
1212                                 }
1213                         }
1214                 }
1215                 
1216                 if (op && RNA_struct_find_property(op->ptr, "proportional_size") && RNA_property_is_set(op->ptr, "proportional_size"))
1217                 {
1218                         t->prop_size = RNA_float_get(op->ptr, "proportional_size");
1219                 }
1220                 else
1221                 {
1222                         t->prop_size = ts->proportional_size;
1223                 }
1224                 
1225                 
1226                 /* TRANSFORM_FIX_ME rna restrictions */
1227                 if (t->prop_size <= 0.00001f)
1228                 {
1229                         printf("Proportional size (%f) under 0.00001, reseting to 1!\n", t->prop_size);
1230                         t->prop_size = 1.0f;
1231                 }
1232                 
1233                 if (op && RNA_struct_find_property(op->ptr, "proportional_edit_falloff") && RNA_property_is_set(op->ptr, "proportional_edit_falloff"))
1234                 {
1235                         t->prop_mode = RNA_enum_get(op->ptr, "proportional_edit_falloff");
1236                 }
1237                 else
1238                 {
1239                         t->prop_mode = ts->prop_mode;
1240                 }
1241         }
1242         else /* add not pet option to context when not available */
1243         {
1244                 t->options |= CTX_NO_PET;
1245         }
1246         
1247         // Mirror is not supported with PET, turn it off.
1248         if (t->flag & T_PROP_EDIT)
1249         {
1250                 t->flag &= ~T_MIRROR;
1251         }
1252
1253         setTransformViewMatrices(t);
1254         initNumInput(&t->num);
1255         
1256         return 1;
1257 }
1258
1259 /* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
1260 void postTrans (bContext *C, TransInfo *t)
1261 {
1262         TransData *td;
1263         
1264         if (t->draw_handle_view)
1265                 ED_region_draw_cb_exit(t->ar->type, t->draw_handle_view);
1266         if (t->draw_handle_apply)
1267                 ED_region_draw_cb_exit(t->ar->type, t->draw_handle_apply);
1268         if (t->draw_handle_pixel)
1269                 ED_region_draw_cb_exit(t->ar->type, t->draw_handle_pixel);
1270         if (t->draw_handle_cursor)
1271                 WM_paint_cursor_end(CTX_wm_manager(C), t->draw_handle_cursor);
1272
1273         if (t->customFree) {
1274                 /* Can take over freeing t->data and data2d etc... */
1275                 t->customFree(t);
1276         }
1277         else if (t->customData) {
1278                 MEM_freeN(t->customData);
1279         }
1280
1281         /* postTrans can be called when nothing is selected, so data is NULL already */
1282         if (t->data) {
1283                 int a;
1284                 
1285                 /* free data malloced per trans-data */
1286                 for(a=0, td= t->data; a<t->total; a++, td++) {
1287                         if (td->flag & TD_BEZTRIPLE) 
1288                                 MEM_freeN(td->hdata);
1289                 }
1290                 MEM_freeN(t->data);
1291         }
1292         
1293         BLI_freelistN(&t->tsnap.points);
1294
1295         if (t->ext) MEM_freeN(t->ext);
1296         if (t->data2d) {
1297                 MEM_freeN(t->data2d);
1298                 t->data2d= NULL;
1299         }
1300         
1301         if(t->spacetype==SPACE_IMAGE) {
1302                 SpaceImage *sima= t->sa->spacedata.first;
1303                 if(sima->flag & SI_LIVE_UNWRAP)
1304                         ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL);
1305         }
1306         else if(t->spacetype==SPACE_VIEW3D) {
1307                 View3D *v3d = t->sa->spacedata.first;
1308                 /* restore manipulator */
1309                 if (t->flag & T_MODAL) {
1310                         v3d->twtype = t->twtype;
1311                 }
1312         }
1313         
1314         if (t->mouse.data)
1315         {
1316                 MEM_freeN(t->mouse.data);
1317         }
1318 }
1319
1320 void applyTransObjects(TransInfo *t)
1321 {
1322         TransData *td;
1323         
1324         for (td = t->data; td < t->data + t->total; td++) {
1325                 copy_v3_v3(td->iloc, td->loc);
1326                 if (td->ext->rot) {
1327                         copy_v3_v3(td->ext->irot, td->ext->rot);
1328                 }
1329                 if (td->ext->size) {
1330                         copy_v3_v3(td->ext->isize, td->ext->size);
1331                 }
1332         }
1333         recalcData(t);
1334 }
1335
1336 static void restoreElement(TransData *td)
1337 {
1338         /* TransData for crease has no loc */
1339         if (td->loc) {
1340                 copy_v3_v3(td->loc, td->iloc);
1341         }
1342         if (td->val) {
1343                 *td->val = td->ival;
1344         }
1345
1346         if (td->ext && (td->flag&TD_NO_EXT)==0) {
1347                 if (td->ext->rot) {
1348                         copy_v3_v3(td->ext->rot, td->ext->irot);
1349                 }
1350                 if(td->ext->rotAngle) {
1351                         *td->ext->rotAngle= td->ext->irotAngle;
1352                 }
1353                 if(td->ext->rotAxis) {
1354                         copy_v3_v3(td->ext->rotAxis, td->ext->irotAxis);
1355                 }
1356                 /* XXX, drotAngle & drotAxis not used yet */
1357                 if (td->ext->size) {
1358                         copy_v3_v3(td->ext->size, td->ext->isize);
1359                 }
1360                 if (td->ext->quat) {
1361                         copy_qt_qt(td->ext->quat, td->ext->iquat);
1362                 }
1363         }
1364         
1365         if (td->flag & TD_BEZTRIPLE) {
1366                 *(td->hdata->h1) = td->hdata->ih1;
1367                 *(td->hdata->h2) = td->hdata->ih2;
1368         }
1369 }
1370
1371 void restoreTransObjects(TransInfo *t)
1372 {
1373         TransData *td;
1374         TransData2D *td2d;
1375
1376         for (td = t->data; td < t->data + t->total; td++) {
1377                 restoreElement(td);
1378         }
1379         
1380         for (td2d=t->data2d; t->data2d && td2d < t->data2d + t->total; td2d++) {
1381                 if (td2d->h1) {
1382                         td2d->h1[0] = td2d->ih1[0];
1383                         td2d->h1[1] = td2d->ih1[1];
1384                 }
1385                 if (td2d->h2) {
1386                         td2d->h2[0] = td2d->ih2[0];
1387                         td2d->h2[1] = td2d->ih2[1];
1388                 }
1389         }
1390
1391         unit_m3(t->mat);
1392         
1393         recalcData(t);
1394 }
1395
1396 void calculateCenter2D(TransInfo *t)
1397 {
1398         if (t->flag & (T_EDIT|T_POSE)) {
1399                 Object *ob= t->obedit?t->obedit:t->poseobj;
1400                 float vec[3];
1401                 
1402                 copy_v3_v3(vec, t->center);
1403                 mul_m4_v3(ob->obmat, vec);
1404                 projectIntView(t, vec, t->center2d);
1405         }
1406         else {
1407                 projectIntView(t, t->center, t->center2d);
1408         }
1409 }
1410
1411 void calculateCenterCursor(TransInfo *t)
1412 {
1413         float *cursor;
1414         
1415         cursor = give_cursor(t->scene, t->view);
1416         copy_v3_v3(t->center, cursor);
1417         
1418         /* If edit or pose mode, move cursor in local space */
1419         if (t->flag & (T_EDIT|T_POSE)) {
1420                 Object *ob = t->obedit?t->obedit:t->poseobj;
1421                 float mat[3][3], imat[3][3];
1422                 
1423                 sub_v3_v3v3(t->center, t->center, ob->obmat[3]);
1424                 copy_m3_m4(mat, ob->obmat);
1425                 invert_m3_m3(imat, mat);
1426                 mul_m3_v3(imat, t->center);
1427         }
1428         
1429         calculateCenter2D(t);
1430 }
1431
1432 void calculateCenterCursor2D(TransInfo *t)
1433 {
1434         float aspx=1.0, aspy=1.0;
1435         float *cursor= NULL;
1436         
1437         if(t->spacetype==SPACE_IMAGE) {
1438                 SpaceImage *sima= (SpaceImage *)t->sa->spacedata.first;
1439                 /* only space supported right now but may change */
1440                 ED_space_image_uv_aspect(sima, &aspx, &aspy);
1441                 cursor = sima->cursor;
1442         }
1443         
1444         if (cursor) {
1445                 t->center[0] = cursor[0] * aspx;
1446                 t->center[1] = cursor[1] * aspy;
1447         }
1448         
1449         calculateCenter2D(t);
1450 }
1451
1452 static void calculateCenterCursorGraph2D(TransInfo *t)
1453 {
1454         SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first;
1455         Scene *scene= t->scene;
1456         
1457         /* cursor is combination of current frame, and graph-editor cursor value */
1458         t->center[0]= (float)(scene->r.cfra);
1459         t->center[1]= sipo->cursorVal;
1460         
1461         calculateCenter2D(t);
1462 }
1463
1464 void calculateCenterMedian(TransInfo *t)
1465 {
1466         float partial[3] = {0.0f, 0.0f, 0.0f};
1467         int total = 0;
1468         int i;
1469         
1470         for(i = 0; i < t->total; i++) {
1471                 if (t->data[i].flag & TD_SELECTED) {
1472                         if (!(t->data[i].flag & TD_NOCENTER))
1473                         {
1474                                 add_v3_v3(partial, t->data[i].center);
1475                                 total++;
1476                         }
1477                 }
1478                 else {
1479                         /*
1480                            All the selected elements are at the head of the array
1481                            which means we can stop when it finds unselected data
1482                         */
1483                         break;
1484                 }
1485         }
1486         if(i)
1487                 mul_v3_fl(partial, 1.0f / total);
1488         copy_v3_v3(t->center, partial);
1489         
1490         calculateCenter2D(t);
1491 }
1492
1493 void calculateCenterBound(TransInfo *t)
1494 {
1495         float max[3];
1496         float min[3];
1497         int i;
1498         for(i = 0; i < t->total; i++) {
1499                 if (i) {
1500                         if (t->data[i].flag & TD_SELECTED) {
1501                                 if (!(t->data[i].flag & TD_NOCENTER))
1502                                         minmax_v3v3_v3(min, max, t->data[i].center);
1503                         }
1504                         else {
1505                                 /*
1506                                    All the selected elements are at the head of the array
1507                                    which means we can stop when it finds unselected data
1508                                 */
1509                                 break;
1510                         }
1511                 }
1512                 else {
1513                         copy_v3_v3(max, t->data[i].center);
1514                         copy_v3_v3(min, t->data[i].center);
1515                 }
1516         }
1517         add_v3_v3v3(t->center, min, max);
1518         mul_v3_fl(t->center, 0.5);
1519         
1520         calculateCenter2D(t);
1521 }
1522
1523 void calculateCenter(TransInfo *t)
1524 {
1525         switch(t->around) {
1526         case V3D_CENTER:
1527                 calculateCenterBound(t);
1528                 break;
1529         case V3D_CENTROID:
1530                 calculateCenterMedian(t);
1531                 break;
1532         case V3D_CURSOR:
1533                 if(t->spacetype==SPACE_IMAGE)
1534                         calculateCenterCursor2D(t);
1535                 else if(t->spacetype==SPACE_IPO)
1536                         calculateCenterCursorGraph2D(t);
1537                 else
1538                         calculateCenterCursor(t);
1539                 break;
1540         case V3D_LOCAL:
1541                 /* Individual element center uses median center for helpline and such */
1542                 calculateCenterMedian(t);
1543                 break;
1544         case V3D_ACTIVE:
1545                 {
1546                 /* set median, and if if if... do object center */
1547                 
1548                 /* EDIT MODE ACTIVE EDITMODE ELEMENT */
1549
1550                 if (t->obedit && t->obedit->type == OB_MESH) {
1551                         BMEditSelection ese;
1552                         BMEditMesh *em = ((Mesh*)t->obedit->data)->edit_btmesh;
1553                         
1554                         if (EDBM_get_actSelection(em, &ese)) {
1555                         EDBM_editselection_center(em, t->center, &ese);
1556                         calculateCenter2D(t);
1557                         break;
1558                         }
1559                 } /* END EDIT MODE ACTIVE ELEMENT */
1560                 
1561                 calculateCenterMedian(t);
1562                 if((t->flag & (T_EDIT|T_POSE))==0)
1563                 {
1564                         Scene *scene = t->scene;
1565                         Object *ob= OBACT;
1566                         if(ob)
1567                         {
1568                                 copy_v3_v3(t->center, ob->obmat[3]);
1569                                 projectIntView(t, t->center, t->center2d);
1570                         }
1571                 }
1572                 
1573                 }
1574         }
1575         
1576         /* setting constraint center */
1577         copy_v3_v3(t->con.center, t->center);
1578         if(t->flag & (T_EDIT|T_POSE))
1579         {
1580                 Object *ob= t->obedit?t->obedit:t->poseobj;
1581                 mul_m4_v3(ob->obmat, t->con.center);
1582         }
1583         
1584         /* for panning from cameraview */
1585         if(t->flag & T_OBJECT)
1586         {
1587                 if(t->spacetype==SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW)
1588                 {
1589                         View3D *v3d = t->view;
1590                         Scene *scene = t->scene;
1591                         RegionView3D *rv3d = t->ar->regiondata;
1592                         
1593                         if(v3d->camera == OBACT && rv3d->persp==RV3D_CAMOB)
1594                         {
1595                                 float axis[3];
1596                                 /* persinv is nasty, use viewinv instead, always right */
1597                                 copy_v3_v3(axis, t->viewinv[2]);
1598                                 normalize_v3(axis);
1599                                 
1600                                 /* 6.0 = 6 grid units */
1601                                 axis[0]= t->center[0]- 6.0f*axis[0];
1602                                 axis[1]= t->center[1]- 6.0f*axis[1];
1603                                 axis[2]= t->center[2]- 6.0f*axis[2];
1604                                 
1605                                 projectIntView(t, axis, t->center2d);
1606                                 
1607                                 /* rotate only needs correct 2d center, grab needs initgrabz() value */
1608                                 if(t->mode==TFM_TRANSLATION)
1609                                 {
1610                                         copy_v3_v3(t->center, axis);
1611                                         copy_v3_v3(t->con.center, t->center);
1612                                 }
1613                         }
1614                 }
1615         }
1616         
1617         if(t->spacetype==SPACE_VIEW3D)
1618         {
1619                 /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d_delta() */
1620                 if(t->flag & (T_EDIT|T_POSE)) {
1621                         Object *ob= t->obedit?t->obedit:t->poseobj;
1622                         float vec[3];
1623                         
1624                         copy_v3_v3(vec, t->center);
1625                         mul_m4_v3(ob->obmat, vec);
1626                         initgrabz(t->ar->regiondata, vec[0], vec[1], vec[2]);
1627                 }
1628                 else {
1629                         initgrabz(t->ar->regiondata, t->center[0], t->center[1], t->center[2]);
1630                 }
1631         }
1632 }
1633
1634 void calculatePropRatio(TransInfo *t)
1635 {
1636         TransData *td = t->data;
1637         int i;
1638         float dist;
1639         short connected = t->flag & T_PROP_CONNECTED;
1640
1641         if (t->flag & T_PROP_EDIT) {
1642                 for(i = 0 ; i < t->total; i++, td++) {
1643                         if (td->flag & TD_SELECTED) {
1644                                 td->factor = 1.0f;
1645                         }
1646                         else if (t->flag & T_MIRROR && td->loc[0] * t->mirror < -0.00001f)
1647                         {
1648                                 td->flag |= TD_SKIP;
1649                                 td->factor = 0.0f;
1650                                 restoreElement(td);
1651                         }
1652                         else if ((connected &&
1653                                                 (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size))
1654                                 ||
1655                                         (connected == 0 &&
1656                                                 td->rdist > t->prop_size)) {
1657                                 /*
1658                                    The elements are sorted according to their dist member in the array,
1659                                    that means we can stop when it finds one element outside of the propsize.
1660                                 */
1661                                 td->flag |= TD_NOACTION;
1662                                 td->factor = 0.0f;
1663                                 restoreElement(td);
1664                         }
1665                         else {
1666                                 /* Use rdist for falloff calculations, it is the real distance */
1667                                 td->flag &= ~TD_NOACTION;
1668                                 
1669                                 if (connected)
1670                                         dist= (t->prop_size-td->dist)/t->prop_size;
1671                                 else
1672                                         dist= (t->prop_size-td->rdist)/t->prop_size;
1673
1674                                 /*
1675                                  * Clamp to positive numbers.
1676                                  * Certain corner cases with connectivity and individual centers
1677                                  * can give values of rdist larger than propsize.
1678                                  */
1679                                 if (dist < 0.0f)
1680                                         dist = 0.0f;
1681                                 
1682                                 switch(t->prop_mode) {
1683                                 case PROP_SHARP:
1684                                         td->factor= dist*dist;
1685                                         break;
1686                                 case PROP_SMOOTH:
1687                                         td->factor= 3.0f*dist*dist - 2.0f*dist*dist*dist;
1688                                         break;
1689                                 case PROP_ROOT:
1690                                         td->factor = (float)sqrt(dist);
1691                                         break;
1692                                 case PROP_LIN:
1693                                         td->factor = dist;
1694                                         break;
1695                                 case PROP_CONST:
1696                                         td->factor = 1.0f;
1697                                         break;
1698                                 case PROP_SPHERE:
1699                                         td->factor = (float)sqrt(2*dist - dist * dist);
1700                                         break;
1701                                 case PROP_RANDOM:
1702                                         BLI_srand( BLI_rand() ); /* random seed */
1703                                         td->factor = BLI_frand()*dist;
1704                                         break;
1705                                 default:
1706                                         td->factor = 1;
1707                                 }
1708                         }
1709                 }
1710                 switch(t->prop_mode) {
1711                 case PROP_SHARP:
1712                         strcpy(t->proptext, "(Sharp)");
1713                         break;
1714                 case PROP_SMOOTH:
1715                         strcpy(t->proptext, "(Smooth)");
1716                         break;
1717                 case PROP_ROOT:
1718                         strcpy(t->proptext, "(Root)");
1719                         break;
1720                 case PROP_LIN:
1721                         strcpy(t->proptext, "(Linear)");
1722                         break;
1723                 case PROP_CONST:
1724                         strcpy(t->proptext, "(Constant)");
1725                         break;
1726                 case PROP_SPHERE:
1727                         strcpy(t->proptext, "(Sphere)");
1728                         break;
1729                 case PROP_RANDOM:
1730                         strcpy(t->proptext, "(Random)");
1731                         break;
1732                 default:
1733                         t->proptext[0]= '\0';
1734                 }
1735         }
1736         else {
1737                 for(i = 0 ; i < t->total; i++, td++) {
1738                         td->factor = 1.0;
1739                 }
1740                 t->proptext[0]= '\0';
1741         }
1742 }