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 *****
38 #include "MEM_guardedalloc.h"
40 #include "DNA_anim_types.h"
41 #include "DNA_action_types.h"
42 #include "DNA_armature_types.h"
43 #include "DNA_camera_types.h"
44 #include "DNA_curve_types.h"
45 #include "DNA_effect_types.h"
46 #include "DNA_image_types.h"
47 #include "DNA_key_types.h"
48 #include "DNA_lamp_types.h"
49 #include "DNA_lattice_types.h"
50 #include "DNA_mesh_types.h"
51 #include "DNA_meshdata_types.h"
52 #include "DNA_meta_types.h"
53 #include "DNA_modifier_types.h"
54 #include "DNA_nla_types.h"
55 #include "DNA_node_types.h"
56 #include "DNA_object_types.h"
57 #include "DNA_object_force.h"
58 #include "DNA_particle_types.h"
59 #include "DNA_scene_types.h"
60 #include "DNA_screen_types.h"
61 #include "DNA_space_types.h"
62 #include "DNA_sequence_types.h"
63 #include "DNA_texture_types.h"
64 #include "DNA_view3d_types.h"
65 #include "DNA_world_types.h"
66 #include "DNA_userdef_types.h"
67 #include "DNA_property_types.h"
68 #include "DNA_vfont_types.h"
69 #include "DNA_constraint_types.h"
70 #include "DNA_listBase.h"
71 #include "DNA_gpencil_types.h"
73 #include "BKE_action.h"
74 #include "BKE_armature.h"
75 #include "BKE_blender.h"
76 #include "BKE_cloth.h"
77 #include "BKE_context.h"
78 #include "BKE_curve.h"
79 #include "BKE_constraint.h"
80 #include "BKE_depsgraph.h"
81 #include "BKE_displist.h"
82 #include "BKE_DerivedMesh.h"
83 #include "BKE_effect.h"
85 #include "BKE_fcurve.h"
86 #include "BKE_global.h"
87 #include "BKE_lattice.h"
90 #include "BKE_mball.h"
92 #include "BKE_modifier.h"
93 #include "BKE_object.h"
94 #include "BKE_particle.h"
95 #include "BKE_sequence.h"
96 #include "BKE_pointcache.h"
97 #include "BKE_softbody.h"
98 #include "BKE_utildefines.h"
99 #include "BKE_bmesh.h"
100 #include "BKE_context.h"
101 #include "BKE_report.h"
103 //#include "BIF_editaction.h"
104 //#include "BIF_editview.h"
105 //#include "BIF_editlattice.h"
106 //#include "BIF_editconstraint.h"
107 //#include "BIF_editmesh.h"
108 //#include "BIF_editnla.h"
109 //#include "BIF_editsima.h"
110 //#include "BIF_editparticle.h"
112 //#include "BIF_keyframing.h"
113 //#include "BIF_poseobject.h"
114 //#include "BIF_meshtools.h"
115 //#include "BIF_mywindow.h"
116 //#include "BIF_resources.h"
117 #include "BIF_retopo.h"
118 //#include "BIF_screen.h"
119 //#include "BIF_space.h"
120 //#include "BIF_toolbox.h"
122 #include "ED_anim_api.h"
123 #include "ED_armature.h"
124 #include "ED_particle.h"
125 #include "ED_image.h"
126 #include "ED_keyframing.h"
127 #include "ED_keyframes_edit.h"
128 #include "ED_object.h"
130 #include "ED_types.h"
131 #include "ED_uvedit.h"
132 #include "ED_view3d.h"
134 #include "UI_view2d.h"
136 //#include "BSE_drawipo.h"
137 //#include "BSE_edit.h"
138 //#include "BSE_editipo.h"
139 //#include "BSE_editipo_types.h"
140 //#include "BSE_editaction_types.h"
142 //#include "BDR_drawaction.h" // list of keyframes in action
143 //#include "BDR_editobject.h" // reset_slowparents()
144 //#include "BDR_gpencil.h"
146 #include "BLI_arithb.h"
147 #include "BLI_blenlib.h"
148 #include "BLI_editVert.h"
150 //#include "editmesh.h"
152 //#include "blendef.h"
154 //#include "mydevice.h"
156 extern ListBase editelems;
158 #include "transform.h"
160 #include "BLO_sys_types.h" // for intptr_t support
162 /* local function prototype - for Object/Bone Constraints */
163 static short constraints_list_needinv(TransInfo *t, ListBase *list);
165 /* ************************** Functions *************************** */
167 static void qsort_trans_data(TransInfo *t, TransData *head, TransData *tail) {
168 TransData pivot = *head;
169 TransData *ihead = head;
170 TransData *itail = tail;
171 short connected = t->flag & T_PROP_CONNECTED;
176 while ((tail->dist >= pivot.dist) && (head < tail))
180 while ((tail->rdist >= pivot.rdist) && (head < tail))
191 while ((head->dist <= pivot.dist) && (head < tail))
195 while ((head->rdist <= pivot.rdist) && (head < tail))
208 qsort_trans_data(t, ihead, head-1);
211 qsort_trans_data(t, head+1, itail);
215 void sort_trans_data_dist(TransInfo *t) {
216 TransData *start = t->data;
219 while(i < t->total && start->flag & TD_SELECTED) {
223 qsort_trans_data(t, start, t->data + t->total - 1);
226 static void sort_trans_data(TransInfo *t)
228 TransData *sel, *unsel;
233 while (sel > unsel) {
234 while (unsel->flag & TD_SELECTED) {
240 while (!(sel->flag & TD_SELECTED)) {
254 /* distance calculated from not-selected vertex to nearest selected vertex
255 warning; this is loops inside loop, has minor N^2 issues, but by sorting list it is OK */
256 static void set_prop_dist(TransInfo *t, short with_dist)
261 for(a=0, tob= t->data; a<t->total; a++, tob++) {
263 tob->rdist= 0.0f; // init, it was mallocced
265 if((tob->flag & TD_SELECTED)==0) {
270 tob->rdist = -1.0f; // signal for next loop
272 for (i = 0, td= t->data; i < t->total; i++, td++) {
273 if(td->flag & TD_SELECTED) {
274 VecSubf(vec, tob->center, td->center);
275 Mat3MulVecfl(tob->mtx, vec);
276 dist = Normalize(vec);
277 if (tob->rdist == -1.0f) {
280 else if (dist < tob->rdist) {
284 else break; // by definition transdata has selected items in beginning
287 tob->dist = tob->rdist;
293 /* ************************** CONVERSIONS ************************* */
295 /* ********************* texture space ********* */
297 static void createTransTexspace(bContext *C, TransInfo *t)
299 Scene *scene = CTX_data_scene(C);
307 if (ob == NULL) { // Shouldn't logically happen, but still...
313 if(id == NULL || !ELEM3( GS(id->name), ID_ME, ID_CU, ID_MB )) {
319 td= t->data= MEM_callocN(sizeof(TransData), "TransTexspace");
320 td->ext= t->ext= MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
322 td->flag= TD_SELECTED;
323 VECCOPY(td->center, ob->obmat[3]);
326 Mat3CpyMat4(td->mtx, ob->obmat);
327 Mat3CpyMat4(td->axismtx, ob->obmat);
328 Mat3Ortho(td->axismtx);
329 Mat3Inv(td->smtx, td->mtx);
331 if (give_obdata_texspace(ob, &texflag, &td->loc, &td->ext->size, &td->ext->rot)) {
332 *texflag &= ~AUTOSPACE;
335 VECCOPY(td->iloc, td->loc);
336 VECCOPY(td->ext->irot, td->ext->rot);
337 VECCOPY(td->ext->isize, td->ext->size);
340 /* ********************* edge (for crease) ***** */
342 static void createTransEdge(bContext *C, TransInfo *t) {
343 #if 0 // TRANSFORM_FIX_ME
344 TransData *td = NULL;
346 float mtx[3][3], smtx[3][3];
347 int count=0, countsel=0;
348 int propmode = t->flag & T_PROP_EDIT;
350 for(eed= em->edges.first; eed; eed= eed->next) {
352 if (eed->f & SELECT) countsel++;
353 if (propmode) count++;
367 td= t->data= MEM_callocN(t->total * sizeof(TransData), "TransCrease");
369 Mat3CpyMat4(mtx, t->obedit->obmat);
372 for(eed= em->edges.first; eed; eed= eed->next) {
373 if(eed->h==0 && (eed->f & SELECT || propmode)) {
374 /* need to set center for center calculations */
375 VecAddf(td->center, eed->v1->co, eed->v2->co);
376 VecMulf(td->center, 0.5f);
380 td->flag= TD_SELECTED;
385 Mat3CpyMat3(td->smtx, smtx);
386 Mat3CpyMat3(td->mtx, mtx);
390 if (t->mode == TFM_BWEIGHT) {
391 td->val = &(eed->bweight);
392 td->ival = eed->bweight;
395 td->val = &(eed->crease);
396 td->ival = eed->crease;
405 /* ********************* pose mode ************* */
407 static bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
409 bConstraint *con= pchan->constraints.first;
411 for(;con; con= con->next) {
412 if(con->type==CONSTRAINT_TYPE_KINEMATIC && (con->enforce!=0.0)) {
413 bKinematicConstraint *data= con->data;
417 if(data->tar->type==OB_ARMATURE && data->subtarget[0]==0)
424 static short apply_targetless_ik(Object *ob)
426 bPoseChannel *pchan, *parchan, *chanlist[256];
427 bKinematicConstraint *data;
428 int segcount, apply= 0;
430 /* now we got a difficult situation... we have to find the
431 target-less IK pchans, and apply transformation to the all
432 pchans that were in the chain */
434 for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
435 data= has_targetless_ik(pchan);
436 if(data && (data->flag & CONSTRAINT_IK_AUTO)) {
438 /* fill the array with the bones of the chain (armature.c does same, keep it synced) */
441 /* exclude tip from chain? */
442 if(!(data->flag & CONSTRAINT_IK_TIP))
443 parchan= pchan->parent;
447 /* Find the chain's root & count the segments needed */
448 for (; parchan; parchan=parchan->parent){
449 chanlist[segcount]= parchan;
452 if(segcount==data->rootbone || segcount>255) break; // 255 is weak
454 for(;segcount;segcount--) {
456 float rmat[4][4], tmat[4][4], imat[4][4];
458 /* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */
459 /* we put in channel the entire result of rmat= (channel * constraint * IK) */
460 /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat */
461 /* rmat = pose_mat(b) * inv( pose_mat(b-1) * offs_bone ) */
463 parchan= chanlist[segcount-1];
465 bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */
467 if(parchan->parent) {
468 Bone *parbone= parchan->parent->bone;
469 float offs_bone[4][4];
471 /* offs_bone = yoffs(b-1) + root(b) + bonemat(b) */
472 Mat4CpyMat3(offs_bone, bone->bone_mat);
474 /* The bone's root offset (is in the parent's coordinate system) */
475 VECCOPY(offs_bone[3], bone->head);
477 /* Get the length translation of parent (length along y axis) */
478 offs_bone[3][1]+= parbone->length;
480 /* pose_mat(b-1) * offs_bone */
481 if(parchan->bone->flag & BONE_HINGE) {
482 /* the rotation of the parent restposition */
483 Mat4CpyMat4(rmat, parbone->arm_mat); /* rmat used as temp */
485 /* the location of actual parent transform */
486 VECCOPY(rmat[3], offs_bone[3]);
487 offs_bone[3][0]= offs_bone[3][1]= offs_bone[3][2]= 0.0f;
488 Mat4MulVecfl(parchan->parent->pose_mat, rmat[3]);
490 Mat4MulMat4(tmat, offs_bone, rmat);
492 else if(parchan->bone->flag & BONE_NO_SCALE) {
493 Mat4MulMat4(tmat, offs_bone, parchan->parent->pose_mat);
497 Mat4MulMat4(tmat, offs_bone, parchan->parent->pose_mat);
499 Mat4Invert(imat, tmat);
502 Mat4CpyMat3(tmat, bone->bone_mat);
504 VECCOPY(tmat[3], bone->head);
505 Mat4Invert(imat, tmat);
508 Mat4MulMat4(rmat, parchan->pose_mat, imat);
510 /* apply and decompose, doesn't work for constraints or non-uniform scale well */
512 float rmat3[3][3], qmat[3][3], imat[3][3], smat[3][3];
514 Mat3CpyMat4(rmat3, rmat);
517 Mat3ToQuat(rmat3, parchan->quat);
519 /* for size, remove rotation */
520 /* causes problems with some constraints (so apply only if needed) */
521 if (data->flag & CONSTRAINT_IK_STRETCH) {
522 QuatToMat3(parchan->quat, qmat);
524 Mat3MulMat3(smat, rmat3, imat);
525 Mat3ToSize(smat, parchan->size);
528 /* causes problems with some constraints (e.g. childof), so disable this */
529 /* as it is IK shouldn't affect location directly */
530 /* VECCOPY(parchan->loc, rmat[3]); */
536 data->flag &= ~CONSTRAINT_IK_AUTO;
543 static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransData *td)
545 Bone *bone= pchan->bone;
546 float pmat[3][3], omat[3][3];
547 float cmat[3][3], tmat[3][3];
550 VECCOPY(vec, pchan->pose_mat[3]);
551 VECCOPY(td->center, vec);
554 td->flag= TD_SELECTED|TD_USEQUAT;
555 if (bone->flag & BONE_HINGE_CHILD_TRANSFORM)
557 td->flag |= TD_NOCENTER;
560 if (bone->flag & BONE_TRANSFORM_CHILD)
562 td->flag |= TD_NOCENTER;
563 td->flag |= TD_NO_LOC;
566 td->protectflag= pchan->protectflag;
568 td->loc = pchan->loc;
569 VECCOPY(td->iloc, pchan->loc);
572 td->ext->quat= pchan->quat;
573 td->ext->size= pchan->size;
575 QUATCOPY(td->ext->iquat, pchan->quat);
576 VECCOPY(td->ext->isize, pchan->size);
578 /* proper way to get parent transform + own transform + constraints transform */
579 Mat3CpyMat4(omat, ob->obmat);
582 if(pchan->bone->flag & BONE_HINGE)
583 Mat3CpyMat4(pmat, pchan->parent->bone->arm_mat);
585 Mat3CpyMat4(pmat, pchan->parent->pose_mat);
587 if (constraints_list_needinv(t, &pchan->constraints)) {
588 Mat3CpyMat4(tmat, pchan->constinv);
590 Mat3MulSerie(td->mtx, pchan->bone->bone_mat, pmat, omat, cmat, 0,0,0,0); // dang mulserie swaps args
593 Mat3MulSerie(td->mtx, pchan->bone->bone_mat, pmat, omat, 0,0,0,0,0); // dang mulserie swaps args
596 if (constraints_list_needinv(t, &pchan->constraints)) {
597 Mat3CpyMat4(tmat, pchan->constinv);
599 Mat3MulSerie(td->mtx, pchan->bone->bone_mat, omat, cmat, 0,0,0,0,0); // dang mulserie swaps args
602 Mat3MulMat3(td->mtx, omat, pchan->bone->bone_mat); // Mat3MulMat3 has swapped args!
605 Mat3Inv(td->smtx, td->mtx);
607 /* for axismat we use bone's own transform */
608 Mat3CpyMat4(pmat, pchan->pose_mat);
609 Mat3MulMat3(td->axismtx, omat, pmat);
610 Mat3Ortho(td->axismtx);
612 if (t->mode==TFM_BONESIZE) {
613 bArmature *arm= t->poseobj->data;
615 if(arm->drawtype==ARM_ENVELOPE) {
617 td->val= &bone->dist;
618 td->ival= bone->dist;
621 // abusive storage of scale in the loc pointer :)
622 td->loc= &bone->xwidth;
623 VECCOPY (td->iloc, td->loc);
628 /* in this case we can do target-less IK grabbing */
629 if (t->mode==TFM_TRANSLATION) {
630 bKinematicConstraint *data= has_targetless_ik(pchan);
632 if(data->flag & CONSTRAINT_IK_TIP) {
633 VECCOPY(data->grabtarget, pchan->pose_tail);
636 VECCOPY(data->grabtarget, pchan->pose_head);
638 td->loc = data->grabtarget;
639 VECCOPY(td->iloc, td->loc);
640 data->flag |= CONSTRAINT_IK_AUTO;
642 /* only object matrix correction */
643 Mat3CpyMat3 (td->mtx, omat);
644 Mat3Inv (td->smtx, td->mtx);
648 /* store reference to first constraint */
649 td->con= pchan->constraints.first;
652 static void bone_children_clear_transflag(TransInfo *t, ListBase *lb)
654 Bone *bone= lb->first;
656 for(;bone;bone= bone->next) {
657 if((bone->flag & BONE_HINGE) && (bone->flag & BONE_CONNECTED))
659 bone->flag |= BONE_HINGE_CHILD_TRANSFORM;
661 else if (bone->flag & BONE_TRANSFORM && (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))
663 bone->flag |= BONE_TRANSFORM_CHILD;
667 bone->flag &= ~BONE_TRANSFORM;
670 bone_children_clear_transflag(t, &bone->childbase);
674 /* sets transform flags in the bones, returns total */
675 static void set_pose_transflags(TransInfo *t, Object *ob)
677 bArmature *arm= ob->data;
684 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
686 if(bone->layer & arm->layer) {
687 if(bone->flag & BONE_SELECTED)
688 bone->flag |= BONE_TRANSFORM;
690 bone->flag &= ~BONE_TRANSFORM;
692 bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
693 bone->flag &= ~BONE_TRANSFORM_CHILD;
697 /* make sure no bone can be transformed when a parent is transformed */
698 /* since pchans are depsgraph sorted, the parents are in beginning of list */
699 if(t->mode!=TFM_BONESIZE) {
700 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
702 if(bone->flag & BONE_TRANSFORM)
703 bone_children_clear_transflag(t, &bone->childbase);
706 /* now count, and check if we have autoIK or have to switch from translate to rotate */
709 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
711 if(bone->flag & BONE_TRANSFORM) {
715 if(t->mode==TFM_TRANSLATION) {
716 if( has_targetless_ik(pchan)==NULL ) {
717 if(pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
718 if(pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM)
721 else if((pchan->protectflag & OB_LOCK_LOC)!=OB_LOCK_LOC)
730 /* if there are no translatable bones, do rotation */
731 if(t->mode==TFM_TRANSLATION && !hastranslation)
732 t->mode= TFM_ROTATION;
736 /* -------- Auto-IK ---------- */
738 /* adjust pose-channel's auto-ik chainlen */
739 static void pchan_autoik_adjust (bPoseChannel *pchan, short chainlen)
743 /* don't bother to search if no valid constraints */
744 if ((pchan->constflag & (PCHAN_HAS_IK|PCHAN_HAS_TARGET))==0)
747 /* check if pchan has ik-constraint */
748 for (con= pchan->constraints.first; con; con= con->next) {
749 if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce!=0.0)) {
750 bKinematicConstraint *data= con->data;
752 /* only accept if a temporary one (for auto-ik) */
753 if (data->flag & CONSTRAINT_IK_TEMP) {
754 /* chainlen is new chainlen, but is limited by maximum chainlen */
755 if ((chainlen==0) || (chainlen > data->max_rootbone))
756 data->rootbone= data->max_rootbone;
758 data->rootbone= chainlen;
764 /* change the chain-length of auto-ik */
765 void transform_autoik_update (TransInfo *t, short mode)
767 short *chainlen= &t->scene->toolsettings->autoik_chainlen;
770 /* mode determines what change to apply to chainlen */
772 /* mode=1 is from WHEELMOUSEDOWN... increases len */
775 else if (mode == -1) {
776 /* mode==-1 is from WHEELMOUSEUP... decreases len */
777 if (*chainlen > 0) (*chainlen)--;
780 /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
781 if (ELEM(NULL, t->poseobj, t->poseobj->pose))
784 /* apply to all pose-channels */
785 for (pchan=t->poseobj->pose->chanbase.first; pchan; pchan=pchan->next) {
786 pchan_autoik_adjust(pchan, *chainlen);
790 /* frees temporal IKs */
791 static void pose_grab_with_ik_clear(Object *ob)
793 bKinematicConstraint *data;
795 bConstraint *con, *next;
797 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
798 /* clear all temporary lock flags */
799 pchan->ikflag &= ~(BONE_IK_NO_XDOF_TEMP|BONE_IK_NO_YDOF_TEMP|BONE_IK_NO_ZDOF_TEMP);
801 pchan->constflag &= ~(PCHAN_HAS_IK|PCHAN_HAS_TARGET);
802 /* remove all temporary IK-constraints added */
803 for (con= pchan->constraints.first; con; con= next) {
805 if (con->type==CONSTRAINT_TYPE_KINEMATIC) {
807 if (data->flag & CONSTRAINT_IK_TEMP) {
808 BLI_remlink(&pchan->constraints, con);
809 MEM_freeN(con->data);
813 pchan->constflag |= PCHAN_HAS_IK;
814 if(data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]==0))
815 pchan->constflag |= PCHAN_HAS_TARGET;
821 /* adds the IK to pchan - returns if added */
822 static short pose_grab_with_ik_add(bPoseChannel *pchan)
824 bKinematicConstraint *data;
826 bConstraint *targetless = 0;
832 /* Rule: not if there's already an IK on this channel */
833 for (con= pchan->constraints.first; con; con= con->next) {
834 if (con->type==CONSTRAINT_TYPE_KINEMATIC) {
835 bKinematicConstraint *data= con->data;
836 if(data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]==0)) {
838 /* but, if this is a targetless IK, we make it auto anyway (for the children loop) */
839 if (con->enforce!=0.0f) {
840 targetless->flag |= CONSTRAINT_IK_AUTO;
844 if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0f))
849 con = add_new_constraint(CONSTRAINT_TYPE_KINEMATIC);
850 BLI_addtail(&pchan->constraints, con);
851 pchan->constflag |= (PCHAN_HAS_IK|PCHAN_HAS_TARGET); /* for draw, but also for detecting while pose solving */
853 if (targetless) { /* if exists use values from last targetless IK-constraint as base */
854 *data = *((bKinematicConstraint*)targetless->data);
857 data->flag= CONSTRAINT_IK_TIP;
858 data->flag |= CONSTRAINT_IK_TEMP|CONSTRAINT_IK_AUTO;
859 VECCOPY(data->grabtarget, pchan->pose_tail);
862 /* we include only a connected chain */
863 while ((pchan) && (pchan->bone->flag & BONE_CONNECTED)) {
864 /* here, we set ik-settings for bone from pchan->protectflag */
865 if (pchan->protectflag & OB_LOCK_ROTX) pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
866 if (pchan->protectflag & OB_LOCK_ROTY) pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
867 if (pchan->protectflag & OB_LOCK_ROTZ) pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
869 /* now we count this pchan as being included */
871 pchan= pchan->parent;
874 /* make a copy of maximum chain-length */
875 data->max_rootbone= data->rootbone;
880 /* bone is a candidate to get IK, but we don't do it if it has children connected */
881 static short pose_grab_with_ik_children(bPose *pose, Bone *bone)
884 short wentdeeper=0, added=0;
886 /* go deeper if children & children are connected */
887 for (bonec= bone->childbase.first; bonec; bonec= bonec->next) {
888 if (bonec->flag & BONE_CONNECTED) {
890 added+= pose_grab_with_ik_children(pose, bonec);
894 bPoseChannel *pchan= get_pose_channel(pose, bone->name);
896 added+= pose_grab_with_ik_add(pchan);
902 /* main call which adds temporal IK chains */
903 static short pose_grab_with_ik(Object *ob)
906 bPoseChannel *pchan, *parent;
910 if ((ob==NULL) || (ob->pose==NULL) || (ob->flag & OB_POSEMODE)==0)
915 /* Rule: allow multiple Bones (but they must be selected, and only one ik-solver per chain should get added) */
916 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
917 if (pchan->bone->layer & arm->layer) {
918 if (pchan->bone->flag & BONE_SELECTED) {
919 /* Rule: no IK for solitatry (unconnected) bones */
920 for (bonec=pchan->bone->childbase.first; bonec; bonec=bonec->next) {
921 if (bonec->flag & BONE_CONNECTED) {
925 if ((pchan->bone->flag & BONE_CONNECTED)==0 && (bonec == NULL))
928 /* rule: if selected Bone is not a root bone, it gets a temporal IK */
930 /* only adds if there's no IK yet (and no parent bone was selected) */
931 for (parent= pchan->parent; parent; parent= parent->parent) {
932 if (parent->bone->flag & BONE_SELECTED)
936 tot_ik += pose_grab_with_ik_add(pchan);
939 /* rule: go over the children and add IK to the tips */
940 tot_ik += pose_grab_with_ik_children(ob->pose, pchan->bone);
946 return (tot_ik) ? 1 : 0;
950 /* only called with pose mode active object now */
951 static void createTransPose(bContext *C, TransInfo *t, Object *ob)
956 TransDataExtension *tdx;
962 /* check validity of state */
963 arm= get_armature(ob);
964 if ((arm==NULL) || (ob->pose==NULL)) return;
966 if (arm->flag & ARM_RESTPOS) {
967 if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE)==0) {
968 BKE_report(CTX_reports(C), RPT_ERROR, "Can't select linked when sync selection is enabled.");
973 /* do we need to add temporal IK chains? */
974 if ((arm->flag & ARM_AUTO_IK) && t->mode==TFM_TRANSLATION) {
975 ik_on= pose_grab_with_ik(ob);
976 if (ik_on) t->flag |= T_AUTOIK;
979 /* set flags and count total (warning, can change transform to rotate) */
980 set_pose_transflags(t, ob);
982 if(t->total==0) return;
985 t->poseobj= ob; /* we also allow non-active objects to be transformed, in weightpaint */
987 /* init trans data */
988 td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransPoseBone");
989 tdx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "TransPoseBoneExt");
990 for(i=0; i<t->total; i++, td++, tdx++) {
996 /* use pose channels to fill trans data */
998 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
999 if (pchan->bone->flag & BONE_TRANSFORM) {
1000 add_pose_transdata(t, pchan, ob, td);
1005 if(td != (t->data+t->total)) {
1006 BKE_report(CTX_reports(C), RPT_DEBUG, "Bone selection count error.");
1009 /* initialise initial auto=ik chainlen's? */
1010 if (ik_on) transform_autoik_update(t, 0);
1013 /* ********************* armature ************** */
1015 static void createTransArmatureVerts(bContext *C, TransInfo *t)
1018 bArmature *arm= t->obedit->data;
1019 ListBase *edbo = arm->edbo;
1021 float mtx[3][3], smtx[3][3], delta[3], bonemat[3][3];
1024 for (ebo = edbo->first; ebo; ebo = ebo->next)
1026 if(ebo->layer & arm->layer)
1028 if (t->mode==TFM_BONESIZE)
1030 if (ebo->flag & BONE_SELECTED)
1033 else if (t->mode==TFM_BONE_ROLL)
1035 if (ebo->flag & BONE_SELECTED)
1040 if (ebo->flag & BONE_TIPSEL)
1042 if (ebo->flag & BONE_ROOTSEL)
1048 if (!t->total) return;
1050 Mat3CpyMat4(mtx, t->obedit->obmat);
1053 td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransEditBone");
1055 for (ebo = edbo->first; ebo; ebo = ebo->next)
1057 ebo->oldlength = ebo->length; // length==0.0 on extrude, used for scaling radius of bone points
1059 if(ebo->layer & arm->layer) {
1060 if (t->mode==TFM_BONE_ENVELOPE)
1062 if (ebo->flag & BONE_ROOTSEL)
1064 td->val= &ebo->rad_head;
1067 VECCOPY (td->center, ebo->head);
1068 td->flag= TD_SELECTED;
1070 Mat3CpyMat3(td->smtx, smtx);
1071 Mat3CpyMat3(td->mtx, mtx);
1079 if (ebo->flag & BONE_TIPSEL)
1081 td->val= &ebo->rad_tail;
1083 VECCOPY (td->center, ebo->tail);
1084 td->flag= TD_SELECTED;
1086 Mat3CpyMat3(td->smtx, smtx);
1087 Mat3CpyMat3(td->mtx, mtx);
1097 else if (t->mode==TFM_BONESIZE)
1099 if (ebo->flag & BONE_SELECTED) {
1100 if(arm->drawtype==ARM_ENVELOPE)
1103 td->val= &ebo->dist;
1104 td->ival= ebo->dist;
1108 // abusive storage of scale in the loc pointer :)
1109 td->loc= &ebo->xwidth;
1110 VECCOPY (td->iloc, td->loc);
1113 VECCOPY (td->center, ebo->head);
1114 td->flag= TD_SELECTED;
1116 /* use local bone matrix */
1117 VecSubf(delta, ebo->tail, ebo->head);
1118 vec_roll_to_mat3(delta, ebo->roll, bonemat);
1119 Mat3MulMat3(td->mtx, mtx, bonemat);
1120 Mat3Inv(td->smtx, td->mtx);
1122 Mat3CpyMat3(td->axismtx, td->mtx);
1123 Mat3Ortho(td->axismtx);
1131 else if (t->mode==TFM_BONE_ROLL)
1133 if (ebo->flag & BONE_SELECTED)
1136 td->val= &(ebo->roll);
1137 td->ival= ebo->roll;
1139 VECCOPY (td->center, ebo->head);
1140 td->flag= TD_SELECTED;
1150 if (ebo->flag & BONE_TIPSEL)
1152 VECCOPY (td->iloc, ebo->tail);
1153 VECCOPY (td->center, td->iloc);
1155 td->flag= TD_SELECTED;
1156 if (ebo->flag & BONE_EDITMODE_LOCKED)
1157 td->protectflag = OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE;
1159 Mat3CpyMat3(td->smtx, smtx);
1160 Mat3CpyMat3(td->mtx, mtx);
1162 VecSubf(delta, ebo->tail, ebo->head);
1163 vec_roll_to_mat3(delta, ebo->roll, td->axismtx);
1165 if ((ebo->flag & BONE_ROOTSEL) == 0)
1176 if (ebo->flag & BONE_ROOTSEL)
1178 VECCOPY (td->iloc, ebo->head);
1179 VECCOPY (td->center, td->iloc);
1181 td->flag= TD_SELECTED;
1182 if (ebo->flag & BONE_EDITMODE_LOCKED)
1183 td->protectflag = OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE;
1185 Mat3CpyMat3(td->smtx, smtx);
1186 Mat3CpyMat3(td->mtx, mtx);
1188 VecSubf(delta, ebo->tail, ebo->head);
1189 vec_roll_to_mat3(delta, ebo->roll, td->axismtx);
1191 td->extra = ebo; /* to fix roll */
1204 /* ********************* meta elements ********* */
1206 static void createTransMBallVerts(bContext *C, TransInfo *t)
1212 TransDataExtension *tx;
1213 float mtx[3][3], smtx[3][3];
1214 int count=0, countsel=0;
1215 int propmode = t->flag & T_PROP_EDIT;
1218 for(ml= editelems.first; ml; ml= ml->next) {
1219 if(ml->flag & SELECT) countsel++;
1220 if(propmode) count++;
1223 /* note: in prop mode we need at least 1 selected */
1224 if (countsel==0) return;
1226 if(propmode) t->total = count;
1227 else t->total = countsel;
1229 td = t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(MBall EditMode)");
1230 tx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "MetaElement_TransExtension");
1232 Mat3CpyMat4(mtx, t->obedit->obmat);
1235 for(ml= editelems.first; ml; ml= ml->next) {
1236 if(propmode || (ml->flag & SELECT)) {
1238 VECCOPY(td->iloc, td->loc);
1239 VECCOPY(td->center, td->loc);
1241 if(ml->flag & SELECT) td->flag= TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
1242 else td->flag= TD_USEQUAT;
1244 Mat3CpyMat3(td->smtx, smtx);
1245 Mat3CpyMat3(td->mtx, mtx);
1250 /* Radius of MetaElem (mass of MetaElem influence) */
1251 if(ml->flag & MB_SCALE_RAD){
1260 /* expx/expy/expz determine "shape" of some MetaElem types */
1261 tx->size = &ml->expx;
1262 tx->isize[0] = ml->expx;
1263 tx->isize[1] = ml->expy;
1264 tx->isize[2] = ml->expz;
1266 /* quat is used for rotation of MetaElem */
1267 tx->quat = ml->quat;
1268 QUATCOPY(tx->iquat, ml->quat);
1279 /* ********************* curve/surface ********* */
1281 static void calc_distanceCurveVerts(TransData *head, TransData *tail) {
1282 TransData *td, *td_near = NULL;
1283 for (td = head; td<=tail; td++) {
1284 if (td->flag & TD_SELECTED) {
1290 dist = VecLenf(td_near->center, td->center);
1291 if (dist < (td-1)->dist) {
1292 td->dist = (td-1)->dist;
1299 td->dist = MAXFLOAT;
1300 td->flag |= TD_NOTCONNECTED;
1304 for (td = tail; td>=head; td--) {
1305 if (td->flag & TD_SELECTED) {
1311 dist = VecLenf(td_near->center, td->center);
1312 if (td->flag & TD_NOTCONNECTED || dist < td->dist || (td+1)->dist < td->dist) {
1313 td->flag &= ~TD_NOTCONNECTED;
1314 if (dist < (td+1)->dist) {
1315 td->dist = (td+1)->dist;
1325 /* Utility function for getting the handle data from bezier's */
1326 TransDataCurveHandleFlags *initTransDataCurveHandes(TransData *td, struct BezTriple *bezt) {
1327 TransDataCurveHandleFlags *hdata;
1328 td->flag |= TD_BEZTRIPLE;
1329 hdata = td->hdata = MEM_mallocN(sizeof(TransDataCurveHandleFlags), "CuHandle Data");
1330 hdata->ih1 = bezt->h1;
1331 hdata->h1 = &bezt->h1;
1332 hdata->ih2 = bezt->h2; /* incase the second is not selected */
1333 hdata->h2 = &bezt->h2;
1337 static void createTransCurveVerts(bContext *C, TransInfo *t)
1339 Object *obedit= CTX_data_edit_object(C);
1340 Curve *cu= obedit->data;
1341 TransData *td = NULL;
1345 float mtx[3][3], smtx[3][3];
1347 int count=0, countsel=0;
1348 int propmode = t->flag & T_PROP_EDIT;
1351 if(cu->editnurb==NULL) return;
1353 /* count total of vertices, check identical as in 2nd loop for making transdata! */
1354 for(nu= cu->editnurb->first; nu; nu= nu->next) {
1355 if((nu->type & 7)==CU_BEZIER) {
1356 for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) {
1358 if (G.f & G_HIDDENHANDLES) {
1359 if(bezt->f2 & SELECT) countsel+=3;
1360 if(propmode) count+= 3;
1362 if(bezt->f1 & SELECT) countsel++;
1363 if(bezt->f2 & SELECT) countsel++;
1364 if(bezt->f3 & SELECT) countsel++;
1365 if(propmode) count+= 3;
1371 for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) {
1373 if(propmode) count++;
1374 if(bp->f1 & SELECT) countsel++;
1379 /* note: in prop mode we need at least 1 selected */
1380 if (countsel==0) return;
1382 if(propmode) t->total = count;
1383 else t->total = countsel;
1384 t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Curve EditMode)");
1386 Mat3CpyMat4(mtx, t->obedit->obmat);
1390 for(nu= cu->editnurb->first; nu; nu= nu->next) {
1391 if((nu->type & 7)==CU_BEZIER) {
1392 TransData *head, *tail;
1394 for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) {
1396 TransDataCurveHandleFlags *hdata = NULL;
1399 ((bezt->f2 & SELECT) && (G.f & G_HIDDENHANDLES)) ||
1400 ((bezt->f1 & SELECT) && (G.f & G_HIDDENHANDLES)==0)
1402 VECCOPY(td->iloc, bezt->vec[0]);
1403 td->loc= bezt->vec[0];
1404 VECCOPY(td->center, bezt->vec[1]);
1405 if (G.f & G_HIDDENHANDLES) {
1406 if(bezt->f2 & SELECT) td->flag= TD_SELECTED;
1409 if(bezt->f1 & SELECT) td->flag= TD_SELECTED;
1416 hdata = initTransDataCurveHandes(td, bezt);
1418 Mat3CpyMat3(td->smtx, smtx);
1419 Mat3CpyMat3(td->mtx, mtx);
1426 /* This is the Curve Point, the other two are handles */
1427 if(propmode || (bezt->f2 & SELECT)) {
1428 VECCOPY(td->iloc, bezt->vec[1]);
1429 td->loc= bezt->vec[1];
1430 VECCOPY(td->center, td->loc);
1431 if(bezt->f2 & SELECT) td->flag= TD_SELECTED;
1436 if (t->mode==TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/ /* TODO - make points scale */
1437 td->val = &(bezt->radius);
1438 td->ival = bezt->radius;
1439 } else if (t->mode==TFM_TILT) {
1440 td->val = &(bezt->alfa);
1441 td->ival = bezt->alfa;
1446 Mat3CpyMat3(td->smtx, smtx);
1447 Mat3CpyMat3(td->mtx, mtx);
1449 if ((bezt->f1&SELECT)==0 && (bezt->f3&SELECT)==0)
1450 /* If the middle is selected but the sides arnt, this is needed */
1451 if (hdata==NULL) { /* if the handle was not saved by the previous handle */
1452 hdata = initTransDataCurveHandes(td, bezt);
1460 ((bezt->f2 & SELECT) && (G.f & G_HIDDENHANDLES)) ||
1461 ((bezt->f3 & SELECT) && (G.f & G_HIDDENHANDLES)==0)
1463 VECCOPY(td->iloc, bezt->vec[2]);
1464 td->loc= bezt->vec[2];
1465 VECCOPY(td->center, bezt->vec[1]);
1466 if (G.f & G_HIDDENHANDLES) {
1467 if(bezt->f2 & SELECT) td->flag= TD_SELECTED;
1470 if(bezt->f3 & SELECT) td->flag= TD_SELECTED;
1477 if (hdata==NULL) { /* if the handle was not saved by the previous handle */
1478 hdata = initTransDataCurveHandes(td, bezt);
1481 Mat3CpyMat3(td->smtx, smtx);
1482 Mat3CpyMat3(td->mtx, mtx);
1489 else if (propmode && head != tail) {
1490 calc_distanceCurveVerts(head, tail-1);
1494 if (propmode && head != tail)
1495 calc_distanceCurveVerts(head, tail-1);
1497 /* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandes
1498 * but for now just dont change handle types */
1499 if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT) == 0)
1500 testhandlesNurb(nu); /* sets the handles based on their selection, do this after the data is copied to the TransData */
1503 TransData *head, *tail;
1505 for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) {
1507 if(propmode || (bp->f1 & SELECT)) {
1508 VECCOPY(td->iloc, bp->vec);
1510 VECCOPY(td->center, td->loc);
1511 if(bp->f1 & SELECT) td->flag= TD_SELECTED;
1516 if (t->mode==TFM_CURVE_SHRINKFATTEN || t->mode==TFM_RESIZE) {
1517 td->val = &(bp->radius);
1518 td->ival = bp->radius;
1520 td->val = &(bp->alfa);
1521 td->ival = bp->alfa;
1524 Mat3CpyMat3(td->smtx, smtx);
1525 Mat3CpyMat3(td->mtx, mtx);
1532 else if (propmode && head != tail) {
1533 calc_distanceCurveVerts(head, tail-1);
1537 if (propmode && head != tail)
1538 calc_distanceCurveVerts(head, tail-1);
1543 /* ********************* lattice *************** */
1545 static void createTransLatticeVerts(bContext *C, TransInfo *t)
1547 Lattice *latt = ((Lattice*)t->obedit->data)->editlatt;
1548 TransData *td = NULL;
1550 float mtx[3][3], smtx[3][3];
1552 int count=0, countsel=0;
1553 int propmode = t->flag & T_PROP_EDIT;
1556 a = latt->pntsu * latt->pntsv * latt->pntsw;
1559 if(bp->f1 & SELECT) countsel++;
1560 if(propmode) count++;
1565 /* note: in prop mode we need at least 1 selected */
1566 if (countsel==0) return;
1568 if(propmode) t->total = count;
1569 else t->total = countsel;
1570 t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Lattice EditMode)");
1572 Mat3CpyMat4(mtx, t->obedit->obmat);
1577 a = latt->pntsu * latt->pntsv * latt->pntsw;
1579 if(propmode || (bp->f1 & SELECT)) {
1581 VECCOPY(td->iloc, bp->vec);
1583 VECCOPY(td->center, td->loc);
1584 if(bp->f1 & SELECT) td->flag= TD_SELECTED;
1586 Mat3CpyMat3(td->smtx, smtx);
1587 Mat3CpyMat3(td->mtx, mtx);
1601 /* ******************* particle edit **************** */
1602 static void createTransParticleVerts(bContext *C, TransInfo *t)
1604 TransData *td = NULL;
1605 TransDataExtension *tx;
1606 Base *base = CTX_data_active_base(C);
1607 Object *ob = CTX_data_active_object(C);
1608 ParticleSystem *psys = PE_get_current(t->scene, ob);
1609 ParticleSystemModifierData *psmd = NULL;
1610 ParticleEditSettings *pset = PE_settings(t->scene);
1611 ParticleData *pa = NULL;
1613 ParticleEditKey *key;
1615 int i,k, totpart, transformparticle;
1616 int count = 0, hasselected = 0;
1617 int propmode = t->flag & T_PROP_EDIT;
1619 if(psys==NULL || t->scene->selectmode==SCE_SELECT_PATH) return;
1621 psmd = psys_get_modifier(ob,psys);
1624 totpart = psys->totpart;
1625 base->flag |= BA_HAS_RECALC_DATA;
1627 for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
1628 pa->flag &= ~PARS_TRANSFORM;
1629 transformparticle= 0;
1631 if((pa->flag & PARS_HIDE)==0) {
1632 for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++) {
1633 if((key->flag&PEK_HIDE)==0) {
1634 if(key->flag&PEK_SELECT) {
1636 transformparticle= 1;
1639 transformparticle= 1;
1644 if(transformparticle) {
1645 count += pa->totkey;
1646 pa->flag |= PARS_TRANSFORM;
1650 /* note: in prop mode we need at least 1 selected */
1651 if (hasselected==0) return;
1654 td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Particle Mode)");
1656 if(t->mode == TFM_BAKE_TIME)
1657 tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "Particle_TransExtension");
1663 Mat4Invert(ob->imat,ob->obmat);
1665 for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
1666 TransData *head, *tail;
1669 if(!(pa->flag & PARS_TRANSFORM)) continue;
1671 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat);
1673 for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++) {
1674 VECCOPY(key->world_co, key->co);
1675 Mat4MulVecfl(mat, key->world_co);
1676 td->loc = key->world_co;
1678 VECCOPY(td->iloc, td->loc);
1679 VECCOPY(td->center, td->loc);
1681 if(key->flag & PEK_SELECT)
1682 td->flag |= TD_SELECTED;
1684 td->flag |= TD_SKIP;
1689 /* don't allow moving roots */
1690 if(k==0 && pset->flag & PE_LOCK_FIRST)
1691 td->protectflag |= OB_LOCK_LOC;
1696 if(t->mode == TFM_BAKE_TIME) {
1697 td->val = key->time;
1698 td->ival = *(key->time);
1699 /* abuse size and quat for min/max values */
1700 td->flag |= TD_NO_EXT;
1701 if(k==0) tx->size = 0;
1702 else tx->size = (key - 1)->time;
1704 if(k == pa->totkey - 1) tx->quat = 0;
1705 else tx->quat = (key + 1)->time;
1713 if (propmode && head != tail)
1714 calc_distanceCurveVerts(head, tail - 1);
1718 void flushTransParticles(TransInfo *t)
1720 Scene *scene = t->scene;
1722 ParticleSystem *psys = PE_get_current(scene, ob);
1723 ParticleSystemModifierData *psmd;
1725 ParticleEditKey *key;
1727 float mat[4][4], imat[4][4], co[3];
1728 int i, k, propmode = t->flag & T_PROP_EDIT;
1730 psmd = psys_get_modifier(ob, psys);
1732 /* we do transform in world space, so flush world space position
1733 * back to particle local space */
1735 for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++, td++) {
1736 if(!(pa->flag & PARS_TRANSFORM)) continue;
1738 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat);
1739 Mat4Invert(imat,mat);
1741 for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++) {
1742 VECCOPY(co, key->world_co);
1743 Mat4MulVecfl(imat, co);
1745 /* optimization for proportional edit */
1746 if(!propmode || !FloatCompare(key->co, co, 0.0001f)) {
1747 VECCOPY(key->co, co);
1748 pa->flag |= PARS_EDIT_RECALC;
1753 PE_update_object(scene, OBACT, 1);
1756 /* ********************* mesh ****************** */
1758 /* proportional distance based on connectivity */
1759 #define E_VEC(a) (vectors + (3 * (a)->tmp.l))
1760 #define E_NEAR(a) (nears[((a)->tmp.l)])
1761 #define THRESHOLD 0.0001f
1762 static void editmesh_set_connectivity_distance(EditMesh *em, int total, float *vectors, EditVert **nears)
1768 /* f2 flag is used for 'selection' */
1769 /* tmp.l is offset on scratch array */
1770 for(eve= em->verts.first; eve; eve= eve->next) {
1774 if(eve->f & SELECT) {
1777 E_VEC(eve)[0] = 0.0f;
1778 E_VEC(eve)[1] = 0.0f;
1779 E_VEC(eve)[2] = 0.0f;
1788 /* Floodfill routine */
1790 At worst this is n*n of complexity where n is number of edges
1791 Best case would be n if the list is ordered perfectly.
1792 Estimate is n log n in average (so not too bad)
1797 for(eed= em->edges.first; eed; eed= eed->next) {
1799 EditVert *v1= eed->v1, *v2= eed->v2;
1800 float *vec2 = E_VEC(v2);
1801 float *vec1 = E_VEC(v1);
1803 if (v1->f2 + v2->f2 == 4)
1809 float len1 = VecLength(vec1);
1810 float len2 = VecLength(vec2);
1812 /* for v2 if not selected */
1814 VecSubf(nvec, v2->co, E_NEAR(v1)->co);
1815 lenn = VecLength(nvec);
1817 if (lenn - len1 > THRESHOLD && len2 - lenn > THRESHOLD) {
1818 VECCOPY(vec2, nvec);
1819 E_NEAR(v2) = E_NEAR(v1);
1823 else if (len2 - len1 > THRESHOLD && len1 - lenn > THRESHOLD) {
1824 VECCOPY(vec2, vec1);
1825 E_NEAR(v2) = E_NEAR(v1);
1829 /* for v1 if not selected */
1831 VecSubf(nvec, v1->co, E_NEAR(v2)->co);
1832 lenn = VecLength(nvec);
1834 if (lenn - len2 > THRESHOLD && len1 - lenn > THRESHOLD) {
1835 VECCOPY(vec1, nvec);
1836 E_NEAR(v1) = E_NEAR(v2);
1840 else if (len1 - len2 > THRESHOLD && len2 - lenn > THRESHOLD) {
1841 VECCOPY(vec1, vec2);
1842 E_NEAR(v1) = E_NEAR(v2);
1849 VecSubf(vec2, v2->co, E_NEAR(v1)->co);
1851 if (VecLength(vec1) - VecLength(vec2) > THRESHOLD) {
1852 VECCOPY(vec2, vec1);
1854 E_NEAR(v2) = E_NEAR(v1);
1860 VecSubf(vec1, v1->co, E_NEAR(v2)->co);
1862 if (VecLength(vec2) - VecLength(vec1) > THRESHOLD) {
1863 VECCOPY(vec1, vec2);
1865 E_NEAR(v1) = E_NEAR(v2);
1873 /* loop-in-a-loop I know, but we need it! (ton) */
1874 static void get_face_center(float *cent, EditMesh *em, EditVert *eve)
1878 for(efa= em->faces.first; efa; efa= efa->next)
1880 if(efa->v1==eve || efa->v2==eve || efa->v3==eve || efa->v4==eve)
1883 VECCOPY(cent, efa->cent);
1887 //way to overwrite what data is edited with transform
1888 //static void VertsToTransData(TransData *td, EditVert *eve, BakeKey *key)
1889 static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert *eve)
1893 // td->loc = key->co;
1897 VECCOPY(td->center, td->loc);
1898 if(t->around==V3D_LOCAL && (em->selectmode & SCE_SELECT_FACE))
1899 get_face_center(td->center, em, eve);
1900 VECCOPY(td->iloc, td->loc);
1903 VECCOPY(td->axismtx[2], eve->no);
1909 td->axismtx[1][2] = 0.0f;
1915 if (t->mode == TFM_BWEIGHT) {
1916 td->val = &(eve->bweight);
1917 td->ival = eve->bweight;
1921 /* *********************** CrazySpace correction. Now without doing subsurf optimal ****************** */
1923 static void make_vertexcos__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
1925 float *vec = userData;
1931 static int modifiers_disable_subsurf_temporary(Object *ob)
1936 for(md=ob->modifiers.first; md; md=md->next)
1937 if(md->type==eModifierType_Subsurf)
1938 if(md->mode & eModifierMode_OnCage) {
1939 md->mode ^= eModifierMode_DisableTemporary;
1946 /* disable subsurf temporal, get mapped cos, and enable it */
1947 static float *get_crazy_mapped_editverts(TransInfo *t)
1949 Mesh *me= t->obedit->data;
1953 /* disable subsurf temporal, get mapped cos, and enable it */
1954 if(modifiers_disable_subsurf_temporary(t->obedit)) {
1955 /* need to make new derivemesh */
1956 makeDerivedMesh(t->scene, t->obedit, me->edit_mesh, CD_MASK_BAREMESH);
1959 /* now get the cage */
1960 dm= editmesh_get_derived_cage(t->scene, t->obedit, me->edit_mesh, CD_MASK_BAREMESH);
1962 vertexcos= MEM_mallocN(3*sizeof(float)*me->edit_mesh->totvert, "vertexcos map");
1963 dm->foreachMappedVert(dm, make_vertexcos__mapFunc, vertexcos);
1967 /* set back the flag, no new cage needs to be built, transform does it */
1968 modifiers_disable_subsurf_temporary(t->obedit);
1973 #define TAN_MAKE_VEC(a, b, c) a[0]= b[0] + 0.2f*(b[0]-c[0]); a[1]= b[1] + 0.2f*(b[1]-c[1]); a[2]= b[2] + 0.2f*(b[2]-c[2])
1974 static void set_crazy_vertex_quat(float *quat, float *v1, float *v2, float *v3, float *def1, float *def2, float *def3)
1976 float vecu[3], vecv[3];
1979 TAN_MAKE_VEC(vecu, v1, v2);
1980 TAN_MAKE_VEC(vecv, v1, v3);
1981 triatoquat(v1, vecu, vecv, q1);
1983 TAN_MAKE_VEC(vecu, def1, def2);
1984 TAN_MAKE_VEC(vecv, def1, def3);
1985 triatoquat(def1, vecu, vecv, q2);
1987 QuatSub(quat, q2, q1);
1991 static void set_crazyspace_quats(EditMesh *em, float *origcos, float *mappedcos, float *quats)
1993 EditVert *eve, *prev;
1995 float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4;
1998 /* two abused locations in vertices */
1999 for(eve= em->verts.first; eve; eve= eve->next, index++) {
2001 eve->prev= (EditVert *)index;
2004 /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */
2005 for(efa= em->faces.first; efa; efa= efa->next) {
2007 /* retrieve mapped coordinates */
2008 v1= mappedcos + 3*(intptr_t)(efa->v1->prev);
2009 v2= mappedcos + 3*(intptr_t)(efa->v2->prev);
2010 v3= mappedcos + 3*(intptr_t)(efa->v3->prev);
2012 co1= (origcos)? origcos + 3*(intptr_t)(efa->v1->prev): efa->v1->co;
2013 co2= (origcos)? origcos + 3*(intptr_t)(efa->v2->prev): efa->v2->co;
2014 co3= (origcos)? origcos + 3*(intptr_t)(efa->v3->prev): efa->v3->co;
2016 if(efa->v2->tmp.p==NULL && efa->v2->f1) {
2017 set_crazy_vertex_quat(quats, co2, co3, co1, v2, v3, v1);
2018 efa->v2->tmp.p= (void*)quats;
2023 v4= mappedcos + 3*(intptr_t)(efa->v4->prev);
2024 co4= (origcos)? origcos + 3*(intptr_t)(efa->v4->prev): efa->v4->co;
2026 if(efa->v1->tmp.p==NULL && efa->v1->f1) {
2027 set_crazy_vertex_quat(quats, co1, co2, co4, v1, v2, v4);
2028 efa->v1->tmp.p= (void*)quats;
2031 if(efa->v3->tmp.p==NULL && efa->v3->f1) {
2032 set_crazy_vertex_quat(quats, co3, co4, co2, v3, v4, v2);
2033 efa->v3->tmp.p= (void*)quats;
2036 if(efa->v4->tmp.p==NULL && efa->v4->f1) {
2037 set_crazy_vertex_quat(quats, co4, co1, co3, v4, v1, v3);
2038 efa->v4->tmp.p= (void*)quats;
2043 if(efa->v1->tmp.p==NULL && efa->v1->f1) {
2044 set_crazy_vertex_quat(quats, co1, co2, co3, v1, v2, v3);
2045 efa->v1->tmp.p= (void*)quats;
2048 if(efa->v3->tmp.p==NULL && efa->v3->f1) {
2049 set_crazy_vertex_quat(quats, co3, co1, co2, v3, v1, v2);
2050 efa->v3->tmp.p= (void*)quats;
2056 /* restore abused prev pointer */
2057 for(prev= NULL, eve= em->verts.first; eve; prev= eve, eve= eve->next)
2062 void createTransBMeshVerts(TransInfo *t, BME_Mesh *bm, BME_TransData_Head *td) {
2068 tob = t->data = MEM_callocN(td->len*sizeof(TransData), "TransObData(Bevel tool)");
2070 for (i=0,v=bm->verts.first;v;v=v->next) {
2071 if ( (vtd = BME_get_transdata(td,v)) ) {
2072 tob->loc = vtd->loc;
2073 tob->val = &vtd->factor;
2074 VECCOPY(tob->iloc,vtd->co);
2075 VECCOPY(tob->center,vtd->org);
2076 VECCOPY(tob->axismtx[0],vtd->vec);
2077 tob->axismtx[1][0] = vtd->max ? *vtd->max : 0;
2082 /* since td is a memarena, it can hold more transdata than actual elements
2083 * (i.e. we can't depend on td->len to determine the number of actual elements) */
2087 static void createTransEditVerts(bContext *C, TransInfo *t)
2089 Scene *scene = CTX_data_scene(C);
2090 TransData *tob = NULL;
2091 EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh;
2093 EditVert **nears = NULL;
2094 EditVert *eve_act = NULL;
2095 float *vectors = NULL, *mappedcos = NULL, *quats= NULL;
2096 float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
2097 int count=0, countsel=0, a, totleft;
2098 int propmode = t->flag & T_PROP_EDIT;
2101 if ((t->options & CTX_NO_MIRROR) == 0 && (scene->toolsettings->editbutflag & B_MESH_X_MIRROR))
2106 // transform now requires awareness for select mode, so we tag the f1 flags in verts
2107 if(scene->selectmode & SCE_SELECT_VERTEX) {
2108 for(eve= em->verts.first; eve; eve= eve->next) {
2109 if(eve->h==0 && (eve->f & SELECT))
2115 else if(scene->selectmode & SCE_SELECT_EDGE) {
2117 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
2118 for(eed= em->edges.first; eed; eed= eed->next) {
2119 if(eed->h==0 && (eed->f & SELECT))
2120 eed->v1->f1= eed->v2->f1= SELECT;
2125 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
2126 for(efa= em->faces.first; efa; efa= efa->next) {
2127 if(efa->h==0 && (efa->f & SELECT)) {
2128 efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
2129 if(efa->v4) efa->v4->f1= SELECT;
2134 /* now we can count */
2135 for(eve= em->verts.first; eve; eve= eve->next) {
2137 if(eve->f1) countsel++;
2138 if(propmode) count++;
2142 /* note: in prop mode we need at least 1 selected */
2143 if (countsel==0) return;
2146 if (em->selected.last) {
2147 EditSelection *ese = em->selected.last;
2148 if ( ese->type == EDITVERT ) {
2149 eve_act = (EditVert *)ese->data;
2157 /* allocating scratch arrays */
2158 vectors = (float *)MEM_mallocN(t->total * 3 * sizeof(float), "scratch vectors");
2159 nears = (EditVert**)MEM_mallocN(t->total * sizeof(EditVert*), "scratch nears");
2161 else t->total = countsel;
2162 tob= t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Mesh EditMode)");
2164 Mat3CpyMat4(mtx, t->obedit->obmat);
2167 if(propmode) editmesh_set_connectivity_distance(em, t->total, vectors, nears);
2169 /* detect CrazySpace [tm] */
2171 if(modifiers_getCageIndex(t->obedit, NULL)>=0) {
2172 if(modifiers_isDeformed(t->scene, t->obedit)) {
2173 /* check if we can use deform matrices for modifier from the
2174 start up to stack, they are more accurate than quats */
2175 totleft= editmesh_get_first_deform_matrices(t->obedit, em, &defmats, &defcos);
2177 /* if we still have more modifiers, also do crazyspace
2178 correction with quats, relative to the coordinates after
2179 the modifiers that support deform matrices (defcos) */
2181 mappedcos= get_crazy_mapped_editverts(t);
2182 quats= MEM_mallocN( (t->total)*sizeof(float)*4, "crazy quats");
2183 set_crazyspace_quats(em, (float*)defcos, mappedcos, quats);
2185 MEM_freeN(mappedcos);
2194 /* find out which half we do */
2196 for (eve=em->verts.first; eve; eve=eve->next) {
2197 if(eve->h==0 && eve->f1 && eve->co[0]!=0.0f) {
2205 for (a=0, eve=em->verts.first; eve; eve=eve->next, a++) {
2207 if(propmode || eve->f1) {
2208 VertsToTransData(t, tob, em, eve);
2211 if(eve->f1) tob->flag |= TD_SELECTED;
2214 if(eve == eve_act) tob->flag |= TD_ACTIVE;
2219 VECCOPY(vec, E_VEC(eve));
2220 Mat3MulVecfl(mtx, vec);
2221 tob->dist= VecLength(vec);
2224 tob->flag |= TD_NOTCONNECTED;
2225 tob->dist = MAXFLOAT;
2230 if(defmats || (quats && eve->tmp.p)) {
2231 float mat[3][3], imat[3][3], qmat[3][3];
2233 /* use both or either quat and defmat correction */
2234 if(quats && eve->tmp.f) {
2235 QuatToMat3(eve->tmp.p, qmat);
2238 Mat3MulSerie(mat, mtx, qmat, defmats[a],
2239 NULL, NULL, NULL, NULL, NULL);
2241 Mat3MulMat3(mat, mtx, qmat);
2244 Mat3MulMat3(mat, mtx, defmats[a]);
2248 Mat3CpyMat3(tob->smtx, imat);
2249 Mat3CpyMat3(tob->mtx, mat);
2252 Mat3CpyMat3(tob->smtx, smtx);
2253 Mat3CpyMat3(tob->mtx, mtx);
2257 if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) {
2258 EditVert *vmir= editmesh_get_x_mirror_vert(t->obedit, em, tob->iloc); /* initializes octree on first call */
2259 if(vmir != eve) tob->extra = vmir;
2269 /* crazy space free */
2276 /* *** NODE EDITOR *** */
2277 void flushTransNodes(TransInfo *t)
2282 /* flush to 2d vector from internally used 3d vector */
2283 for(a=0, td= t->data2d; a<t->total; a++, td++) {
2284 td->loc2d[0]= td->loc[0];
2285 td->loc2d[1]= td->loc[1];
2289 /* *** SEQUENCE EDITOR *** */
2290 void flushTransSeq(TransInfo *t)
2292 ListBase *seqbasep= seq_give_editing(t->scene, FALSE)->seqbasep; /* Editing null check alredy done */
2294 TransData *td= t->data;
2295 TransData2D *td2d= t->data2d;
2296 TransDataSeq *tdsq= NULL;
2301 /* prevent updating the same seq twice
2302 * if the transdata order is changed this will mess up
2303 * but so will TransDataSeq */
2304 Sequence *seq_prev= NULL;
2306 /* flush to 2d vector from internally used 3d vector */
2307 for(a=0; a<t->total; a++, td++, td2d++) {
2309 tdsq= (TransDataSeq *)td->extra;
2311 new_frame= (int)(td2d->loc[0] + 0.5f);
2313 switch (tdsq->sel_flag) {
2315 if (seq->type != SEQ_META && seq_tx_test(seq)) /* for meta's, their children move */
2316 seq->start= new_frame - tdsq->start_offset;
2318 if (seq->depth==0) {
2319 seq->machine= (int)(td2d->loc[1] + 0.5f);
2320 CLAMP(seq->machine, 1, MAXSEQ);
2323 case SEQ_LEFTSEL: /* no vertical transform */
2324 seq_tx_set_final_left(seq, new_frame);
2325 seq_tx_handle_xlimits(seq, tdsq->flag&SEQ_LEFTSEL, tdsq->flag&SEQ_RIGHTSEL);
2326 fix_single_seq(seq); /* todo - move this into aftertrans update? - old seq tx needed it anyway */
2328 case SEQ_RIGHTSEL: /* no vertical transform */
2329 seq_tx_set_final_right(seq, new_frame);
2330 seq_tx_handle_xlimits(seq, tdsq->flag&SEQ_LEFTSEL, tdsq->flag&SEQ_RIGHTSEL);
2331 fix_single_seq(seq); /* todo - move this into aftertrans update? - old seq tx needed it anyway */
2335 if (seq != seq_prev) {
2337 /* Calculate this strip and all nested strips
2338 * children are ALWAYS transformed first
2339 * so we dont need to do this in another loop. */
2342 /* test overlap, displayes red outline */
2343 seq->flag &= ~SEQ_OVERLAP;
2344 if( seq_test_overlap(seqbasep, seq) ) {
2345 seq->flag |= SEQ_OVERLAP;
2349 calc_sequence_disp(seq);
2355 if (t->mode == TFM_TIME_TRANSLATE) { /* originally TFM_TIME_EXTEND, transform changes */
2356 /* Special annoying case here, need to calc metas with TFM_TIME_EXTEND only */
2357 seq= seqbasep->first;
2360 if (seq->type == SEQ_META && seq->flag & SELECT)
2367 /* ********************* UV ****************** */
2369 static void UVsToTransData(SpaceImage *sima, TransData *td, TransData2D *td2d, float *uv, int selected)
2373 ED_space_image_uv_aspect(sima, &aspx, &aspy);
2375 /* uv coords are scaled by aspects. this is needed for rotations and
2376 proportional editing to be consistent with the stretchted uv coords
2377 that are displayed. this also means that for display and numinput,
2378 and when the the uv coords are flushed, these are converted each time */
2379 td2d->loc[0] = uv[0]*aspx;
2380 td2d->loc[1] = uv[1]*aspy;
2381 td2d->loc[2] = 0.0f;
2385 td->loc = td2d->loc;
2386 VECCOPY(td->center, td->loc);
2387 VECCOPY(td->iloc, td->loc);
2389 memset(td->axismtx, 0, sizeof(td->axismtx));
2390 td->axismtx[2][2] = 1.0f;
2392 td->ext= NULL; td->tdi= NULL; td->val= NULL;
2395 td->flag |= TD_SELECTED;
2405 static void createTransUVs(bContext *C, TransInfo *t)
2407 SpaceImage *sima = (SpaceImage*)CTX_wm_space_data(C);
2408 Image *ima = CTX_data_edit_image(C);
2409 Scene *scene = CTX_data_scene(C);
2410 TransData *td = NULL;
2411 TransData2D *td2d = NULL;
2413 int count=0, countsel=0;
2414 int propmode = t->flag & T_PROP_EDIT;
2416 EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh;
2419 if(!ED_uvedit_test(t->obedit)) return;
2422 for (efa= em->faces.first; efa; efa= efa->next) {
2423 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2425 if(uvedit_face_visible(scene, ima, efa, tf)) {
2428 if (uvedit_uv_selected(scene, efa, tf, 0)) countsel++;
2429 if (uvedit_uv_selected(scene, efa, tf, 1)) countsel++;
2430 if (uvedit_uv_selected(scene, efa, tf, 2)) countsel++;
2431 if (efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) countsel++;
2433 count += (efa->v4)? 4: 3;
2439 /* note: in prop mode we need at least 1 selected */
2440 if (countsel==0) return;
2442 t->total= (propmode)? count: countsel;
2443 t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(UV Editing)");
2444 /* for each 2d uv coord a 3d vector is allocated, so that they can be
2445 treated just as if they were 3d verts */
2446 t->data2d= MEM_callocN(t->total*sizeof(TransData2D), "TransObData2D(UV Editing)");
2448 if(sima->flag & SI_CLIP_UV)
2449 t->flag |= T_CLIP_UV;
2454 for (efa= em->faces.first; efa; efa= efa->next) {
2455 if ((tf=(MTFace *)efa->tmp.p)) {
2457 UVsToTransData(sima, td++, td2d++, tf->uv[0], uvedit_uv_selected(scene, efa, tf, 0));
2458 UVsToTransData(sima, td++, td2d++, tf->uv[1], uvedit_uv_selected(scene, efa, tf, 1));
2459 UVsToTransData(sima, td++, td2d++, tf->uv[2], uvedit_uv_selected(scene, efa, tf, 2));
2461 UVsToTransData(sima, td++, td2d++, tf->uv[3], uvedit_uv_selected(scene, efa, tf, 3));
2463 if(uvedit_uv_selected(scene, efa, tf, 0)) UVsToTransData(sima, td++, td2d++, tf->uv[0], 1);
2464 if(uvedit_uv_selected(scene, efa, tf, 1)) UVsToTransData(sima, td++, td2d++, tf->uv[1], 1);
2465 if(uvedit_uv_selected(scene, efa, tf, 2)) UVsToTransData(sima, td++, td2d++, tf->uv[2], 1);
2466 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) UVsToTransData(sima, td++, td2d++, tf->uv[3], 1);
2471 if (sima->flag & SI_LIVE_UNWRAP)
2472 ED_uvedit_live_unwrap_begin(t->scene, t->obedit);
2475 void flushTransUVs(TransInfo *t)
2477 SpaceImage *sima = t->sa->spacedata.first;
2479 int a, width, height;
2480 float aspx, aspy, invx, invy;
2482 ED_space_image_uv_aspect(sima, &aspx, &aspy);
2483 ED_space_image_size(sima, &width, &height);
2487 /* flush to 2d vector from internally used 3d vector */
2488 for(a=0, td= t->data2d; a<t->total; a++, td++) {
2489 td->loc2d[0]= td->loc[0]*invx;
2490 td->loc2d[1]= td->loc[1]*invy;
2492 if((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)) {
2493 td->loc2d[0]= (float)floor(width*td->loc2d[0] + 0.5f)/width;
2494 td->loc2d[1]= (float)floor(height*td->loc2d[1] + 0.5f)/height;
2499 int clipUVTransform(TransInfo *t, float *vec, int resize)
2502 int a, clipx=1, clipy=1;
2503 float aspx, aspy, min[2], max[2];
2505 ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
2506 min[0]= min[1]= 0.0f;
2507 max[0]= aspx; max[1]= aspy;
2509 for(a=0, td= t->data; a<t->total; a++, td++) {
2510 DO_MINMAX2(td->loc, min, max);
2514 if(min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < aspx*0.5f)
2515 vec[0] *= t->center[0]/(t->center[0] - min[0]);
2516 else if(max[0] > aspx && t->center[0] < aspx)
2517 vec[0] *= (t->center[0] - aspx)/(t->center[0] - max[0]);
2521 if(min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < aspy*0.5f)
2522 vec[1] *= t->center[1]/(t->center[1] - min[1]);
2523 else if(max[1] > aspy && t->center[1] < aspy)
2524 vec[1] *= (t->center[1] - aspy)/(t->center[1] - max[1]);
2531 else if(max[0] > aspx)
2532 vec[0] -= max[0]-aspx;
2538 else if(max[1] > aspy)
2539 vec[1] -= max[1]-aspy;
2544 return (clipx || clipy);
2547 /* ********************* ACTION/NLA EDITOR ****************** */
2549 /* Called by special_aftertrans_update to make sure selected gp-frames replace
2550 * any other gp-frames which may reside on that frame (that are not selected).
2551 * It also makes sure gp-frames are still stored in chronological order after
2554 static void posttrans_gpd_clean (bGPdata *gpd)
2558 for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
2559 ListBase sel_buffer = {NULL, NULL};
2560 bGPDframe *gpf, *gpfn;
2561 bGPDframe *gfs, *gfsn;
2563 /* loop 1: loop through and isolate selected gp-frames to buffer
2564 * (these need to be sorted as they are isolated)
2566 for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
2570 if (gpf->flag & GP_FRAME_SELECT) {
2571 BLI_remlink(&gpl->frames, gpf);
2573 /* find place to add them in buffer
2574 * - go backwards as most frames will still be in order,
2575 * so doing it this way will be faster
2577 for (gfs= sel_buffer.last; gfs; gfs= gfs->prev) {
2578 /* if current (gpf) occurs after this one in buffer, add! */
2579 if (gfs->framenum < gpf->framenum) {
2580 BLI_insertlinkafter(&sel_buffer, gfs, gpf);
2586 BLI_addhead(&sel_buffer, gpf);
2590 /* error checking: it is unlikely, but may be possible to have none selected */
2591 if (sel_buffer.first == NULL)
2594 /* if all were selected (i.e. gpl->frames is empty), then just transfer sel-buf over */
2595 if (gpl->frames.first == NULL) {
2596 gpl->frames.first= sel_buffer.first;
2597 gpl->frames.last= sel_buffer.last;
2602 /* loop 2: remove duplicates of frames in buffers */
2603 for (gpf= gpl->frames.first; gpf && sel_buffer.first; gpf= gpfn) {
2606 /* loop through sel_buffer, emptying stuff from front of buffer if ok */
2607 for (gfs= sel_buffer.first; gfs && gpf; gfs= gfsn) {
2610 /* if this buffer frame needs to go before current, add it! */
2611 if (gfs->framenum < gpf->framenum) {
2612 /* transfer buffer frame to frames list (before current) */
2613 BLI_remlink(&sel_buffer, gfs);
2614 BLI_insertlinkbefore(&gpl->frames, gpf, gfs);
2616 /* if this buffer frame is on same frame, replace current with it and stop */
2617 else if (gfs->framenum == gpf->framenum) {
2618 /* transfer buffer frame to frames list (before current) */
2619 BLI_remlink(&sel_buffer, gfs);
2620 BLI_insertlinkbefore(&gpl->frames, gpf, gfs);
2622 /* get rid of current frame */
2624 //gpencil_layer_delframe(gpl, gpf);
2629 /* if anything is still in buffer, append to end */
2630 for (gfs= sel_buffer.first; gfs; gfs= gfsn) {
2633 BLI_remlink(&sel_buffer, gfs);
2634 BLI_addtail(&gpl->frames, gfs);
2639 /* Called during special_aftertrans_update to make sure selected keyframes replace
2640 * any other keyframes which may reside on that frame (that is not selected).
2642 static void posttrans_fcurve_clean (FCurve *fcu)
2644 float *selcache; /* cache for frame numbers of selected frames (icu->totvert*sizeof(float)) */
2645 int len, index, i; /* number of frames in cache, item index */
2647 /* allocate memory for the cache */
2648 // TODO: investigate using GHash for this instead?
2649 if (fcu->totvert == 0)
2651 selcache= MEM_callocN(sizeof(float)*fcu->totvert, "FCurveSelFrameNums");
2655 /* We do 2 loops, 1 for marking keyframes for deletion, one for deleting
2656 * as there is no guarantee what order the keyframes are exactly, even though
2657 * they have been sorted by time.
2660 /* Loop 1: find selected keyframes */
2661 for (i = 0; i < fcu->totvert; i++) {
2662 BezTriple *bezt= &fcu->bezt[i];
2664 if (BEZSELECTED(bezt)) {
2665 selcache[index]= bezt->vec[1][0];
2671 /* Loop 2: delete unselected keyframes on the same frames (if any keyframes were found) */
2673 for (i = 0; i < fcu->totvert; i++) {
2674 BezTriple *bezt= &fcu->bezt[i];
2676 if (BEZSELECTED(bezt) == 0) {
2677 /* check beztriple should be removed according to cache */
2678 for (index= 0; index < len; index++) {
2679 if (IS_EQ(bezt->vec[1][0], selcache[index])) {
2680 //delete_icu_key(icu, i, 0);
2683 else if (bezt->vec[1][0] > selcache[index])
2689 testhandles_fcurve(fcu);
2693 MEM_freeN(selcache);
2697 /* Called by special_aftertrans_update to make sure selected keyframes replace
2698 * any other keyframes which may reside on that frame (that is not selected).
2699 * remake_action_ipos should have already been called
2701 static void posttrans_action_clean (bAnimContext *ac, bAction *act)
2703 ListBase anim_data = {NULL, NULL};
2708 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);