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_action.h"
69 #include "BKE_armature.h"
70 #include "BKE_cloth.h"
71 #include "BKE_curve.h"
72 #include "BKE_depsgraph.h"
73 #include "BKE_displist.h"
74 #include "BKE_depsgraph.h"
75 #include "BKE_fcurve.h"
76 #include "BKE_global.h"
77 #include "BKE_group.h"
78 #include "BKE_lattice.h"
81 #include "BKE_modifier.h"
83 #include "BKE_object.h"
84 #include "BKE_utildefines.h"
85 #include "BKE_context.h"
87 #include "ED_anim_api.h"
88 #include "ED_armature.h"
90 #include "ED_keyframing.h"
91 #include "ED_markers.h"
93 #include "ED_retopo.h"
94 #include "ED_space_api.h"
95 #include "ED_uvedit.h"
96 #include "ED_view3d.h"
98 //#include "BDR_unwrapper.h"
100 #include "BLI_arithb.h"
101 #include "BLI_blenlib.h"
102 #include "BLI_editVert.h"
103 #include "BLI_rand.h"
105 #include "RNA_access.h"
107 #include "WM_types.h"
109 #include "UI_resources.h"
111 //#include "blendef.h"
113 //#include "mydevice.h"
115 #include "transform.h"
117 extern ListBase editelems;
119 /* ************************** Functions *************************** */
121 void getViewVector(TransInfo *t, float coord[3], float vec[3])
123 if (t->persp != V3D_ORTHO)
131 Mat4MulVec4fl(t->viewmat, p2);
133 p2[0] = 2.0f * p2[0];
134 p2[1] = 2.0f * p2[1];
135 p2[2] = 2.0f * p2[2];
137 Mat4MulVec4fl(t->viewinv, p2);
139 VecSubf(vec, p1, p2);
142 VECCOPY(vec, t->viewinv[2]);
147 /* ************************** GENERICS **************************** */
149 static void clipMirrorModifier(TransInfo *t, Object *ob)
151 ModifierData *md= ob->modifiers.first;
152 float tolerance[3] = {0.0f, 0.0f, 0.0f};
155 for (; md; md=md->next) {
156 if (md->type==eModifierType_Mirror) {
157 MirrorModifierData *mmd = (MirrorModifierData*) md;
159 if(mmd->flag & MOD_MIR_CLIPPING) {
161 if(mmd->flag & MOD_MIR_AXIS_X) {
163 tolerance[0] = mmd->tolerance;
165 if(mmd->flag & MOD_MIR_AXIS_Y) {
167 tolerance[1] = mmd->tolerance;
169 if(mmd->flag & MOD_MIR_AXIS_Z) {
171 tolerance[2] = mmd->tolerance;
174 float mtx[4][4], imtx[4][4];
176 TransData *td = t->data;
178 if (mmd->mirror_ob) {
181 Mat4Invert(obinv, mmd->mirror_ob->obmat);
182 Mat4MulMat4(mtx, ob->obmat, obinv);
183 Mat4Invert(imtx, mtx);
186 for(i = 0 ; i < t->total; i++, td++) {
188 float loc[3], iloc[3];
190 if (td->flag & TD_NOACTION)
195 if (td->flag & TD_SKIP)
198 VecCopyf(loc, td->loc);
199 VecCopyf(iloc, td->iloc);
201 if (mmd->mirror_ob) {
202 VecMat4MulVecfl(loc, mtx, loc);
203 VecMat4MulVecfl(iloc, mtx, iloc);
208 if(fabs(iloc[0])<=tolerance[0] ||
209 loc[0]*iloc[0]<0.0f) {
216 if(fabs(iloc[1])<=tolerance[1] ||
217 loc[1]*iloc[1]<0.0f) {
223 if(fabs(iloc[2])<=tolerance[2] ||
224 loc[2]*iloc[2]<0.0f) {
230 if (mmd->mirror_ob) {
231 VecMat4MulVecfl(loc, imtx, loc);
233 VecCopyf(td->loc, loc);
243 /* assumes obedit set to mesh object */
244 static void editmesh_apply_to_mirror(TransInfo *t)
246 TransData *td = t->data;
250 for(i = 0 ; i < t->total; i++, td++) {
251 if (td->flag & TD_NOACTION)
255 if (td->flag & TD_SKIP)
260 eve->co[0]= -td->loc[0];
261 eve->co[1]= td->loc[1];
262 eve->co[2]= td->loc[2];
267 /* tags the given ID block for refreshes (if applicable) due to
268 * Animation Editor editing
270 static void animedit_refresh_id_tags (ID *id)
272 AnimData *adt= BKE_animdata_from_id(id);
274 /* tag AnimData for refresh so that other views will update in realtime with these changes */
276 adt->recalc |= ADT_RECALC_ANIM;
278 /* if ID-block is Object, set recalc flags */
279 // TODO: this should probably go through the depsgraph instead... but for now, let's be lazy
280 switch (GS(id->name)) {
283 Object *ob= (Object *)id;
284 ob->recalc |= OB_RECALC;
290 /* called for updating while transform acts, once per redraw */
291 void recalcData(TransInfo *t)
293 Scene *scene = t->scene;
298 else if(G.f & G_PARTICLEEDIT) {
299 flushTransParticles(t);
301 if (t->spacetype==SPACE_NODE) {
304 else if (t->spacetype==SPACE_SEQ) {
307 else if (t->spacetype == SPACE_ACTION) {
308 SpaceAction *sact= (SpaceAction *)t->sa->spacedata.first;
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) {
343 SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first;
346 ListBase anim_data = {NULL, NULL};
354 /* initialise relevant anim-context 'context' data from TransInfo data */
355 /* NOTE: sync this with the code in ANIM_animdata_get_context() */
356 memset(&ac, 0, sizeof(bAnimContext));
358 scene= ac.scene= t->scene;
362 ac.spacetype= (t->sa)? t->sa->spacetype : 0;
363 ac.regiontype= (t->ar)? t->ar->regiontype : 0;
365 ANIM_animdata_context_getdata(&ac);
367 /* do the flush first */
368 flushTransGraphData(t);
370 /* get curves to check if a re-sort is needed */
371 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY | ANIMFILTER_CURVEVISIBLE);
372 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
374 /* now test if there is a need to re-sort */
375 for (ale= anim_data.first; ale; ale= ale->next) {
376 FCurve *fcu= (FCurve *)ale->key_data;
377 AnimData *adt= BKE_animdata_from_id(ale->id);
379 /* watch it: if the time is wrong: do not correct handles yet */
380 if (test_time_fcurve(fcu))
383 calchandles_fcurve(fcu);
385 /* set refresh tags for objects using this animation */
386 animedit_refresh_id_tags(ale->id);
389 /* do resort and other updates? */
390 if (dosort) remake_graph_transdata(t, &anim_data);
392 /* now free temp channels */
393 BLI_freelistN(&anim_data);
395 else if (t->spacetype == SPACE_NLA) {
396 TransDataNla *tdn= (TransDataNla *)t->customData;
397 SpaceNla *snla= (SpaceNla *)t->sa->spacedata.first;
398 Scene *scene= t->scene;
402 /* for each strip we've got, perform some additional validation of the values that got set before
403 * using RNA to set the value (which does some special operations when setting these values to make
404 * sure that everything works ok)
406 for (i = 0; i < t->total; i++, tdn++) {
407 NlaStrip *strip= tdn->strip;
408 PointerRNA strip_ptr;
409 short pExceeded, nExceeded, iter;
410 int delta_y1, delta_y2;
412 /* if this tdn has no handles, that means it is just a dummy that should be skipped */
413 if (tdn->handle == 0)
416 /* set refresh tags for objects using this animation */
417 animedit_refresh_id_tags(tdn->id);
419 /* if cancelling transform, just write the values without validating, then move on */
420 if (t->state == TRANS_CANCEL) {
421 /* clear the values by directly overwriting the originals, but also need to restore
422 * endpoints of neighboring transition-strips
426 strip->start= tdn->h1[0];
428 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION))
429 strip->prev->end= tdn->h1[0];
432 strip->end= tdn->h2[0];
434 if ((strip->next) && (strip->next->type == NLASTRIP_TYPE_TRANSITION))
435 strip->next->start= tdn->h2[0];
437 /* flush transforms to child strips (since this should be a meta) */
438 BKE_nlameta_flush_transforms(strip);
440 /* restore to original track (if needed) */
441 if (tdn->oldTrack != tdn->nlt) {
442 /* just append to end of list for now, since strips get sorted in special_aftertrans_update() */
443 BLI_remlink(&tdn->nlt->strips, strip);
444 BLI_addtail(&tdn->oldTrack->strips, strip);
450 /* firstly, check if the proposed transform locations would overlap with any neighbouring strips
451 * (barring transitions) which are absolute barriers since they are not being moved
453 * this is done as a iterative procedure (done 5 times max for now)
455 for (iter=0; iter < 5; iter++) {
456 pExceeded= ((strip->prev) && (strip->prev->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h1[0] < strip->prev->end));
457 nExceeded= ((strip->next) && (strip->next->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h2[0] > strip->next->start));
459 if ((pExceeded && nExceeded) || (iter == 4) ) {
460 /* both endpoints exceeded (or iteration ping-pong'd meaning that we need a compromise)
461 * - simply crop strip to fit within the bounds of the strips bounding it
462 * - if there were no neighbours, clear the transforms (make it default to the strip's current values)
464 if (strip->prev && strip->next) {
465 tdn->h1[0]= strip->prev->end;
466 tdn->h2[0]= strip->next->start;
469 tdn->h1[0]= strip->start;
470 tdn->h2[0]= strip->end;
473 else if (nExceeded) {
475 float offset= tdn->h2[0] - strip->next->start;
477 tdn->h1[0] -= offset;
478 tdn->h2[0] -= offset;
480 else if (pExceeded) {
482 float offset= strip->prev->end - tdn->h1[0];
484 tdn->h1[0] += offset;
485 tdn->h2[0] += offset;
487 else /* all is fine and well */
491 /* handle auto-snapping */
492 switch (snla->autosnap) {
493 case SACTSNAP_FRAME: /* snap to nearest frame/time */
494 if (snla->flag & SNLA_DRAWTIME) {
495 tdn->h1[0]= (float)( floor((tdn->h1[0]/secf) + 0.5f) * secf );
496 tdn->h2[0]= (float)( floor((tdn->h2[0]/secf) + 0.5f) * secf );
499 tdn->h1[0]= (float)( floor(tdn->h1[0]+0.5f) );
500 tdn->h2[0]= (float)( floor(tdn->h2[0]+0.5f) );
504 case SACTSNAP_MARKER: /* snap to nearest marker */
505 tdn->h1[0]= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h1[0]);
506 tdn->h2[0]= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h2[0]);
510 /* use RNA to write the values... */
511 // TODO: do we need to write in 2 passes to make sure that no truncation goes on?
512 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
514 RNA_float_set(&strip_ptr, "start_frame", tdn->h1[0]);
515 RNA_float_set(&strip_ptr, "end_frame", tdn->h2[0]);
517 /* flush transforms to child strips (since this should be a meta) */
518 BKE_nlameta_flush_transforms(strip);
521 /* now, check if we need to try and move track
522 * - we need to calculate both, as only one may have been altered by transform if only 1 handle moved
524 delta_y1= ((int)tdn->h1[1] / NLACHANNEL_STEP - tdn->trackIndex);
525 delta_y2= ((int)tdn->h2[1] / NLACHANNEL_STEP - tdn->trackIndex);
527 if (delta_y1 || delta_y2) {
529 int delta = (delta_y2) ? delta_y2 : delta_y1;
532 /* move in the requested direction, checking at each layer if there's space for strip to pass through,
533 * stopping on the last track available or that we're able to fit in
536 for (track=tdn->nlt->next, n=0; (track) && (n < delta); track=track->next, n++) {
537 /* check if space in this track for the strip */
538 if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
539 /* move strip to this track */
540 BLI_remlink(&tdn->nlt->strips, strip);
541 BKE_nlatrack_add_strip(track, strip);
544 tdn->trackIndex += (n + 1); /* + 1, since n==0 would mean that we didn't change track */
546 else /* can't move any further */
551 /* make delta 'positive' before using it, since we now know to go backwards */
554 for (track=tdn->nlt->prev, n=0; (track) && (n < delta); track=track->prev, n++) {
555 /* check if space in this track for the strip */
556 if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
557 /* move strip to this track */
558 BLI_remlink(&tdn->nlt->strips, strip);
559 BKE_nlatrack_add_strip(track, strip);
562 tdn->trackIndex -= (n - 1); /* - 1, since n==0 would mean that we didn't change track */
564 else /* can't move any further */
571 else if (t->obedit) {
572 if ELEM(t->obedit->type, OB_CURVE, OB_SURF) {
573 Curve *cu= t->obedit->data;
574 Nurb *nu= cu->editnurb->first;
576 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
578 if (t->state == TRANS_CANCEL) {
580 calchandlesNurb(nu); /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
584 /* Normal updating */
590 /* TRANSFORM_FIX_ME */
594 else if(t->obedit->type==OB_LATTICE) {
595 Lattice *la= t->obedit->data;
596 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
598 if(la->editlatt->flag & LT_OUTSIDE) outside_lattice(la->editlatt);
600 else if (t->obedit->type == OB_MESH) {
601 if(t->spacetype==SPACE_IMAGE) {
602 SpaceImage *sima= t->sa->spacedata.first;
605 if(sima->flag & SI_LIVE_UNWRAP)
606 ED_uvedit_live_unwrap_re_solve();
608 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA);
610 EditMesh *em = ((Mesh*)t->obedit->data)->edit_mesh;
611 /* mirror modifier clipping? */
612 if(t->state != TRANS_CANCEL) {
613 /* TRANSFORM_FIX_ME */
614 // if ((G.qual & LR_CTRLKEY)==0) {
615 // /* Only retopo if not snapping, Note, this is the only case of G.qual being used, but we have no T_SHIFT_MOD - Campbell */
618 clipMirrorModifier(t, t->obedit);
620 if((t->options & CTX_NO_MIRROR) == 0 && (t->flag & T_MIRROR))
621 editmesh_apply_to_mirror(t);
623 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
625 recalc_editnormals(em);
628 else if(t->obedit->type==OB_ARMATURE) { /* no recalc flag, does pose */
629 bArmature *arm= t->obedit->data;
630 ListBase *edbo = arm->edbo;
632 TransData *td = t->data;
635 /* Ensure all bones are correctly adjusted */
636 for (ebo = edbo->first; ebo; ebo = ebo->next){
638 if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
639 /* If this bone has a parent tip that has been moved */
640 if (ebo->parent->flag & BONE_TIPSEL){
641 VECCOPY (ebo->head, ebo->parent->tail);
642 if(t->mode==TFM_BONE_ENVELOPE) ebo->rad_head= ebo->parent->rad_tail;
644 /* If this bone has a parent tip that has NOT been moved */
646 VECCOPY (ebo->parent->tail, ebo->head);
647 if(t->mode==TFM_BONE_ENVELOPE) ebo->parent->rad_tail= ebo->rad_head;
651 /* on extrude bones, oldlength==0.0f, so we scale radius of points */
652 ebo->length= VecLenf(ebo->head, ebo->tail);
653 if(ebo->oldlength==0.0f) {
654 ebo->rad_head= 0.25f*ebo->length;
655 ebo->rad_tail= 0.10f*ebo->length;
656 ebo->dist= 0.25f*ebo->length;
658 if(ebo->rad_head > ebo->parent->rad_tail)
659 ebo->rad_head= ebo->parent->rad_tail;
662 else if(t->mode!=TFM_BONE_ENVELOPE) {
663 /* if bones change length, lets do that for the deform distance as well */
664 ebo->dist*= ebo->length/ebo->oldlength;
665 ebo->rad_head*= ebo->length/ebo->oldlength;
666 ebo->rad_tail*= ebo->length/ebo->oldlength;
667 ebo->oldlength= ebo->length;
672 if (t->mode != TFM_BONE_ROLL)
675 for(i = 0; i < t->total; i++, td++)
679 float vec[3], up_axis[3];
683 VECCOPY(up_axis, td->axismtx[2]);
685 if (t->mode != TFM_ROTATION)
687 VecSubf(vec, ebo->tail, ebo->head);
689 RotationBetweenVectorsToQuat(qrot, td->axismtx[1], vec);
690 QuatMulVecf(qrot, up_axis);
694 Mat3MulVecfl(t->mat, up_axis);
697 ebo->roll = ED_rollBoneToVector(ebo, up_axis);
702 if(arm->flag & ARM_MIRROR_EDIT)
703 transform_armature_mirror_update(t->obedit);
707 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
709 else if( (t->flag & T_POSE) && t->poseobj) {
710 Object *ob= t->poseobj;
711 bArmature *arm= ob->data;
713 /* if animtimer is running, and the object already has animation data,
714 * check if the auto-record feature means that we should record 'samples'
715 * (i.e. uneditable animation values)
717 // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
718 // TODO: maybe the ob->adt check isn't really needed? makes it too difficult to use...
719 if (/*(ob->adt) && */(t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
720 short targetless_ik= (t->flag & T_AUTOIK); // XXX this currently doesn't work, since flags aren't set yet!
721 autokeyframe_pose_cb_func(t->scene, (View3D *)t->view, ob, t->mode, targetless_ik);
724 /* old optimize trick... this enforces to bypass the depgraph */
725 if (!(arm->flag & ARM_DELAYDEFORM)) {
726 DAG_object_flush_update(scene, ob, OB_RECALC_DATA); /* sets recalc flags */
729 where_is_pose(scene, ob);
732 for(base= FIRSTBASE; base; base= base->next) {
733 Object *ob= base->object;
735 /* this flag is from depgraph, was stored in initialize phase, handled in drawview.c */
736 if(base->flag & BA_HAS_RECALC_OB)
737 ob->recalc |= OB_RECALC_OB;
738 if(base->flag & BA_HAS_RECALC_DATA)
739 ob->recalc |= OB_RECALC_DATA;
741 /* if object/base is selected */
742 if ((base->flag & SELECT) || (ob->flag & SELECT)) {
743 /* if animtimer is running, and the object already has animation data,
744 * check if the auto-record feature means that we should record 'samples'
745 * (i.e. uneditable animation values)
747 // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
748 // TODO: maybe the ob->adt check isn't really needed? makes it too difficult to use...
749 if (/*(ob->adt) && */(t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
750 autokeyframe_ob_cb_func(t->scene, (View3D *)t->view, ob, t->mode);
754 /* proxy exception */
756 ob->proxy->recalc |= ob->recalc;
758 group_tag_recalc(ob->proxy_group->dup_group);
762 /* update shaded drawmode while transform */
763 if(t->spacetype==SPACE_VIEW3D && ((View3D*)t->view)->drawtype == OB_SHADED)
764 reshadeall_displist(t->scene);
767 void drawLine(TransInfo *t, float *center, float *dir, char axis, short options)
769 float v1[3], v2[3], v3[3];
770 char col[3], col2[3];
772 if (t->spacetype == SPACE_VIEW3D)
774 View3D *v3d = t->view;
778 //if(t->obedit) glLoadMatrixf(t->obedit->obmat); // sets opengl viewing
782 VecMulf(v3, v3d->far);
784 VecSubf(v2, center, v3);
785 VecAddf(v1, center, v3);
787 if (options & DRAWLIGHT) {
788 col[0] = col[1] = col[2] = 220;
791 UI_GetThemeColor3ubv(TH_GRID, col);
793 UI_make_axis_color(col, col2, axis);
794 glColor3ubv((GLubyte *)col2);
797 glBegin(GL_LINE_STRIP);
806 void resetTransRestrictions(TransInfo *t)
808 t->flag &= ~T_ALL_RESTRICTIONS;
811 int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
813 Scene *sce = CTX_data_scene(C);
814 ToolSettings *ts = CTX_data_tool_settings(C);
815 ARegion *ar = CTX_wm_region(C);
816 ScrArea *sa = CTX_wm_area(C);
817 Object *obedit = CTX_data_edit_object(C);
819 /* moving: is shown in drawobject() (transform color) */
821 // if(obedit || (t->flag & T_POSE) ) G.moving= G_TRANSFORM_EDIT;
822 // else if(G.f & G_PARTICLEEDIT) G.moving= G_TRANSFORM_PARTICLE;
823 // else G.moving= G_TRANSFORM_OBJ;
834 t->helpline = HLP_NONE;
838 t->redraw = 1; /* redraw first time */
842 t->imval[0] = event->x - t->ar->winrct.xmin;
843 t->imval[1] = event->y - t->ar->winrct.ymin;
845 t->event_type = event->type;
853 t->con.imval[0] = t->imval[0];
854 t->con.imval[1] = t->imval[1];
856 t->mval[0] = t->imval[0];
857 t->mval[1] = t->imval[1];
860 t->handleEvent = NULL;
876 t->spacetype = sa->spacetype;
877 if(t->spacetype == SPACE_VIEW3D)
879 View3D *v3d = sa->spacedata.first;
882 t->animtimer= CTX_wm_screen(C)->animtimer;
884 if(v3d->flag & V3D_ALIGN) t->flag |= T_V3D_ALIGN;
885 t->around = v3d->around;
887 if (op && RNA_struct_find_property(op->ptr, "constraint_axis") && RNA_property_is_set(op->ptr, "constraint_orientation"))
889 t->current_orientation = RNA_enum_get(op->ptr, "constraint_orientation");
891 if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C) - 1)
893 t->current_orientation = V3D_MANIP_GLOBAL;
898 t->current_orientation = v3d->twmode;
901 else if(t->spacetype==SPACE_IMAGE || t->spacetype==SPACE_NODE)
903 SpaceImage *sima = sa->spacedata.first;
904 // XXX for now, get View2D from the active region
906 t->around = sima->around;
910 // XXX for now, get View2D from the active region
913 t->around = V3D_CENTER;
916 if (op && RNA_struct_find_property(op->ptr, "mirror") && RNA_property_is_set(op->ptr, "mirror"))
918 if (RNA_boolean_get(op->ptr, "mirror"))
923 // Need stuff to take it from edit mesh or whatnot here
926 if (t->obedit && t->obedit->type == OB_MESH && ts->editbutflag & B_MESH_X_MIRROR)
932 /* setting PET flag */
933 if (op && RNA_struct_find_property(op->ptr, "proportional") && RNA_property_is_set(op->ptr, "proportional"))
935 switch(RNA_enum_get(op->ptr, "proportional"))
937 case 2: /* XXX connected constant */
938 t->flag |= T_PROP_CONNECTED;
939 case 1: /* XXX prop on constant */
940 t->flag |= T_PROP_EDIT;
946 if ((t->options & CTX_NO_PET) == 0 && (ts->proportional)) {
947 t->flag |= T_PROP_EDIT;
949 if(ts->proportional == 2)
950 t->flag |= T_PROP_CONNECTED; // yes i know, has to become define
954 if (op && RNA_struct_find_property(op->ptr, "proportional_size") && RNA_property_is_set(op->ptr, "proportional_size"))
956 t->prop_size = RNA_float_get(op->ptr, "proportional_size");
960 t->prop_size = ts->proportional_size;
963 if (op && RNA_struct_find_property(op->ptr, "proportional_editing_falloff") && RNA_property_is_set(op->ptr, "proportional_editing_falloff"))
965 t->prop_mode = RNA_enum_get(op->ptr, "proportional_editing_falloff");
969 t->prop_mode = ts->prop_mode;
972 /* TRANSFORM_FIX_ME rna restrictions */
973 if (t->prop_size <= 0)
978 setTransformViewMatrices(t);
979 initNumInput(&t->num);
980 initNDofInput(&t->ndof);
985 /* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
986 void postTrans (TransInfo *t)
992 ED_region_draw_cb_exit(t->ar->type, t->draw_handle);
995 /* postTrans can be called when nothing is selected, so data is NULL already */
999 /* since ipokeys are optional on objects, we mallocced them per trans-data */
1000 for(a=0, td= t->data; a<t->total; a++, td++) {
1001 if(td->tdi) MEM_freeN(td->tdi);
1002 if (td->flag & TD_BEZTRIPLE) MEM_freeN(td->hdata);
1007 if (t->ext) MEM_freeN(t->ext);
1009 MEM_freeN(t->data2d);
1013 if(t->spacetype==SPACE_IMAGE) {
1014 SpaceImage *sima= t->sa->spacedata.first;
1015 if(sima->flag & SI_LIVE_UNWRAP)
1016 ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL);
1018 else if(ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) {
1020 MEM_freeN(t->customData);
1024 void applyTransObjects(TransInfo *t)
1028 for (td = t->data; td < t->data + t->total; td++) {
1029 VECCOPY(td->iloc, td->loc);
1031 VECCOPY(td->ext->irot, td->ext->rot);
1033 if (td->ext->size) {
1034 VECCOPY(td->ext->isize, td->ext->size);
1040 /* helper for below */
1041 static void restore_ipokey(float *poin, float *old)
1050 static void restoreElement(TransData *td) {
1051 /* TransData for crease has no loc */
1053 VECCOPY(td->loc, td->iloc);
1056 *td->val = td->ival;
1058 if (td->ext && (td->flag&TD_NO_EXT)==0) {
1060 VECCOPY(td->ext->rot, td->ext->irot);
1062 if (td->ext->size) {
1063 VECCOPY(td->ext->size, td->ext->isize);
1065 if(td->flag & TD_USEQUAT) {
1066 if (td->ext->quat) {
1067 QUATCOPY(td->ext->quat, td->ext->iquat);
1072 if (td->flag & TD_BEZTRIPLE) {
1073 *(td->hdata->h1) = td->hdata->ih1;
1074 *(td->hdata->h2) = td->hdata->ih2;
1078 TransDataIpokey *tdi= td->tdi;
1080 restore_ipokey(tdi->locx, tdi->oldloc);
1081 restore_ipokey(tdi->locy, tdi->oldloc+1);
1082 restore_ipokey(tdi->locz, tdi->oldloc+2);
1084 restore_ipokey(tdi->rotx, tdi->oldrot);
1085 restore_ipokey(tdi->roty, tdi->oldrot+1);
1086 restore_ipokey(tdi->rotz, tdi->oldrot+2);
1088 restore_ipokey(tdi->sizex, tdi->oldsize);
1089 restore_ipokey(tdi->sizey, tdi->oldsize+1);
1090 restore_ipokey(tdi->sizez, tdi->oldsize+2);
1094 void restoreTransObjects(TransInfo *t)
1098 for (td = t->data; td < t->data + t->total; td++) {
1107 void calculateCenter2D(TransInfo *t)
1109 if (t->flag & (T_EDIT|T_POSE)) {
1110 Object *ob= t->obedit?t->obedit:t->poseobj;
1113 VECCOPY(vec, t->center);
1114 Mat4MulVecfl(ob->obmat, vec);
1115 projectIntView(t, vec, t->center2d);
1118 projectIntView(t, t->center, t->center2d);
1122 void calculateCenterCursor(TransInfo *t)
1126 cursor = give_cursor(t->scene, t->view);
1127 VECCOPY(t->center, cursor);
1129 /* If edit or pose mode, move cursor in local space */
1130 if (t->flag & (T_EDIT|T_POSE)) {
1131 Object *ob = t->obedit?t->obedit:t->poseobj;
1132 float mat[3][3], imat[3][3];
1134 VecSubf(t->center, t->center, ob->obmat[3]);
1135 Mat3CpyMat4(mat, ob->obmat);
1137 Mat3MulVecfl(imat, t->center);
1140 calculateCenter2D(t);
1143 void calculateCenterCursor2D(TransInfo *t)
1145 View2D *v2d= t->view;
1146 float aspx=1.0, aspy=1.0;
1148 if(t->spacetype==SPACE_IMAGE) /* only space supported right now but may change */
1149 ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
1152 t->center[0] = v2d->cursor[0] * aspx;
1153 t->center[1] = v2d->cursor[1] * aspy;
1156 calculateCenter2D(t);
1159 void calculateCenterMedian(TransInfo *t)
1161 float partial[3] = {0.0f, 0.0f, 0.0f};
1165 for(i = 0; i < t->total; i++) {
1166 if (t->data[i].flag & TD_SELECTED) {
1167 if (!(t->data[i].flag & TD_NOCENTER))
1169 VecAddf(partial, partial, t->data[i].center);
1175 All the selected elements are at the head of the array
1176 which means we can stop when it finds unselected data
1182 VecMulf(partial, 1.0f / total);
1183 VECCOPY(t->center, partial);
1185 calculateCenter2D(t);
1188 void calculateCenterBound(TransInfo *t)
1193 for(i = 0; i < t->total; i++) {
1195 if (t->data[i].flag & TD_SELECTED) {
1196 if (!(t->data[i].flag & TD_NOCENTER))
1197 MinMax3(min, max, t->data[i].center);
1201 All the selected elements are at the head of the array
1202 which means we can stop when it finds unselected data
1208 VECCOPY(max, t->data[i].center);
1209 VECCOPY(min, t->data[i].center);
1212 VecAddf(t->center, min, max);
1213 VecMulf(t->center, 0.5);
1215 calculateCenter2D(t);
1218 void calculateCenter(TransInfo *t)
1222 calculateCenterBound(t);
1225 calculateCenterMedian(t);
1228 if(t->spacetype==SPACE_IMAGE)
1229 calculateCenterCursor2D(t);
1231 calculateCenterCursor(t);
1234 /* Individual element center uses median center for helpline and such */
1235 calculateCenterMedian(t);
1239 /* set median, and if if if... do object center */
1240 #if 0 // TRANSFORM_FIX_ME
1242 /* EDIT MODE ACTIVE EDITMODE ELEMENT */
1244 if (t->obedit && t->obedit->type == OB_MESH && EM_get_actSelection(&ese)) {
1245 EM_editselection_center(t->center, &ese);
1246 calculateCenter2D(t);
1248 } /* END EDIT MODE ACTIVE ELEMENT */
1251 calculateCenterMedian(t);
1252 if((t->flag & (T_EDIT|T_POSE))==0)
1254 Scene *scene = t->scene;
1258 VECCOPY(t->center, ob->obmat[3]);
1259 projectIntView(t, t->center, t->center2d);
1266 /* setting constraint center */
1267 VECCOPY(t->con.center, t->center);
1268 if(t->flag & (T_EDIT|T_POSE))
1270 Object *ob= t->obedit?t->obedit:t->poseobj;
1271 Mat4MulVecfl(ob->obmat, t->con.center);
1274 /* voor panning from cameraview */
1275 if(t->flag & T_OBJECT)
1277 if(t->spacetype==SPACE_VIEW3D)
1279 View3D *v3d = t->view;
1280 Scene *scene = t->scene;
1281 RegionView3D *rv3d = t->ar->regiondata;
1283 if(v3d->camera == OBACT && rv3d->persp==V3D_CAMOB)
1286 /* persinv is nasty, use viewinv instead, always right */
1287 VECCOPY(axis, t->viewinv[2]);
1290 /* 6.0 = 6 grid units */
1291 axis[0]= t->center[0]- 6.0f*axis[0];
1292 axis[1]= t->center[1]- 6.0f*axis[1];
1293 axis[2]= t->center[2]- 6.0f*axis[2];
1295 projectIntView(t, axis, t->center2d);
1297 /* rotate only needs correct 2d center, grab needs initgrabz() value */
1298 if(t->mode==TFM_TRANSLATION)
1300 VECCOPY(t->center, axis);
1301 VECCOPY(t->con.center, t->center);
1307 if(t->spacetype==SPACE_VIEW3D)
1309 /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d_delta() */
1310 if(t->flag & (T_EDIT|T_POSE)) {
1311 Object *ob= t->obedit?t->obedit:t->poseobj;
1314 VECCOPY(vec, t->center);
1315 Mat4MulVecfl(ob->obmat, vec);
1316 initgrabz(t->ar->regiondata, vec[0], vec[1], vec[2]);
1319 initgrabz(t->ar->regiondata, t->center[0], t->center[1], t->center[2]);
1324 void calculatePropRatio(TransInfo *t)
1326 TransData *td = t->data;
1329 short connected = t->flag & T_PROP_CONNECTED;
1331 if (t->flag & T_PROP_EDIT) {
1332 for(i = 0 ; i < t->total; i++, td++) {
1333 if (td->flag & TD_SELECTED) {
1336 else if ((connected &&
1337 (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size))
1340 td->rdist > t->prop_size)) {
1342 The elements are sorted according to their dist member in the array,
1343 that means we can stop when it finds one element outside of the propsize.
1345 td->flag |= TD_NOACTION;
1350 /* Use rdist for falloff calculations, it is the real distance */
1351 td->flag &= ~TD_NOACTION;
1352 dist= (t->prop_size-td->rdist)/t->prop_size;
1355 * Clamp to positive numbers.
1356 * Certain corner cases with connectivity and individual centers
1357 * can give values of rdist larger than propsize.
1362 switch(t->prop_mode) {
1364 td->factor= dist*dist;
1367 td->factor= 3.0f*dist*dist - 2.0f*dist*dist*dist;
1370 td->factor = (float)sqrt(dist);
1379 td->factor = (float)sqrt(2*dist - dist * dist);
1382 BLI_srand( BLI_rand() ); /* random seed */
1383 td->factor = BLI_frand()*dist;
1390 switch(t->prop_mode) {
1392 strcpy(t->proptext, "(Sharp)");
1395 strcpy(t->proptext, "(Smooth)");
1398 strcpy(t->proptext, "(Root)");
1401 strcpy(t->proptext, "(Linear)");
1404 strcpy(t->proptext, "(Constant)");
1407 strcpy(t->proptext, "(Sphere)");
1410 strcpy(t->proptext, "(Random)");
1413 strcpy(t->proptext, "");
1417 for(i = 0 ; i < t->total; i++, td++) {
1420 strcpy(t->proptext, "");
1424 float get_drawsize(ARegion *ar, float *co)
1426 RegionView3D *rv3d= ar->regiondata;
1427 float size, vec[3], len1, len2;
1429 /* size calculus, depending ortho/persp settings, like initgrabz() */
1430 size= rv3d->persmat[0][3]*co[0]+ rv3d->persmat[1][3]*co[1]+ rv3d->persmat[2][3]*co[2]+ rv3d->persmat[3][3];
1432 VECCOPY(vec, rv3d->persinv[0]);
1433 len1= Normalize(vec);
1434 VECCOPY(vec, rv3d->persinv[1]);
1435 len2= Normalize(vec);
1437 size*= 0.01f*(len1>len2?len1:len2);
1439 /* correct for window size to make widgets appear fixed size */
1440 if(ar->winx > ar->winy) size*= 1000.0f/(float)ar->winx;
1441 else size*= 1000.0f/(float)ar->winy;