4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
33 #include "MEM_guardedalloc.h"
35 #include "BLO_sys_types.h" // for intptr_t support
37 #include "DNA_anim_types.h"
38 #include "DNA_action_types.h"
39 #include "DNA_armature_types.h"
40 #include "DNA_constraint_types.h"
41 #include "DNA_curve_types.h"
42 #include "DNA_lattice_types.h"
43 #include "DNA_mesh_types.h"
44 #include "DNA_modifier_types.h"
45 #include "DNA_nla_types.h"
46 #include "DNA_node_types.h"
47 #include "DNA_object_types.h"
48 #include "DNA_object_force.h"
49 #include "DNA_particle_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_space_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_userdef_types.h"
54 #include "DNA_view3d_types.h"
55 #include "DNA_windowmanager_types.h"
57 #include "RNA_access.h"
59 //#include "BIF_screen.h"
60 //#include "BIF_mywindow.h"
62 //#include "BIF_editmesh.h"
63 //#include "BIF_editsima.h"
64 //#include "BIF_editparticle.h"
65 //#include "BIF_meshtools.h"
67 #include "BKE_animsys.h"
68 #include "BKE_action.h"
70 #include "BKE_armature.h"
71 #include "BKE_cloth.h"
72 #include "BKE_curve.h"
73 #include "BKE_depsgraph.h"
74 #include "BKE_displist.h"
75 #include "BKE_depsgraph.h"
76 #include "BKE_fcurve.h"
77 #include "BKE_global.h"
78 #include "BKE_group.h"
79 #include "BKE_lattice.h"
82 #include "BKE_modifier.h"
84 #include "BKE_object.h"
85 #include "BKE_utildefines.h"
86 #include "BKE_context.h"
88 #include "ED_anim_api.h"
89 #include "ED_armature.h"
91 #include "ED_keyframing.h"
92 #include "ED_markers.h"
94 #include "ED_retopo.h"
95 #include "ED_space_api.h"
96 #include "ED_uvedit.h"
97 #include "ED_view3d.h"
99 //#include "BDR_unwrapper.h"
101 #include "BLI_arithb.h"
102 #include "BLI_blenlib.h"
103 #include "BLI_editVert.h"
104 #include "BLI_rand.h"
106 #include "RNA_access.h"
108 #include "WM_types.h"
110 #include "UI_resources.h"
112 //#include "blendef.h"
114 //#include "mydevice.h"
116 #include "transform.h"
118 extern ListBase editelems;
120 /* ************************** Functions *************************** */
122 void getViewVector(TransInfo *t, float coord[3], float vec[3])
124 if (t->persp != V3D_ORTHO)
132 Mat4MulVec4fl(t->viewmat, p2);
134 p2[0] = 2.0f * p2[0];
135 p2[1] = 2.0f * p2[1];
136 p2[2] = 2.0f * p2[2];
138 Mat4MulVec4fl(t->viewinv, p2);
140 VecSubf(vec, p1, p2);
143 VECCOPY(vec, t->viewinv[2]);
148 /* ************************** GENERICS **************************** */
150 static void clipMirrorModifier(TransInfo *t, Object *ob)
152 ModifierData *md= ob->modifiers.first;
153 float tolerance[3] = {0.0f, 0.0f, 0.0f};
156 for (; md; md=md->next) {
157 if (md->type==eModifierType_Mirror) {
158 MirrorModifierData *mmd = (MirrorModifierData*) md;
160 if(mmd->flag & MOD_MIR_CLIPPING) {
162 if(mmd->flag & MOD_MIR_AXIS_X) {
164 tolerance[0] = mmd->tolerance;
166 if(mmd->flag & MOD_MIR_AXIS_Y) {
168 tolerance[1] = mmd->tolerance;
170 if(mmd->flag & MOD_MIR_AXIS_Z) {
172 tolerance[2] = mmd->tolerance;
175 float mtx[4][4], imtx[4][4];
177 TransData *td = t->data;
179 if (mmd->mirror_ob) {
182 Mat4Invert(obinv, mmd->mirror_ob->obmat);
183 Mat4MulMat4(mtx, ob->obmat, obinv);
184 Mat4Invert(imtx, mtx);
187 for(i = 0 ; i < t->total; i++, td++) {
189 float loc[3], iloc[3];
191 if (td->flag & TD_NOACTION)
196 if (td->flag & TD_SKIP)
199 VecCopyf(loc, td->loc);
200 VecCopyf(iloc, td->iloc);
202 if (mmd->mirror_ob) {
203 VecMat4MulVecfl(loc, mtx, loc);
204 VecMat4MulVecfl(iloc, mtx, iloc);
209 if(fabs(iloc[0])<=tolerance[0] ||
210 loc[0]*iloc[0]<0.0f) {
217 if(fabs(iloc[1])<=tolerance[1] ||
218 loc[1]*iloc[1]<0.0f) {
224 if(fabs(iloc[2])<=tolerance[2] ||
225 loc[2]*iloc[2]<0.0f) {
231 if (mmd->mirror_ob) {
232 VecMat4MulVecfl(loc, imtx, loc);
234 VecCopyf(td->loc, loc);
244 /* assumes obedit set to mesh object */
245 static void editmesh_apply_to_mirror(TransInfo *t)
247 TransData *td = t->data;
251 for(i = 0 ; i < t->total; i++, td++) {
252 if (td->flag & TD_NOACTION)
256 if (td->flag & TD_SKIP)
261 eve->co[0]= -td->loc[0];
262 eve->co[1]= td->loc[1];
263 eve->co[2]= td->loc[2];
268 /* tags the given ID block for refreshes (if applicable) due to
269 * Animation Editor editing
271 static void animedit_refresh_id_tags (ID *id)
273 AnimData *adt= BKE_animdata_from_id(id);
275 /* tag AnimData for refresh so that other views will update in realtime with these changes */
277 adt->recalc |= ADT_RECALC_ANIM;
279 /* if ID-block is Object, set recalc flags */
280 // TODO: this should probably go through the depsgraph instead... but for now, let's be lazy
281 switch (GS(id->name)) {
284 Object *ob= (Object *)id;
285 ob->recalc |= OB_RECALC;
291 /* called for updating while transform acts, once per redraw */
292 void recalcData(TransInfo *t)
294 Scene *scene = t->scene;
299 else if(G.f & G_PARTICLEEDIT) {
300 flushTransParticles(t);
302 if (t->spacetype==SPACE_NODE) {
305 else if (t->spacetype==SPACE_SEQ) {
308 else if (t->spacetype == SPACE_ACTION) {
312 ListBase anim_data = {NULL, NULL};
316 /* initialise relevant anim-context 'context' data from TransInfo data */
317 /* NOTE: sync this with the code in ANIM_animdata_get_context() */
318 memset(&ac, 0, sizeof(bAnimContext));
320 scene= ac.scene= t->scene;
324 ac.spacetype= (t->sa)? t->sa->spacetype : 0;
325 ac.regiontype= (t->ar)? t->ar->regiontype : 0;
327 ANIM_animdata_context_getdata(&ac);
329 /* get animdata blocks visible in editor, assuming that these will be the ones where things changed */
330 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ANIMDATA);
331 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
333 /* just tag these animdata-blocks to recalc, assuming that some data there changed */
334 for (ale= anim_data.first; ale; ale= ale->next) {
335 /* set refresh tags for objects using this animation */
336 animedit_refresh_id_tags(ale->id);
339 /* now free temp channels */
340 BLI_freelistN(&anim_data);
342 else if (t->spacetype == SPACE_IPO) {
345 ListBase anim_data = {NULL, NULL};
353 /* initialise relevant anim-context 'context' data from TransInfo data */
354 /* NOTE: sync this with the code in ANIM_animdata_get_context() */
355 memset(&ac, 0, sizeof(bAnimContext));
357 scene= ac.scene= t->scene;
361 ac.spacetype= (t->sa)? t->sa->spacetype : 0;
362 ac.regiontype= (t->ar)? t->ar->regiontype : 0;
364 ANIM_animdata_context_getdata(&ac);
366 /* do the flush first */
367 flushTransGraphData(t);
369 /* get curves to check if a re-sort is needed */
370 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY | ANIMFILTER_CURVEVISIBLE);
371 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
373 /* now test if there is a need to re-sort */
374 for (ale= anim_data.first; ale; ale= ale->next) {
375 FCurve *fcu= (FCurve *)ale->key_data;
377 /* watch it: if the time is wrong: do not correct handles yet */
378 if (test_time_fcurve(fcu))
381 calchandles_fcurve(fcu);
383 /* set refresh tags for objects using this animation */
384 animedit_refresh_id_tags(ale->id);
387 /* do resort and other updates? */
388 if (dosort) remake_graph_transdata(t, &anim_data);
390 /* now free temp channels */
391 BLI_freelistN(&anim_data);
393 else if (t->spacetype == SPACE_NLA) {
394 TransDataNla *tdn= (TransDataNla *)t->customData;
395 SpaceNla *snla= (SpaceNla *)t->sa->spacedata.first;
396 Scene *scene= t->scene;
400 /* for each strip we've got, perform some additional validation of the values that got set before
401 * using RNA to set the value (which does some special operations when setting these values to make
402 * sure that everything works ok)
404 for (i = 0; i < t->total; i++, tdn++) {
405 NlaStrip *strip= tdn->strip;
406 PointerRNA strip_ptr;
407 short pExceeded, nExceeded, iter;
408 int delta_y1, delta_y2;
410 /* if this tdn has no handles, that means it is just a dummy that should be skipped */
411 if (tdn->handle == 0)
414 /* set refresh tags for objects using this animation */
415 animedit_refresh_id_tags(tdn->id);
417 /* if cancelling transform, just write the values without validating, then move on */
418 if (t->state == TRANS_CANCEL) {
419 /* clear the values by directly overwriting the originals, but also need to restore
420 * endpoints of neighboring transition-strips
424 strip->start= tdn->h1[0];
426 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION))
427 strip->prev->end= tdn->h1[0];
430 strip->end= tdn->h2[0];
432 if ((strip->next) && (strip->next->type == NLASTRIP_TYPE_TRANSITION))
433 strip->next->start= tdn->h2[0];
435 /* flush transforms to child strips (since this should be a meta) */
436 BKE_nlameta_flush_transforms(strip);
438 /* restore to original track (if needed) */
439 if (tdn->oldTrack != tdn->nlt) {
440 /* just append to end of list for now, since strips get sorted in special_aftertrans_update() */
441 BLI_remlink(&tdn->nlt->strips, strip);
442 BLI_addtail(&tdn->oldTrack->strips, strip);
448 /* firstly, check if the proposed transform locations would overlap with any neighbouring strips
449 * (barring transitions) which are absolute barriers since they are not being moved
451 * this is done as a iterative procedure (done 5 times max for now)
453 for (iter=0; iter < 5; iter++) {
454 pExceeded= ((strip->prev) && (strip->prev->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h1[0] < strip->prev->end));
455 nExceeded= ((strip->next) && (strip->next->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h2[0] > strip->next->start));
457 if ((pExceeded && nExceeded) || (iter == 4) ) {
458 /* both endpoints exceeded (or iteration ping-pong'd meaning that we need a compromise)
459 * - simply crop strip to fit within the bounds of the strips bounding it
460 * - if there were no neighbours, clear the transforms (make it default to the strip's current values)
462 if (strip->prev && strip->next) {
463 tdn->h1[0]= strip->prev->end;
464 tdn->h2[0]= strip->next->start;
467 tdn->h1[0]= strip->start;
468 tdn->h2[0]= strip->end;
471 else if (nExceeded) {
473 float offset= tdn->h2[0] - strip->next->start;
475 tdn->h1[0] -= offset;
476 tdn->h2[0] -= offset;
478 else if (pExceeded) {
480 float offset= strip->prev->end - tdn->h1[0];
482 tdn->h1[0] += offset;
483 tdn->h2[0] += offset;
485 else /* all is fine and well */
489 /* handle auto-snapping */
490 switch (snla->autosnap) {
491 case SACTSNAP_FRAME: /* snap to nearest frame/time */
492 if (snla->flag & SNLA_DRAWTIME) {
493 tdn->h1[0]= (float)( floor((tdn->h1[0]/secf) + 0.5f) * secf );
494 tdn->h2[0]= (float)( floor((tdn->h2[0]/secf) + 0.5f) * secf );
497 tdn->h1[0]= (float)( floor(tdn->h1[0]+0.5f) );
498 tdn->h2[0]= (float)( floor(tdn->h2[0]+0.5f) );
502 case SACTSNAP_MARKER: /* snap to nearest marker */
503 tdn->h1[0]= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h1[0]);
504 tdn->h2[0]= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h2[0]);
508 /* use RNA to write the values... */
509 // TODO: do we need to write in 2 passes to make sure that no truncation goes on?
510 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
512 RNA_float_set(&strip_ptr, "start_frame", tdn->h1[0]);
513 RNA_float_set(&strip_ptr, "end_frame", tdn->h2[0]);
515 /* flush transforms to child strips (since this should be a meta) */
516 BKE_nlameta_flush_transforms(strip);
519 /* now, check if we need to try and move track
520 * - we need to calculate both, as only one may have been altered by transform if only 1 handle moved
522 delta_y1= ((int)tdn->h1[1] / NLACHANNEL_STEP - tdn->trackIndex);
523 delta_y2= ((int)tdn->h2[1] / NLACHANNEL_STEP - tdn->trackIndex);
525 if (delta_y1 || delta_y2) {
527 int delta = (delta_y2) ? delta_y2 : delta_y1;
530 /* move in the requested direction, checking at each layer if there's space for strip to pass through,
531 * stopping on the last track available or that we're able to fit in
534 for (track=tdn->nlt->next, n=0; (track) && (n < delta); track=track->next, n++) {
535 /* check if space in this track for the strip */
536 if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
537 /* move strip to this track */
538 BLI_remlink(&tdn->nlt->strips, strip);
539 BKE_nlatrack_add_strip(track, strip);
542 tdn->trackIndex += (n + 1); /* + 1, since n==0 would mean that we didn't change track */
544 else /* can't move any further */
549 /* make delta 'positive' before using it, since we now know to go backwards */
552 for (track=tdn->nlt->prev, n=0; (track) && (n < delta); track=track->prev, n++) {
553 /* check if space in this track for the strip */
554 if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
555 /* move strip to this track */
556 BLI_remlink(&tdn->nlt->strips, strip);
557 BKE_nlatrack_add_strip(track, strip);
560 tdn->trackIndex -= (n - 1); /* - 1, since n==0 would mean that we didn't change track */
562 else /* can't move any further */
569 else if (t->obedit) {
570 if ELEM(t->obedit->type, OB_CURVE, OB_SURF) {
571 Curve *cu= t->obedit->data;
572 Nurb *nu= cu->editnurb->first;
574 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
576 if (t->state == TRANS_CANCEL) {
578 calchandlesNurb(nu); /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
582 /* Normal updating */
588 /* TRANSFORM_FIX_ME */
592 else if(t->obedit->type==OB_LATTICE) {
593 Lattice *la= t->obedit->data;
594 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
596 if(la->editlatt->flag & LT_OUTSIDE) outside_lattice(la->editlatt);
598 else if (t->obedit->type == OB_MESH) {
599 if(t->spacetype==SPACE_IMAGE) {
600 SpaceImage *sima= t->sa->spacedata.first;
603 if(sima->flag & SI_LIVE_UNWRAP)
604 ED_uvedit_live_unwrap_re_solve();
606 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA);
608 EditMesh *em = ((Mesh*)t->obedit->data)->edit_mesh;
609 /* mirror modifier clipping? */
610 if(t->state != TRANS_CANCEL) {
611 /* TRANSFORM_FIX_ME */
612 // if ((G.qual & LR_CTRLKEY)==0) {
613 // /* Only retopo if not snapping, Note, this is the only case of G.qual being used, but we have no T_SHIFT_MOD - Campbell */
616 clipMirrorModifier(t, t->obedit);
618 if((t->options & CTX_NO_MIRROR) == 0 && (t->flag & T_MIRROR))
619 editmesh_apply_to_mirror(t);
621 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
623 recalc_editnormals(em);
626 else if(t->obedit->type==OB_ARMATURE) { /* no recalc flag, does pose */
627 bArmature *arm= t->obedit->data;
628 ListBase *edbo = arm->edbo;
630 TransData *td = t->data;
633 /* Ensure all bones are correctly adjusted */
634 for (ebo = edbo->first; ebo; ebo = ebo->next){
636 if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
637 /* If this bone has a parent tip that has been moved */
638 if (ebo->parent->flag & BONE_TIPSEL){
639 VECCOPY (ebo->head, ebo->parent->tail);
640 if(t->mode==TFM_BONE_ENVELOPE) ebo->rad_head= ebo->parent->rad_tail;
642 /* If this bone has a parent tip that has NOT been moved */
644 VECCOPY (ebo->parent->tail, ebo->head);
645 if(t->mode==TFM_BONE_ENVELOPE) ebo->parent->rad_tail= ebo->rad_head;
649 /* on extrude bones, oldlength==0.0f, so we scale radius of points */
650 ebo->length= VecLenf(ebo->head, ebo->tail);
651 if(ebo->oldlength==0.0f) {
652 ebo->rad_head= 0.25f*ebo->length;
653 ebo->rad_tail= 0.10f*ebo->length;
654 ebo->dist= 0.25f*ebo->length;
656 if(ebo->rad_head > ebo->parent->rad_tail)
657 ebo->rad_head= ebo->parent->rad_tail;
660 else if(t->mode!=TFM_BONE_ENVELOPE) {
661 /* if bones change length, lets do that for the deform distance as well */
662 ebo->dist*= ebo->length/ebo->oldlength;
663 ebo->rad_head*= ebo->length/ebo->oldlength;
664 ebo->rad_tail*= ebo->length/ebo->oldlength;
665 ebo->oldlength= ebo->length;
670 if (t->mode != TFM_BONE_ROLL)
673 for(i = 0; i < t->total; i++, td++)
677 float vec[3], up_axis[3];
681 VECCOPY(up_axis, td->axismtx[2]);
683 if (t->mode != TFM_ROTATION)
685 VecSubf(vec, ebo->tail, ebo->head);
687 RotationBetweenVectorsToQuat(qrot, td->axismtx[1], vec);
688 QuatMulVecf(qrot, up_axis);
692 Mat3MulVecfl(t->mat, up_axis);
695 ebo->roll = ED_rollBoneToVector(ebo, up_axis);
700 if(arm->flag & ARM_MIRROR_EDIT)
701 transform_armature_mirror_update(t->obedit);
705 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
707 else if( (t->flag & T_POSE) && t->poseobj) {
708 Object *ob= t->poseobj;
709 bArmature *arm= ob->data;
711 /* if animtimer is running, and the object already has animation data,
712 * check if the auto-record feature means that we should record 'samples'
713 * (i.e. uneditable animation values)
715 // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
716 // TODO: maybe the ob->adt check isn't really needed? makes it too difficult to use...
717 if (/*(ob->adt) && */(t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
718 short targetless_ik= (t->flag & T_AUTOIK); // XXX this currently doesn't work, since flags aren't set yet!
719 autokeyframe_pose_cb_func(t->scene, (View3D *)t->view, ob, t->mode, targetless_ik);
722 /* old optimize trick... this enforces to bypass the depgraph */
723 if (!(arm->flag & ARM_DELAYDEFORM)) {
724 DAG_object_flush_update(scene, ob, OB_RECALC_DATA); /* sets recalc flags */
727 where_is_pose(scene, ob);
730 for(base= FIRSTBASE; base; base= base->next) {
731 Object *ob= base->object;
733 /* this flag is from depgraph, was stored in initialize phase, handled in drawview.c */
734 if(base->flag & BA_HAS_RECALC_OB)
735 ob->recalc |= OB_RECALC_OB;
736 if(base->flag & BA_HAS_RECALC_DATA)
737 ob->recalc |= OB_RECALC_DATA;
739 /* if object/base is selected */
740 if ((base->flag & SELECT) || (ob->flag & SELECT)) {
741 /* if animtimer is running, and the object already has animation data,
742 * check if the auto-record feature means that we should record 'samples'
743 * (i.e. uneditable animation values)
745 // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
746 // TODO: maybe the ob->adt check isn't really needed? makes it too difficult to use...
747 if (/*(ob->adt) && */(t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
748 autokeyframe_ob_cb_func(t->scene, (View3D *)t->view, ob, t->mode);
752 /* proxy exception */
754 ob->proxy->recalc |= ob->recalc;
756 group_tag_recalc(ob->proxy_group->dup_group);
760 /* update shaded drawmode while transform */
761 if(t->spacetype==SPACE_VIEW3D && ((View3D*)t->view)->drawtype == OB_SHADED)
762 reshadeall_displist(t->scene);
765 void drawLine(TransInfo *t, float *center, float *dir, char axis, short options)
767 float v1[3], v2[3], v3[3];
768 char col[3], col2[3];
770 if (t->spacetype == SPACE_VIEW3D)
772 View3D *v3d = t->view;
776 //if(t->obedit) glLoadMatrixf(t->obedit->obmat); // sets opengl viewing
780 VecMulf(v3, v3d->far);
782 VecSubf(v2, center, v3);
783 VecAddf(v1, center, v3);
785 if (options & DRAWLIGHT) {
786 col[0] = col[1] = col[2] = 220;
789 UI_GetThemeColor3ubv(TH_GRID, col);
791 UI_make_axis_color(col, col2, axis);
792 glColor3ubv((GLubyte *)col2);
795 glBegin(GL_LINE_STRIP);
804 void resetTransRestrictions(TransInfo *t)
806 t->flag &= ~T_ALL_RESTRICTIONS;
809 int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
811 Scene *sce = CTX_data_scene(C);
812 ToolSettings *ts = CTX_data_tool_settings(C);
813 ARegion *ar = CTX_wm_region(C);
814 ScrArea *sa = CTX_wm_area(C);
815 Object *obedit = CTX_data_edit_object(C);
817 /* moving: is shown in drawobject() (transform color) */
819 // if(obedit || (t->flag & T_POSE) ) G.moving= G_TRANSFORM_EDIT;
820 // else if(G.f & G_PARTICLEEDIT) G.moving= G_TRANSFORM_PARTICLE;
821 // else G.moving= G_TRANSFORM_OBJ;
832 t->helpline = HLP_NONE;
836 t->redraw = 1; /* redraw first time */
840 t->imval[0] = event->x - t->ar->winrct.xmin;
841 t->imval[1] = event->y - t->ar->winrct.ymin;
843 t->event_type = event->type;
851 t->con.imval[0] = t->imval[0];
852 t->con.imval[1] = t->imval[1];
854 t->mval[0] = t->imval[0];
855 t->mval[1] = t->imval[1];
858 t->handleEvent = NULL;
874 t->spacetype = sa->spacetype;
875 if(t->spacetype == SPACE_VIEW3D)
877 View3D *v3d = sa->spacedata.first;
880 t->animtimer= CTX_wm_screen(C)->animtimer;
882 if(v3d->flag & V3D_ALIGN) t->flag |= T_V3D_ALIGN;
883 t->around = v3d->around;
885 if (op && RNA_struct_find_property(op->ptr, "constraint_axis") && RNA_property_is_set(op->ptr, "constraint_orientation"))
887 t->current_orientation = RNA_enum_get(op->ptr, "constraint_orientation");
889 if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C) - 1)
891 t->current_orientation = V3D_MANIP_GLOBAL;
896 t->current_orientation = v3d->twmode;
899 else if(t->spacetype==SPACE_IMAGE || t->spacetype==SPACE_NODE)
901 SpaceImage *sima = sa->spacedata.first;
902 // XXX for now, get View2D from the active region
904 t->around = sima->around;
908 // XXX for now, get View2D from the active region
911 t->around = V3D_CENTER;
914 if (op && RNA_struct_find_property(op->ptr, "mirror") && RNA_property_is_set(op->ptr, "mirror"))
916 if (RNA_boolean_get(op->ptr, "mirror"))
921 // Need stuff to take it from edit mesh or whatnot here
924 if (t->obedit && t->obedit->type == OB_MESH && ts->editbutflag & B_MESH_X_MIRROR)
930 /* setting PET flag */
931 if (op && RNA_struct_find_property(op->ptr, "proportional") && RNA_property_is_set(op->ptr, "proportional"))
933 switch(RNA_enum_get(op->ptr, "proportional"))
935 case 2: /* XXX connected constant */
936 t->flag |= T_PROP_CONNECTED;
937 case 1: /* XXX prop on constant */
938 t->flag |= T_PROP_EDIT;
944 if ((t->options & CTX_NO_PET) == 0 && (ts->proportional)) {
945 t->flag |= T_PROP_EDIT;
947 if(ts->proportional == 2)
948 t->flag |= T_PROP_CONNECTED; // yes i know, has to become define
952 if (op && RNA_struct_find_property(op->ptr, "proportional_size") && RNA_property_is_set(op->ptr, "proportional_size"))
954 t->prop_size = RNA_float_get(op->ptr, "proportional_size");
958 t->prop_size = ts->proportional_size;
961 if (op && RNA_struct_find_property(op->ptr, "proportional_editing_falloff") && RNA_property_is_set(op->ptr, "proportional_editing_falloff"))
963 t->prop_mode = RNA_enum_get(op->ptr, "proportional_editing_falloff");
967 t->prop_mode = ts->prop_mode;
970 /* TRANSFORM_FIX_ME rna restrictions */
971 if (t->prop_size <= 0)
976 setTransformViewMatrices(t);
977 initNumInput(&t->num);
978 initNDofInput(&t->ndof);
983 /* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
984 void postTrans (TransInfo *t)
990 ED_region_draw_cb_exit(t->ar->type, t->draw_handle);
993 /* postTrans can be called when nothing is selected, so data is NULL already */
997 /* since ipokeys are optional on objects, we mallocced them per trans-data */
998 for(a=0, td= t->data; a<t->total; a++, td++) {
999 if(td->tdi) MEM_freeN(td->tdi);
1000 if (td->flag & TD_BEZTRIPLE) MEM_freeN(td->hdata);
1005 if (t->ext) MEM_freeN(t->ext);
1007 MEM_freeN(t->data2d);
1011 if(t->spacetype==SPACE_IMAGE) {
1012 SpaceImage *sima= t->sa->spacedata.first;
1013 if(sima->flag & SI_LIVE_UNWRAP)
1014 ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL);
1016 else if(ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) {
1018 MEM_freeN(t->customData);
1022 void applyTransObjects(TransInfo *t)
1026 for (td = t->data; td < t->data + t->total; td++) {
1027 VECCOPY(td->iloc, td->loc);
1029 VECCOPY(td->ext->irot, td->ext->rot);
1031 if (td->ext->size) {
1032 VECCOPY(td->ext->isize, td->ext->size);
1038 /* helper for below */
1039 static void restore_ipokey(float *poin, float *old)
1048 static void restoreElement(TransData *td) {
1049 /* TransData for crease has no loc */
1051 VECCOPY(td->loc, td->iloc);
1054 *td->val = td->ival;
1056 if (td->ext && (td->flag&TD_NO_EXT)==0) {
1058 VECCOPY(td->ext->rot, td->ext->irot);
1060 if (td->ext->size) {
1061 VECCOPY(td->ext->size, td->ext->isize);
1063 if(td->flag & TD_USEQUAT) {
1064 if (td->ext->quat) {
1065 QUATCOPY(td->ext->quat, td->ext->iquat);
1070 if (td->flag & TD_BEZTRIPLE) {
1071 *(td->hdata->h1) = td->hdata->ih1;
1072 *(td->hdata->h2) = td->hdata->ih2;
1076 TransDataIpokey *tdi= td->tdi;
1078 restore_ipokey(tdi->locx, tdi->oldloc);
1079 restore_ipokey(tdi->locy, tdi->oldloc+1);
1080 restore_ipokey(tdi->locz, tdi->oldloc+2);
1082 restore_ipokey(tdi->rotx, tdi->oldrot);
1083 restore_ipokey(tdi->roty, tdi->oldrot+1);
1084 restore_ipokey(tdi->rotz, tdi->oldrot+2);
1086 restore_ipokey(tdi->sizex, tdi->oldsize);
1087 restore_ipokey(tdi->sizey, tdi->oldsize+1);
1088 restore_ipokey(tdi->sizez, tdi->oldsize+2);
1092 void restoreTransObjects(TransInfo *t)
1096 for (td = t->data; td < t->data + t->total; td++) {
1105 void calculateCenter2D(TransInfo *t)
1107 if (t->flag & (T_EDIT|T_POSE)) {
1108 Object *ob= t->obedit?t->obedit:t->poseobj;
1111 VECCOPY(vec, t->center);
1112 Mat4MulVecfl(ob->obmat, vec);
1113 projectIntView(t, vec, t->center2d);
1116 projectIntView(t, t->center, t->center2d);
1120 void calculateCenterCursor(TransInfo *t)
1124 cursor = give_cursor(t->scene, t->view);
1125 VECCOPY(t->center, cursor);
1127 /* If edit or pose mode, move cursor in local space */
1128 if (t->flag & (T_EDIT|T_POSE)) {
1129 Object *ob = t->obedit?t->obedit:t->poseobj;
1130 float mat[3][3], imat[3][3];
1132 VecSubf(t->center, t->center, ob->obmat[3]);
1133 Mat3CpyMat4(mat, ob->obmat);
1135 Mat3MulVecfl(imat, t->center);
1138 calculateCenter2D(t);
1141 void calculateCenterCursor2D(TransInfo *t)
1143 View2D *v2d= t->view;
1144 float aspx=1.0, aspy=1.0;
1146 if(t->spacetype==SPACE_IMAGE) /* only space supported right now but may change */
1147 ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
1150 t->center[0] = v2d->cursor[0] * aspx;
1151 t->center[1] = v2d->cursor[1] * aspy;
1154 calculateCenter2D(t);
1157 void calculateCenterMedian(TransInfo *t)
1159 float partial[3] = {0.0f, 0.0f, 0.0f};
1163 for(i = 0; i < t->total; i++) {
1164 if (t->data[i].flag & TD_SELECTED) {
1165 if (!(t->data[i].flag & TD_NOCENTER))
1167 VecAddf(partial, partial, t->data[i].center);
1173 All the selected elements are at the head of the array
1174 which means we can stop when it finds unselected data
1180 VecMulf(partial, 1.0f / total);
1181 VECCOPY(t->center, partial);
1183 calculateCenter2D(t);
1186 void calculateCenterBound(TransInfo *t)
1191 for(i = 0; i < t->total; i++) {
1193 if (t->data[i].flag & TD_SELECTED) {
1194 if (!(t->data[i].flag & TD_NOCENTER))
1195 MinMax3(min, max, t->data[i].center);
1199 All the selected elements are at the head of the array
1200 which means we can stop when it finds unselected data
1206 VECCOPY(max, t->data[i].center);
1207 VECCOPY(min, t->data[i].center);
1210 VecAddf(t->center, min, max);
1211 VecMulf(t->center, 0.5);
1213 calculateCenter2D(t);
1216 void calculateCenter(TransInfo *t)
1220 calculateCenterBound(t);
1223 calculateCenterMedian(t);
1226 if(t->spacetype==SPACE_IMAGE)
1227 calculateCenterCursor2D(t);
1229 calculateCenterCursor(t);
1232 /* Individual element center uses median center for helpline and such */
1233 calculateCenterMedian(t);
1237 /* set median, and if if if... do object center */
1238 #if 0 // TRANSFORM_FIX_ME
1240 /* EDIT MODE ACTIVE EDITMODE ELEMENT */
1242 if (t->obedit && t->obedit->type == OB_MESH && EM_get_actSelection(&ese)) {
1243 EM_editselection_center(t->center, &ese);
1244 calculateCenter2D(t);
1246 } /* END EDIT MODE ACTIVE ELEMENT */
1249 calculateCenterMedian(t);
1250 if((t->flag & (T_EDIT|T_POSE))==0)
1252 Scene *scene = t->scene;
1256 VECCOPY(t->center, ob->obmat[3]);
1257 projectIntView(t, t->center, t->center2d);
1264 /* setting constraint center */
1265 VECCOPY(t->con.center, t->center);
1266 if(t->flag & (T_EDIT|T_POSE))
1268 Object *ob= t->obedit?t->obedit:t->poseobj;
1269 Mat4MulVecfl(ob->obmat, t->con.center);
1272 /* voor panning from cameraview */
1273 if(t->flag & T_OBJECT)
1275 if(t->spacetype==SPACE_VIEW3D)
1277 View3D *v3d = t->view;
1278 Scene *scene = t->scene;
1279 RegionView3D *rv3d = t->ar->regiondata;
1281 if(v3d->camera == OBACT && rv3d->persp==V3D_CAMOB)
1284 /* persinv is nasty, use viewinv instead, always right */
1285 VECCOPY(axis, t->viewinv[2]);
1288 /* 6.0 = 6 grid units */
1289 axis[0]= t->center[0]- 6.0f*axis[0];
1290 axis[1]= t->center[1]- 6.0f*axis[1];
1291 axis[2]= t->center[2]- 6.0f*axis[2];
1293 projectIntView(t, axis, t->center2d);
1295 /* rotate only needs correct 2d center, grab needs initgrabz() value */
1296 if(t->mode==TFM_TRANSLATION)
1298 VECCOPY(t->center, axis);
1299 VECCOPY(t->con.center, t->center);
1305 if(t->spacetype==SPACE_VIEW3D)
1307 /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d_delta() */
1308 if(t->flag & (T_EDIT|T_POSE)) {
1309 Object *ob= t->obedit?t->obedit:t->poseobj;
1312 VECCOPY(vec, t->center);
1313 Mat4MulVecfl(ob->obmat, vec);
1314 initgrabz(t->ar->regiondata, vec[0], vec[1], vec[2]);
1317 initgrabz(t->ar->regiondata, t->center[0], t->center[1], t->center[2]);
1322 void calculatePropRatio(TransInfo *t)
1324 TransData *td = t->data;
1327 short connected = t->flag & T_PROP_CONNECTED;
1329 if (t->flag & T_PROP_EDIT) {
1330 for(i = 0 ; i < t->total; i++, td++) {
1331 if (td->flag & TD_SELECTED) {
1334 else if ((connected &&
1335 (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size))
1338 td->rdist > t->prop_size)) {
1340 The elements are sorted according to their dist member in the array,
1341 that means we can stop when it finds one element outside of the propsize.
1343 td->flag |= TD_NOACTION;
1348 /* Use rdist for falloff calculations, it is the real distance */
1349 td->flag &= ~TD_NOACTION;
1350 dist= (t->prop_size-td->rdist)/t->prop_size;
1353 * Clamp to positive numbers.
1354 * Certain corner cases with connectivity and individual centers
1355 * can give values of rdist larger than propsize.
1360 switch(t->prop_mode) {
1362 td->factor= dist*dist;
1365 td->factor= 3.0f*dist*dist - 2.0f*dist*dist*dist;
1368 td->factor = (float)sqrt(dist);
1377 td->factor = (float)sqrt(2*dist - dist * dist);
1380 BLI_srand( BLI_rand() ); /* random seed */
1381 td->factor = BLI_frand()*dist;
1388 switch(t->prop_mode) {
1390 strcpy(t->proptext, "(Sharp)");
1393 strcpy(t->proptext, "(Smooth)");
1396 strcpy(t->proptext, "(Root)");
1399 strcpy(t->proptext, "(Linear)");
1402 strcpy(t->proptext, "(Constant)");
1405 strcpy(t->proptext, "(Sphere)");
1408 strcpy(t->proptext, "(Random)");
1411 strcpy(t->proptext, "");
1415 for(i = 0 ; i < t->total; i++, td++) {
1418 strcpy(t->proptext, "");
1422 float get_drawsize(ARegion *ar, float *co)
1424 RegionView3D *rv3d= ar->regiondata;
1425 float size, vec[3], len1, len2;
1427 /* size calculus, depending ortho/persp settings, like initgrabz() */
1428 size= rv3d->persmat[0][3]*co[0]+ rv3d->persmat[1][3]*co[1]+ rv3d->persmat[2][3]*co[2]+ rv3d->persmat[3][3];
1430 VECCOPY(vec, rv3d->persinv[0]);
1431 len1= Normalize(vec);
1432 VECCOPY(vec, rv3d->persinv[1]);
1433 len2= Normalize(vec);
1435 size*= 0.01f*(len1>len2?len1:len2);
1437 /* correct for window size to make widgets appear fixed size */
1438 if(ar->winx > ar->winy) size*= 1000.0f/(float)ar->winx;
1439 else size*= 1000.0f/(float)ar->winy;