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 /* called for updating while transform acts, once per redraw */
268 void recalcData(TransInfo *t)
270 Scene *scene = t->scene;
275 else if(G.f & G_PARTICLEEDIT) {
276 flushTransParticles(t);
278 if (t->spacetype==SPACE_NODE) {
281 else if (t->spacetype==SPACE_SEQ) {
284 else if (t->spacetype == SPACE_IPO) {
285 SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first;
288 ListBase anim_data = {NULL, NULL};
296 /* initialise relevant anim-context 'context' data from TransInfo data */
297 /* NOTE: sync this with the code in ANIM_animdata_get_context() */
298 memset(&ac, 0, sizeof(bAnimContext));
300 scene= ac.scene= t->scene;
304 ac.spacetype= (t->sa)? t->sa->spacetype : 0;
305 ac.regiontype= (t->ar)? t->ar->regiontype : 0;
307 ANIM_animdata_context_getdata(&ac);
309 /* do the flush first */
310 flushTransGraphData(t);
312 /* get curves to check if a re-sort is needed */
313 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY | ANIMFILTER_CURVEVISIBLE);
314 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
316 /* now test if there is a need to re-sort */
317 for (ale= anim_data.first; ale; ale= ale->next) {
318 FCurve *fcu= (FCurve *)ale->key_data;
320 /* watch it: if the time is wrong: do not correct handles yet */
321 if (test_time_fcurve(fcu))
324 calchandles_fcurve(fcu);
327 /* do resort and other updates? */
328 if (dosort) remake_graph_transdata(t, &anim_data);
329 //if (sipo->showkey) update_ipokey_val();
331 /* now free temp channels */
332 BLI_freelistN(&anim_data);
334 /* update realtime - not working? */
339 else if (t->spacetype == SPACE_NLA) {
340 TransDataNla *tdn= (TransDataNla *)t->customData;
341 SpaceNla *snla= (SpaceNla *)t->sa->spacedata.first;
342 Scene *scene= t->scene;
346 /* for each strip we've got, perform some additional validation of the values that got set before
347 * using RNA to set the value (which does some special operations when setting these values to make
348 * sure that everything works ok)
350 for (i = 0; i < t->total; i++, tdn++) {
351 NlaStrip *strip= tdn->strip;
352 PointerRNA strip_ptr;
353 short pExceeded, nExceeded, iter;
354 int delta_y1, delta_y2;
356 /* if this tdn has no handles, that means it is just a dummy that should be skipped */
357 if (tdn->handle == 0)
360 /* if cancelling transform, just write the values without validating, then move on */
361 if (t->state == TRANS_CANCEL) {
362 /* clear the values by directly overwriting the originals, but also need to restore
363 * endpoints of neighboring transition-strips
367 strip->start= tdn->h1[0];
369 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION))
370 strip->prev->end= tdn->h1[0];
373 strip->end= tdn->h2[0];
375 if ((strip->next) && (strip->next->type == NLASTRIP_TYPE_TRANSITION))
376 strip->next->start= tdn->h2[0];
378 /* flush transforms to child strips (since this should be a meta) */
379 BKE_nlameta_flush_transforms(strip);
381 /* restore to original track (if needed) */
382 if (tdn->oldTrack != tdn->nlt) {
383 /* just append to end of list for now, since strips get sorted in special_aftertrans_update() */
384 BLI_remlink(&tdn->nlt->strips, strip);
385 BLI_addtail(&tdn->oldTrack->strips, strip);
391 /* firstly, check if the proposed transform locations would overlap with any neighbouring strips
392 * (barring transitions) which are absolute barriers since they are not being moved
394 * this is done as a iterative procedure (done 5 times max for now)
396 for (iter=0; iter < 5; iter++) {
397 pExceeded= ((strip->prev) && (strip->prev->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h1[0] < strip->prev->end));
398 nExceeded= ((strip->next) && (strip->next->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h2[0] > strip->next->start));
400 if ((pExceeded && nExceeded) || (iter == 4) ) {
401 /* both endpoints exceeded (or iteration ping-pong'd meaning that we need a compromise)
402 * - simply crop strip to fit within the bounds of the strips bounding it
403 * - if there were no neighbours, clear the transforms (make it default to the strip's current values)
405 if (strip->prev && strip->next) {
406 tdn->h1[0]= strip->prev->end;
407 tdn->h2[0]= strip->next->start;
410 tdn->h1[0]= strip->start;
411 tdn->h2[0]= strip->end;
414 else if (nExceeded) {
416 float offset= tdn->h2[0] - strip->next->start;
418 tdn->h1[0] -= offset;
419 tdn->h2[0] -= offset;
421 else if (pExceeded) {
423 float offset= strip->prev->end - tdn->h1[0];
425 tdn->h1[0] += offset;
426 tdn->h2[0] += offset;
428 else /* all is fine and well */
432 /* handle auto-snapping */
433 switch (snla->autosnap) {
434 case SACTSNAP_FRAME: /* snap to nearest frame/time */
435 if (snla->flag & SNLA_DRAWTIME) {
436 tdn->h1[0]= (float)( floor((tdn->h1[0]/secf) + 0.5f) * secf );
437 tdn->h2[0]= (float)( floor((tdn->h2[0]/secf) + 0.5f) * secf );
440 tdn->h1[0]= (float)( floor(tdn->h1[0]+0.5f) );
441 tdn->h2[0]= (float)( floor(tdn->h2[0]+0.5f) );
445 case SACTSNAP_MARKER: /* snap to nearest marker */
446 tdn->h1[0]= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h1[0]);
447 tdn->h2[0]= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h2[0]);
451 /* use RNA to write the values... */
452 // TODO: do we need to write in 2 passes to make sure that no truncation goes on?
453 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
455 RNA_float_set(&strip_ptr, "start_frame", tdn->h1[0]);
456 RNA_float_set(&strip_ptr, "end_frame", tdn->h2[0]);
458 /* flush transforms to child strips (since this should be a meta) */
459 BKE_nlameta_flush_transforms(strip);
462 /* now, check if we need to try and move track
463 * - we need to calculate both, as only one may have been altered by transform if only 1 handle moved
465 delta_y1= ((int)tdn->h1[1] / NLACHANNEL_STEP - tdn->trackIndex);
466 delta_y2= ((int)tdn->h2[1] / NLACHANNEL_STEP - tdn->trackIndex);
468 if (delta_y1 || delta_y2) {
470 int delta = (delta_y2) ? delta_y2 : delta_y1;
473 /* move in the requested direction, checking at each layer if there's space for strip to pass through,
474 * stopping on the last track available or that we're able to fit in
477 for (track=tdn->nlt->next, n=0; (track) && (n < delta); track=track->next, n++) {
478 /* check if space in this track for the strip */
479 if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
480 /* move strip to this track */
481 BLI_remlink(&tdn->nlt->strips, strip);
482 BKE_nlatrack_add_strip(track, strip);
485 tdn->trackIndex += (n + 1); /* + 1, since n==0 would mean that we didn't change track */
487 else /* can't move any further */
492 /* make delta 'positive' before using it, since we now know to go backwards */
495 for (track=tdn->nlt->prev, n=0; (track) && (n < delta); track=track->prev, n++) {
496 /* check if space in this track for the strip */
497 if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
498 /* move strip to this track */
499 BLI_remlink(&tdn->nlt->strips, strip);
500 BKE_nlatrack_add_strip(track, strip);
503 tdn->trackIndex -= (n - 1); /* - 1, since n==0 would mean that we didn't change track */
505 else /* can't move any further */
512 else if (t->obedit) {
513 if ELEM(t->obedit->type, OB_CURVE, OB_SURF) {
514 Curve *cu= t->obedit->data;
515 Nurb *nu= cu->editnurb->first;
517 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
519 if (t->state == TRANS_CANCEL) {
521 calchandlesNurb(nu); /* Cant do testhandlesNurb here, it messes up the h1 and h2 flags */
525 /* Normal updating */
531 /* TRANSFORM_FIX_ME */
535 else if(t->obedit->type==OB_LATTICE) {
536 Lattice *la= t->obedit->data;
537 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
539 if(la->editlatt->flag & LT_OUTSIDE) outside_lattice(la->editlatt);
541 else if (t->obedit->type == OB_MESH) {
542 if(t->spacetype==SPACE_IMAGE) {
543 SpaceImage *sima= t->sa->spacedata.first;
546 if(sima->flag & SI_LIVE_UNWRAP)
547 ED_uvedit_live_unwrap_re_solve();
549 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA);
551 EditMesh *em = ((Mesh*)t->obedit->data)->edit_mesh;
552 /* mirror modifier clipping? */
553 if(t->state != TRANS_CANCEL) {
554 /* TRANSFORM_FIX_ME */
555 // if ((G.qual & LR_CTRLKEY)==0) {
556 // /* Only retopo if not snapping, Note, this is the only case of G.qual being used, but we have no T_SHIFT_MOD - Campbell */
559 clipMirrorModifier(t, t->obedit);
561 if((t->options & CTX_NO_MIRROR) == 0 && (t->flag & T_MIRROR))
562 editmesh_apply_to_mirror(t);
564 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
566 recalc_editnormals(em);
569 else if(t->obedit->type==OB_ARMATURE) { /* no recalc flag, does pose */
570 bArmature *arm= t->obedit->data;
571 ListBase *edbo = arm->edbo;
573 TransData *td = t->data;
576 /* Ensure all bones are correctly adjusted */
577 for (ebo = edbo->first; ebo; ebo = ebo->next){
579 if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
580 /* If this bone has a parent tip that has been moved */
581 if (ebo->parent->flag & BONE_TIPSEL){
582 VECCOPY (ebo->head, ebo->parent->tail);
583 if(t->mode==TFM_BONE_ENVELOPE) ebo->rad_head= ebo->parent->rad_tail;
585 /* If this bone has a parent tip that has NOT been moved */
587 VECCOPY (ebo->parent->tail, ebo->head);
588 if(t->mode==TFM_BONE_ENVELOPE) ebo->parent->rad_tail= ebo->rad_head;
592 /* on extrude bones, oldlength==0.0f, so we scale radius of points */
593 ebo->length= VecLenf(ebo->head, ebo->tail);
594 if(ebo->oldlength==0.0f) {
595 ebo->rad_head= 0.25f*ebo->length;
596 ebo->rad_tail= 0.10f*ebo->length;
597 ebo->dist= 0.25f*ebo->length;
599 if(ebo->rad_head > ebo->parent->rad_tail)
600 ebo->rad_head= ebo->parent->rad_tail;
603 else if(t->mode!=TFM_BONE_ENVELOPE) {
604 /* if bones change length, lets do that for the deform distance as well */
605 ebo->dist*= ebo->length/ebo->oldlength;
606 ebo->rad_head*= ebo->length/ebo->oldlength;
607 ebo->rad_tail*= ebo->length/ebo->oldlength;
608 ebo->oldlength= ebo->length;
613 if (t->mode != TFM_BONE_ROLL)
616 for(i = 0; i < t->total; i++, td++)
620 float vec[3], up_axis[3];
624 VECCOPY(up_axis, td->axismtx[2]);
626 if (t->mode != TFM_ROTATION)
628 VecSubf(vec, ebo->tail, ebo->head);
630 RotationBetweenVectorsToQuat(qrot, td->axismtx[1], vec);
631 QuatMulVecf(qrot, up_axis);
635 Mat3MulVecfl(t->mat, up_axis);
638 ebo->roll = ED_rollBoneToVector(ebo, up_axis);
643 if(arm->flag & ARM_MIRROR_EDIT)
644 transform_armature_mirror_update(t->obedit);
648 DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
650 else if( (t->flag & T_POSE) && t->poseobj) {
651 Object *ob= t->poseobj;
652 bArmature *arm= ob->data;
654 /* if animtimer is running, and the object already has animation data,
655 * check if the auto-record feature means that we should record 'samples'
656 * (i.e. uneditable animation values)
658 // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
659 // TODO: maybe the ob->adt check isn't really needed? makes it too difficult to use...
660 if (/*(ob->adt) && */(t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
661 short targetless_ik= (t->flag & T_AUTOIK); // XXX this currently doesn't work, since flags aren't set yet!
662 autokeyframe_pose_cb_func(t->scene, (View3D *)t->view, ob, t->mode, targetless_ik);
665 /* old optimize trick... this enforces to bypass the depgraph */
666 if (!(arm->flag & ARM_DELAYDEFORM)) {
667 DAG_object_flush_update(scene, ob, OB_RECALC_DATA); /* sets recalc flags */
670 where_is_pose(scene, ob);
673 for(base= FIRSTBASE; base; base= base->next) {
674 Object *ob= base->object;
676 /* this flag is from depgraph, was stored in initialize phase, handled in drawview.c */
677 if(base->flag & BA_HAS_RECALC_OB)
678 ob->recalc |= OB_RECALC_OB;
679 if(base->flag & BA_HAS_RECALC_DATA)
680 ob->recalc |= OB_RECALC_DATA;
682 /* if object/base is selected */
683 if ((base->flag & SELECT) || (ob->flag & SELECT)) {
684 /* if animtimer is running, and the object already has animation data,
685 * check if the auto-record feature means that we should record 'samples'
686 * (i.e. uneditable animation values)
688 // TODO: autokeyframe calls need some setting to specify to add samples (FPoints) instead of keyframes?
689 // TODO: maybe the ob->adt check isn't really needed? makes it too difficult to use...
690 if (/*(ob->adt) && */(t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
691 autokeyframe_ob_cb_func(t->scene, (View3D *)t->view, ob, t->mode);
695 /* proxy exception */
697 ob->proxy->recalc |= ob->recalc;
699 group_tag_recalc(ob->proxy_group->dup_group);
703 /* update shaded drawmode while transform */
704 if(t->spacetype==SPACE_VIEW3D && ((View3D*)t->view)->drawtype == OB_SHADED)
705 reshadeall_displist(t->scene);
708 void drawLine(TransInfo *t, float *center, float *dir, char axis, short options)
710 float v1[3], v2[3], v3[3];
711 char col[3], col2[3];
713 if (t->spacetype == SPACE_VIEW3D)
715 View3D *v3d = t->view;
719 //if(t->obedit) glLoadMatrixf(t->obedit->obmat); // sets opengl viewing
723 VecMulf(v3, v3d->far);
725 VecSubf(v2, center, v3);
726 VecAddf(v1, center, v3);
728 if (options & DRAWLIGHT) {
729 col[0] = col[1] = col[2] = 220;
732 UI_GetThemeColor3ubv(TH_GRID, col);
734 UI_make_axis_color(col, col2, axis);
735 glColor3ubv((GLubyte *)col2);
738 glBegin(GL_LINE_STRIP);
747 void resetTransRestrictions(TransInfo *t)
749 t->flag &= ~T_ALL_RESTRICTIONS;
752 int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
754 Scene *sce = CTX_data_scene(C);
755 ToolSettings *ts = CTX_data_tool_settings(C);
756 ARegion *ar = CTX_wm_region(C);
757 ScrArea *sa = CTX_wm_area(C);
758 Object *obedit = CTX_data_edit_object(C);
760 /* moving: is shown in drawobject() (transform color) */
762 // if(obedit || (t->flag & T_POSE) ) G.moving= G_TRANSFORM_EDIT;
763 // else if(G.f & G_PARTICLEEDIT) G.moving= G_TRANSFORM_PARTICLE;
764 // else G.moving= G_TRANSFORM_OBJ;
775 t->helpline = HLP_NONE;
779 t->redraw = 1; /* redraw first time */
783 t->imval[0] = event->x - t->ar->winrct.xmin;
784 t->imval[1] = event->y - t->ar->winrct.ymin;
786 t->event_type = event->type;
794 t->con.imval[0] = t->imval[0];
795 t->con.imval[1] = t->imval[1];
797 t->mval[0] = t->imval[0];
798 t->mval[1] = t->imval[1];
801 t->handleEvent = NULL;
817 t->spacetype = sa->spacetype;
818 if(t->spacetype == SPACE_VIEW3D)
820 View3D *v3d = sa->spacedata.first;
823 t->animtimer= CTX_wm_screen(C)->animtimer;
825 if(v3d->flag & V3D_ALIGN) t->flag |= T_V3D_ALIGN;
826 t->around = v3d->around;
828 if (op && RNA_struct_find_property(op->ptr, "constraint_axis") && RNA_property_is_set(op->ptr, "constraint_orientation"))
830 t->current_orientation = RNA_int_get(op->ptr, "constraint_orientation");
832 if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C) - 1)
834 t->current_orientation = V3D_MANIP_GLOBAL;
839 t->current_orientation = v3d->twmode;
842 else if(t->spacetype==SPACE_IMAGE || t->spacetype==SPACE_NODE)
844 SpaceImage *sima = sa->spacedata.first;
845 // XXX for now, get View2D from the active region
847 t->around = sima->around;
851 // XXX for now, get View2D from the active region
854 t->around = V3D_CENTER;
857 if (op && RNA_struct_find_property(op->ptr, "mirror") && RNA_property_is_set(op->ptr, "mirror"))
859 if (RNA_boolean_get(op->ptr, "mirror"))
864 // Need stuff to take it from edit mesh or whatnot here
867 if (t->obedit && t->obedit->type == OB_MESH && ts->editbutflag & B_MESH_X_MIRROR)
873 /* setting PET flag */
874 if (op && RNA_struct_find_property(op->ptr, "proportional") && RNA_property_is_set(op->ptr, "proportional"))
876 switch(RNA_enum_get(op->ptr, "proportional"))
878 case 2: /* XXX connected constant */
879 t->flag |= T_PROP_CONNECTED;
880 case 1: /* XXX prop on constant */
881 t->flag |= T_PROP_EDIT;
887 if ((t->options & CTX_NO_PET) == 0 && (ts->proportional)) {
888 t->flag |= T_PROP_EDIT;
890 if(ts->proportional == 2)
891 t->flag |= T_PROP_CONNECTED; // yes i know, has to become define
895 if (op && RNA_struct_find_property(op->ptr, "proportional_size") && RNA_property_is_set(op->ptr, "proportional_size"))
897 t->prop_size = RNA_float_get(op->ptr, "proportional_size");
901 t->prop_size = ts->proportional_size;
904 if (op && RNA_struct_find_property(op->ptr, "proportional_editing_falloff") && RNA_property_is_set(op->ptr, "proportional_editing_falloff"))
906 t->prop_mode = RNA_enum_get(op->ptr, "proportional_editing_falloff");
910 t->prop_mode = ts->prop_mode;
913 /* TRANSFORM_FIX_ME rna restrictions */
914 if (t->prop_size <= 0)
919 setTransformViewMatrices(t);
920 initNumInput(&t->num);
921 initNDofInput(&t->ndof);
926 /* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
927 void postTrans (TransInfo *t)
933 ED_region_draw_cb_exit(t->ar->type, t->draw_handle);
936 /* postTrans can be called when nothing is selected, so data is NULL already */
940 /* since ipokeys are optional on objects, we mallocced them per trans-data */
941 for(a=0, td= t->data; a<t->total; a++, td++) {
942 if(td->tdi) MEM_freeN(td->tdi);
943 if (td->flag & TD_BEZTRIPLE) MEM_freeN(td->hdata);
948 if (t->ext) MEM_freeN(t->ext);
950 MEM_freeN(t->data2d);
954 if(t->spacetype==SPACE_IMAGE) {
955 SpaceImage *sima= t->sa->spacedata.first;
956 if(sima->flag & SI_LIVE_UNWRAP)
957 ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL);
959 else if(ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) {
961 MEM_freeN(t->customData);
965 void applyTransObjects(TransInfo *t)
969 for (td = t->data; td < t->data + t->total; td++) {
970 VECCOPY(td->iloc, td->loc);
972 VECCOPY(td->ext->irot, td->ext->rot);
975 VECCOPY(td->ext->isize, td->ext->size);
981 /* helper for below */
982 static void restore_ipokey(float *poin, float *old)
991 static void restoreElement(TransData *td) {
992 /* TransData for crease has no loc */
994 VECCOPY(td->loc, td->iloc);
999 if (td->ext && (td->flag&TD_NO_EXT)==0) {
1001 VECCOPY(td->ext->rot, td->ext->irot);
1003 if (td->ext->size) {
1004 VECCOPY(td->ext->size, td->ext->isize);
1006 if(td->flag & TD_USEQUAT) {
1007 if (td->ext->quat) {
1008 QUATCOPY(td->ext->quat, td->ext->iquat);
1013 if (td->flag & TD_BEZTRIPLE) {
1014 *(td->hdata->h1) = td->hdata->ih1;
1015 *(td->hdata->h2) = td->hdata->ih2;
1019 TransDataIpokey *tdi= td->tdi;
1021 restore_ipokey(tdi->locx, tdi->oldloc);
1022 restore_ipokey(tdi->locy, tdi->oldloc+1);
1023 restore_ipokey(tdi->locz, tdi->oldloc+2);
1025 restore_ipokey(tdi->rotx, tdi->oldrot);
1026 restore_ipokey(tdi->roty, tdi->oldrot+1);
1027 restore_ipokey(tdi->rotz, tdi->oldrot+2);
1029 restore_ipokey(tdi->sizex, tdi->oldsize);
1030 restore_ipokey(tdi->sizey, tdi->oldsize+1);
1031 restore_ipokey(tdi->sizez, tdi->oldsize+2);
1035 void restoreTransObjects(TransInfo *t)
1039 for (td = t->data; td < t->data + t->total; td++) {
1048 void calculateCenter2D(TransInfo *t)
1050 if (t->flag & (T_EDIT|T_POSE)) {
1051 Object *ob= t->obedit?t->obedit:t->poseobj;
1054 VECCOPY(vec, t->center);
1055 Mat4MulVecfl(ob->obmat, vec);
1056 projectIntView(t, vec, t->center2d);
1059 projectIntView(t, t->center, t->center2d);
1063 void calculateCenterCursor(TransInfo *t)
1067 cursor = give_cursor(t->scene, t->view);
1068 VECCOPY(t->center, cursor);
1070 /* If edit or pose mode, move cursor in local space */
1071 if (t->flag & (T_EDIT|T_POSE)) {
1072 Object *ob = t->obedit?t->obedit:t->poseobj;
1073 float mat[3][3], imat[3][3];
1075 VecSubf(t->center, t->center, ob->obmat[3]);
1076 Mat3CpyMat4(mat, ob->obmat);
1078 Mat3MulVecfl(imat, t->center);
1081 calculateCenter2D(t);
1084 void calculateCenterCursor2D(TransInfo *t)
1086 View2D *v2d= t->view;
1087 float aspx=1.0, aspy=1.0;
1089 if(t->spacetype==SPACE_IMAGE) /* only space supported right now but may change */
1090 ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
1093 t->center[0] = v2d->cursor[0] * aspx;
1094 t->center[1] = v2d->cursor[1] * aspy;
1097 calculateCenter2D(t);
1100 void calculateCenterMedian(TransInfo *t)
1102 float partial[3] = {0.0f, 0.0f, 0.0f};
1106 for(i = 0; i < t->total; i++) {
1107 if (t->data[i].flag & TD_SELECTED) {
1108 if (!(t->data[i].flag & TD_NOCENTER))
1110 VecAddf(partial, partial, t->data[i].center);
1116 All the selected elements are at the head of the array
1117 which means we can stop when it finds unselected data
1123 VecMulf(partial, 1.0f / total);
1124 VECCOPY(t->center, partial);
1126 calculateCenter2D(t);
1129 void calculateCenterBound(TransInfo *t)
1134 for(i = 0; i < t->total; i++) {
1136 if (t->data[i].flag & TD_SELECTED) {
1137 if (!(t->data[i].flag & TD_NOCENTER))
1138 MinMax3(min, max, t->data[i].center);
1142 All the selected elements are at the head of the array
1143 which means we can stop when it finds unselected data
1149 VECCOPY(max, t->data[i].center);
1150 VECCOPY(min, t->data[i].center);
1153 VecAddf(t->center, min, max);
1154 VecMulf(t->center, 0.5);
1156 calculateCenter2D(t);
1159 void calculateCenter(TransInfo *t)
1163 calculateCenterBound(t);
1166 calculateCenterMedian(t);
1169 if(t->spacetype==SPACE_IMAGE)
1170 calculateCenterCursor2D(t);
1172 calculateCenterCursor(t);
1175 /* Individual element center uses median center for helpline and such */
1176 calculateCenterMedian(t);
1180 /* set median, and if if if... do object center */
1181 #if 0 // TRANSFORM_FIX_ME
1183 /* EDIT MODE ACTIVE EDITMODE ELEMENT */
1185 if (t->obedit && t->obedit->type == OB_MESH && EM_get_actSelection(&ese)) {
1186 EM_editselection_center(t->center, &ese);
1187 calculateCenter2D(t);
1189 } /* END EDIT MODE ACTIVE ELEMENT */
1192 calculateCenterMedian(t);
1193 if((t->flag & (T_EDIT|T_POSE))==0)
1195 Scene *scene = t->scene;
1199 VECCOPY(t->center, ob->obmat[3]);
1200 projectIntView(t, t->center, t->center2d);
1207 /* setting constraint center */
1208 VECCOPY(t->con.center, t->center);
1209 if(t->flag & (T_EDIT|T_POSE))
1211 Object *ob= t->obedit?t->obedit:t->poseobj;
1212 Mat4MulVecfl(ob->obmat, t->con.center);
1215 /* voor panning from cameraview */
1216 if(t->flag & T_OBJECT)
1218 if(t->spacetype==SPACE_VIEW3D)
1220 View3D *v3d = t->view;
1221 Scene *scene = t->scene;
1222 RegionView3D *rv3d = t->ar->regiondata;
1224 if(v3d->camera == OBACT && rv3d->persp==V3D_CAMOB)
1227 /* persinv is nasty, use viewinv instead, always right */
1228 VECCOPY(axis, t->viewinv[2]);
1231 /* 6.0 = 6 grid units */
1232 axis[0]= t->center[0]- 6.0f*axis[0];
1233 axis[1]= t->center[1]- 6.0f*axis[1];
1234 axis[2]= t->center[2]- 6.0f*axis[2];
1236 projectIntView(t, axis, t->center2d);
1238 /* rotate only needs correct 2d center, grab needs initgrabz() value */
1239 if(t->mode==TFM_TRANSLATION)
1241 VECCOPY(t->center, axis);
1242 VECCOPY(t->con.center, t->center);
1248 if(t->spacetype==SPACE_VIEW3D)
1250 /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d_delta() */
1251 if(t->flag & (T_EDIT|T_POSE)) {
1252 Object *ob= t->obedit?t->obedit:t->poseobj;
1255 VECCOPY(vec, t->center);
1256 Mat4MulVecfl(ob->obmat, vec);
1257 initgrabz(t->ar->regiondata, vec[0], vec[1], vec[2]);
1260 initgrabz(t->ar->regiondata, t->center[0], t->center[1], t->center[2]);
1265 void calculatePropRatio(TransInfo *t)
1267 TransData *td = t->data;
1270 short connected = t->flag & T_PROP_CONNECTED;
1272 if (t->flag & T_PROP_EDIT) {
1273 for(i = 0 ; i < t->total; i++, td++) {
1274 if (td->flag & TD_SELECTED) {
1277 else if ((connected &&
1278 (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size))
1281 td->rdist > t->prop_size)) {
1283 The elements are sorted according to their dist member in the array,
1284 that means we can stop when it finds one element outside of the propsize.
1286 td->flag |= TD_NOACTION;
1291 /* Use rdist for falloff calculations, it is the real distance */
1292 td->flag &= ~TD_NOACTION;
1293 dist= (t->prop_size-td->rdist)/t->prop_size;
1296 * Clamp to positive numbers.
1297 * Certain corner cases with connectivity and individual centers
1298 * can give values of rdist larger than propsize.
1303 switch(t->prop_mode) {
1305 td->factor= dist*dist;
1308 td->factor= 3.0f*dist*dist - 2.0f*dist*dist*dist;
1311 td->factor = (float)sqrt(dist);
1320 td->factor = (float)sqrt(2*dist - dist * dist);
1323 BLI_srand( BLI_rand() ); /* random seed */
1324 td->factor = BLI_frand()*dist;
1331 switch(t->prop_mode) {
1333 strcpy(t->proptext, "(Sharp)");
1336 strcpy(t->proptext, "(Smooth)");
1339 strcpy(t->proptext, "(Root)");
1342 strcpy(t->proptext, "(Linear)");
1345 strcpy(t->proptext, "(Constant)");
1348 strcpy(t->proptext, "(Sphere)");
1351 strcpy(t->proptext, "(Random)");
1354 strcpy(t->proptext, "");
1358 for(i = 0 ; i < t->total; i++, td++) {
1361 strcpy(t->proptext, "");
1365 float get_drawsize(ARegion *ar, float *co)
1367 RegionView3D *rv3d= ar->regiondata;
1368 float size, vec[3], len1, len2;
1370 /* size calculus, depending ortho/persp settings, like initgrabz() */
1371 size= rv3d->persmat[0][3]*co[0]+ rv3d->persmat[1][3]*co[1]+ rv3d->persmat[2][3]*co[2]+ rv3d->persmat[3][3];
1373 VECCOPY(vec, rv3d->persinv[0]);
1374 len1= Normalize(vec);
1375 VECCOPY(vec, rv3d->persinv[1]);
1376 len2= Normalize(vec);
1378 size*= 0.01f*(len1>len2?len1:len2);
1380 /* correct for window size to make widgets appear fixed size */
1381 if(ar->winx > ar->winy) size*= 1000.0f/(float)ar->winx;
1382 else size*= 1000.0f/(float)ar->winy;