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_action_types.h"
41 #include "DNA_armature_types.h"
42 #include "DNA_camera_types.h"
43 #include "DNA_curve_types.h"
44 #include "DNA_effect_types.h"
45 #include "DNA_image_types.h"
46 #include "DNA_ipo_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_texture_types.h"
63 #include "DNA_view3d_types.h"
64 #include "DNA_world_types.h"
65 #include "DNA_userdef_types.h"
66 #include "DNA_property_types.h"
67 #include "DNA_vfont_types.h"
68 #include "DNA_constraint_types.h"
69 #include "DNA_listBase.h"
70 #include "DNA_gpencil_types.h"
72 #include "BKE_action.h"
73 #include "BKE_armature.h"
74 #include "BKE_blender.h"
75 #include "BKE_cloth.h"
76 #include "BKE_context.h"
77 #include "BKE_curve.h"
78 #include "BKE_constraint.h"
79 #include "BKE_depsgraph.h"
80 #include "BKE_displist.h"
81 #include "BKE_DerivedMesh.h"
82 #include "BKE_effect.h"
84 #include "BKE_global.h"
86 #include "BKE_lattice.h"
89 #include "BKE_mball.h"
91 #include "BKE_modifier.h"
92 #include "BKE_object.h"
93 #include "BKE_particle.h"
94 #include "BKE_pointcache.h"
95 #include "BKE_softbody.h"
96 #include "BKE_utildefines.h"
97 #include "BKE_bmesh.h"
98 #include "BKE_context.h"
100 //#include "BIF_editaction.h"
101 //#include "BIF_editview.h"
102 //#include "BIF_editlattice.h"
103 //#include "BIF_editconstraint.h"
104 #include "BIF_editarmature.h"
105 //#include "BIF_editmesh.h"
106 //#include "BIF_editnla.h"
107 //#include "BIF_editsima.h"
108 //#include "BIF_editparticle.h"
110 //#include "BIF_keyframing.h"
111 //#include "BIF_poseobject.h"
112 //#include "BIF_meshtools.h"
113 //#include "BIF_mywindow.h"
114 //#include "BIF_resources.h"
115 #include "BIF_retopo.h"
116 //#include "BIF_screen.h"
117 //#include "BIF_space.h"
118 //#include "BIF_toolbox.h"
120 #include "ED_types.h"
121 #include "ED_anim_api.h"
122 #include "ED_keyframing.h"
123 #include "ED_keyframes_edit.h"
124 #include "ED_view3d.h"
127 #include "UI_view2d.h"
129 //#include "BSE_drawipo.h"
130 //#include "BSE_edit.h"
131 //#include "BSE_editipo.h"
132 //#include "BSE_editipo_types.h"
133 //#include "BSE_editaction_types.h"
135 //#include "BDR_drawaction.h" // list of keyframes in action
136 //#include "BDR_editobject.h" // reset_slowparents()
137 //#include "BDR_gpencil.h"
138 //#include "BDR_unwrapper.h"
140 #include "BLI_arithb.h"
141 #include "BLI_blenlib.h"
142 #include "BLI_editVert.h"
144 //#include "editmesh.h"
146 //#include "blendef.h"
148 //#include "mydevice.h"
150 extern ListBase editNurb;
151 extern ListBase editelems;
153 #include "transform.h"
155 #include "BLO_sys_types.h" // for intptr_t support
157 /************ STUBS TO GET COMPILE ************/
158 void transform_aspect_ratio_tface_uv(float *a1, float *a2) {}
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.0) {
840 targetless->flag |= CONSTRAINT_IK_AUTO;
844 if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0))
850 //con = add_new_constraint(CONSTRAINT_TYPE_KINEMATIC);
851 BLI_addtail(&pchan->constraints, con);
852 pchan->constflag |= (PCHAN_HAS_IK|PCHAN_HAS_TARGET); /* for draw, but also for detecting while pose solving */
854 if (targetless) { /* if exists use values from last targetless IK-constraint as base */
855 *data = *((bKinematicConstraint*)targetless->data);
858 data->flag= CONSTRAINT_IK_TIP;
859 data->flag |= CONSTRAINT_IK_TEMP|CONSTRAINT_IK_AUTO;
860 VECCOPY(data->grabtarget, pchan->pose_tail);
863 /* we include only a connected chain */
864 while ((pchan) && (pchan->bone->flag & BONE_CONNECTED)) {
865 /* here, we set ik-settings for bone from pchan->protectflag */
866 if (pchan->protectflag & OB_LOCK_ROTX) pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
867 if (pchan->protectflag & OB_LOCK_ROTY) pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
868 if (pchan->protectflag & OB_LOCK_ROTZ) pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
870 /* now we count this pchan as being included */
872 pchan= pchan->parent;
875 /* make a copy of maximum chain-length */
876 data->max_rootbone= data->rootbone;
881 /* bone is a candidate to get IK, but we don't do it if it has children connected */
882 static short pose_grab_with_ik_children(bPose *pose, Bone *bone)
885 short wentdeeper=0, added=0;
887 /* go deeper if children & children are connected */
888 for (bonec= bone->childbase.first; bonec; bonec= bonec->next) {
889 if (bonec->flag & BONE_CONNECTED) {
891 added+= pose_grab_with_ik_children(pose, bonec);
895 bPoseChannel *pchan= get_pose_channel(pose, bone->name);
897 added+= pose_grab_with_ik_add(pchan);
903 /* main call which adds temporal IK chains */
904 static short pose_grab_with_ik(Object *ob)
907 bPoseChannel *pchan, *parent;
911 if ((ob==NULL) || (ob->pose==NULL) || (ob->flag & OB_POSEMODE)==0)
916 /* Rule: allow multiple Bones (but they must be selected, and only one ik-solver per chain should get added) */
917 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
918 if (pchan->bone->layer & arm->layer) {
919 if (pchan->bone->flag & BONE_SELECTED) {
920 /* Rule: no IK for solitatry (unconnected) bones */
921 for (bonec=pchan->bone->childbase.first; bonec; bonec=bonec->next) {
922 if (bonec->flag & BONE_CONNECTED) {
926 if ((pchan->bone->flag & BONE_CONNECTED)==0 && (bonec == NULL))
929 /* rule: if selected Bone is not a root bone, it gets a temporal IK */
931 /* only adds if there's no IK yet (and no parent bone was selected) */
932 for (parent= pchan->parent; parent; parent= parent->parent) {
933 if (parent->bone->flag & BONE_SELECTED)
937 tot_ik += pose_grab_with_ik_add(pchan);
940 /* rule: go over the children and add IK to the tips */
941 tot_ik += pose_grab_with_ik_children(ob->pose, pchan->bone);
947 return (tot_ik) ? 1 : 0;
951 /* only called with pose mode active object now */
952 static void createTransPose(bContext *C, TransInfo *t, Object *ob)
959 TransDataExtension *tdx;
965 /* check validity of state */
966 arm=get_armature (ob);
967 if (arm==NULL || ob->pose==NULL) return;
969 if (arm->flag & ARM_RESTPOS) {
970 if(ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE)==0) {
971 notice("Pose edit not possible while Rest Position is enabled");
975 if (!(ob->lay & G.vd->lay)) return;
977 /* do we need to add temporal IK chains? */
978 if ((arm->flag & ARM_AUTO_IK) && t->mode==TFM_TRANSLATION) {
979 ik_on= pose_grab_with_ik(ob);
980 if (ik_on) t->flag |= T_AUTOIK;
983 /* set flags and count total (warning, can change transform to rotate) */
984 set_pose_transflags(t, ob);
986 if(t->total==0) return;
989 t->poseobj= ob; /* we also allow non-active objects to be transformed, in weightpaint */
991 /* make sure the lock is set OK, unlock can be accidentally saved? */
992 ob->pose->flag |= POSE_LOCKED;
993 ob->pose->flag &= ~POSE_DO_UNLOCK;
995 /* init trans data */
996 td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransPoseBone");
997 tdx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "TransPoseBoneExt");
998 for(i=0; i<t->total; i++, td++, tdx++) {
1004 /* use pose channels to fill trans data */
1006 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1007 if(pchan->bone->flag & BONE_TRANSFORM) {
1008 add_pose_transdata(t, pchan, ob, td);
1013 if(td != (t->data+t->total)) printf("Bone selection count error\n");
1015 /* initialise initial auto=ik chainlen's? */
1016 if (ik_on) transform_autoik_update(t, 0);
1020 /* ********************* armature ************** */
1022 static void createTransArmatureVerts(bContext *C, TransInfo *t)
1027 bArmature *arm= t->obedit->data;
1029 float mtx[3][3], smtx[3][3], delta[3], bonemat[3][3];
1032 for (ebo=G.edbo.first;ebo;ebo=ebo->next) {
1033 if(ebo->layer & arm->layer) {
1034 if (t->mode==TFM_BONESIZE) {
1035 if (ebo->flag & BONE_SELECTED)
1038 else if (t->mode==TFM_BONE_ROLL) {
1039 if (ebo->flag & BONE_SELECTED)
1043 if (ebo->flag & BONE_TIPSEL)
1045 if (ebo->flag & BONE_ROOTSEL)
1051 if (!t->total) return;
1053 Mat3CpyMat4(mtx, t->obedit->obmat);
1056 td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransEditBone");
1058 for (ebo=G.edbo.first;ebo;ebo=ebo->next){
1059 ebo->oldlength= ebo->length; // length==0.0 on extrude, used for scaling radius of bone points
1061 if(ebo->layer & arm->layer) {
1062 if (t->mode==TFM_BONE_ENVELOPE) {
1064 if (ebo->flag & BONE_ROOTSEL){
1065 td->val= &ebo->rad_head;
1068 VECCOPY (td->center, ebo->head);
1069 td->flag= TD_SELECTED;
1071 Mat3CpyMat3(td->smtx, smtx);
1072 Mat3CpyMat3(td->mtx, mtx);
1080 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) {
1098 if (ebo->flag & BONE_SELECTED) {
1099 if(arm->drawtype==ARM_ENVELOPE) {
1101 td->val= &ebo->dist;
1102 td->ival= ebo->dist;
1105 // abusive storage of scale in the loc pointer :)
1106 td->loc= &ebo->xwidth;
1107 VECCOPY (td->iloc, td->loc);
1110 VECCOPY (td->center, ebo->head);
1111 td->flag= TD_SELECTED;
1113 /* use local bone matrix */
1114 VecSubf(delta, ebo->tail, ebo->head);
1115 vec_roll_to_mat3(delta, ebo->roll, bonemat);
1116 Mat3MulMat3(td->mtx, mtx, bonemat);
1117 Mat3Inv(td->smtx, td->mtx);
1119 Mat3CpyMat3(td->axismtx, td->mtx);
1120 Mat3Ortho(td->axismtx);
1128 else if (t->mode==TFM_BONE_ROLL) {
1129 if (ebo->flag & BONE_SELECTED) {
1131 td->val= &(ebo->roll);
1132 td->ival= ebo->roll;
1134 VECCOPY (td->center, ebo->head);
1135 td->flag= TD_SELECTED;
1144 if (ebo->flag & BONE_TIPSEL){
1145 VECCOPY (td->iloc, ebo->tail);
1146 VECCOPY (td->center, td->iloc);
1148 td->flag= TD_SELECTED;
1149 if (ebo->flag & BONE_EDITMODE_LOCKED)
1150 td->protectflag = OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE;
1152 Mat3CpyMat3(td->smtx, smtx);
1153 Mat3CpyMat3(td->mtx, mtx);
1155 VecSubf(delta, ebo->tail, ebo->head);
1156 vec_roll_to_mat3(delta, ebo->roll, td->axismtx);
1158 if ((ebo->flag & BONE_ROOTSEL) == 0)
1169 if (ebo->flag & BONE_ROOTSEL){
1170 VECCOPY (td->iloc, ebo->head);
1171 VECCOPY (td->center, td->iloc);
1173 td->flag= TD_SELECTED;
1174 if (ebo->flag & BONE_EDITMODE_LOCKED)
1175 td->protectflag = OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE;
1177 Mat3CpyMat3(td->smtx, smtx);
1178 Mat3CpyMat3(td->mtx, mtx);
1180 VecSubf(delta, ebo->tail, ebo->head);
1181 vec_roll_to_mat3(delta, ebo->roll, td->axismtx);
1183 td->extra = ebo; /* to fix roll */
1197 /* ********************* meta elements ********* */
1199 static void createTransMBallVerts(bContext *C, TransInfo *t)
1205 TransDataExtension *tx;
1206 float mtx[3][3], smtx[3][3];
1207 int count=0, countsel=0;
1208 int propmode = t->flag & T_PROP_EDIT;
1211 for(ml= editelems.first; ml; ml= ml->next) {
1212 if(ml->flag & SELECT) countsel++;
1213 if(propmode) count++;
1216 /* note: in prop mode we need at least 1 selected */
1217 if (countsel==0) return;
1219 if(propmode) t->total = count;
1220 else t->total = countsel;
1222 td = t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(MBall EditMode)");
1223 tx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "MetaElement_TransExtension");
1225 Mat3CpyMat4(mtx, t->obedit->obmat);
1228 for(ml= editelems.first; ml; ml= ml->next) {
1229 if(propmode || (ml->flag & SELECT)) {
1231 VECCOPY(td->iloc, td->loc);
1232 VECCOPY(td->center, td->loc);
1234 if(ml->flag & SELECT) td->flag= TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
1235 else td->flag= TD_USEQUAT;
1237 Mat3CpyMat3(td->smtx, smtx);
1238 Mat3CpyMat3(td->mtx, mtx);
1243 /* Radius of MetaElem (mass of MetaElem influence) */
1244 if(ml->flag & MB_SCALE_RAD){
1253 /* expx/expy/expz determine "shape" of some MetaElem types */
1254 tx->size = &ml->expx;
1255 tx->isize[0] = ml->expx;
1256 tx->isize[1] = ml->expy;
1257 tx->isize[2] = ml->expz;
1259 /* quat is used for rotation of MetaElem */
1260 tx->quat = ml->quat;
1261 QUATCOPY(tx->iquat, ml->quat);
1272 /* ********************* curve/surface ********* */
1274 static void calc_distanceCurveVerts(TransData *head, TransData *tail) {
1275 TransData *td, *td_near = NULL;
1276 for (td = head; td<=tail; td++) {
1277 if (td->flag & TD_SELECTED) {
1283 dist = VecLenf(td_near->center, td->center);
1284 if (dist < (td-1)->dist) {
1285 td->dist = (td-1)->dist;
1292 td->dist = MAXFLOAT;
1293 td->flag |= TD_NOTCONNECTED;
1297 for (td = tail; td>=head; td--) {
1298 if (td->flag & TD_SELECTED) {
1304 dist = VecLenf(td_near->center, td->center);
1305 if (td->flag & TD_NOTCONNECTED || dist < td->dist || (td+1)->dist < td->dist) {
1306 td->flag &= ~TD_NOTCONNECTED;
1307 if (dist < (td+1)->dist) {
1308 td->dist = (td+1)->dist;
1318 /* Utility function for getting the handle data from bezier's */
1319 TransDataCurveHandleFlags *initTransDataCurveHandes(TransData *td, struct BezTriple *bezt) {
1320 TransDataCurveHandleFlags *hdata;
1321 td->flag |= TD_BEZTRIPLE;
1322 hdata = td->hdata = MEM_mallocN(sizeof(TransDataCurveHandleFlags), "CuHandle Data");
1323 hdata->ih1 = bezt->h1;
1324 hdata->h1 = &bezt->h1;
1325 hdata->ih2 = bezt->h2; /* incase the second is not selected */
1326 hdata->h2 = &bezt->h2;
1330 static void createTransCurveVerts(bContext *C, TransInfo *t)
1334 TransData *td = NULL;
1338 float mtx[3][3], smtx[3][3];
1340 int count=0, countsel=0;
1341 int propmode = t->flag & T_PROP_EDIT;
1343 /* count total of vertices, check identical as in 2nd loop for making transdata! */
1344 for(nu= editNurb.first; nu; nu= nu->next) {
1345 if((nu->type & 7)==CU_BEZIER) {
1346 for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) {
1348 if (G.f & G_HIDDENHANDLES) {
1349 if(bezt->f2 & SELECT) countsel+=3;
1350 if(propmode) count+= 3;
1352 if(bezt->f1 & SELECT) countsel++;
1353 if(bezt->f2 & SELECT) countsel++;
1354 if(bezt->f3 & SELECT) countsel++;
1355 if(propmode) count+= 3;
1361 for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) {
1363 if(propmode) count++;
1364 if(bp->f1 & SELECT) countsel++;
1369 /* note: in prop mode we need at least 1 selected */
1370 if (countsel==0) return;
1372 if(propmode) t->total = count;
1373 else t->total = countsel;
1374 t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Curve EditMode)");
1376 Mat3CpyMat4(mtx, t->obedit->obmat);
1380 for(nu= editNurb.first; nu; nu= nu->next) {
1381 if((nu->type & 7)==CU_BEZIER) {
1382 TransData *head, *tail;
1384 for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) {
1386 TransDataCurveHandleFlags *hdata = NULL;
1389 ((bezt->f2 & SELECT) && (G.f & G_HIDDENHANDLES)) ||
1390 ((bezt->f1 & SELECT) && (G.f & G_HIDDENHANDLES)==0)
1392 VECCOPY(td->iloc, bezt->vec[0]);
1393 td->loc= bezt->vec[0];
1394 VECCOPY(td->center, bezt->vec[1]);
1395 if (G.f & G_HIDDENHANDLES) {
1396 if(bezt->f2 & SELECT) td->flag= TD_SELECTED;
1399 if(bezt->f1 & SELECT) td->flag= TD_SELECTED;
1406 hdata = initTransDataCurveHandes(td, bezt);
1408 Mat3CpyMat3(td->smtx, smtx);
1409 Mat3CpyMat3(td->mtx, mtx);
1416 /* This is the Curve Point, the other two are handles */
1417 if(propmode || (bezt->f2 & SELECT)) {
1418 VECCOPY(td->iloc, bezt->vec[1]);
1419 td->loc= bezt->vec[1];
1420 VECCOPY(td->center, td->loc);
1421 if(bezt->f2 & SELECT) td->flag= TD_SELECTED;
1426 if (t->mode==TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/ /* TODO - make points scale */
1427 td->val = &(bezt->radius);
1428 td->ival = bezt->radius;
1429 } else if (t->mode==TFM_TILT) {
1430 td->val = &(bezt->alfa);
1431 td->ival = bezt->alfa;
1436 Mat3CpyMat3(td->smtx, smtx);
1437 Mat3CpyMat3(td->mtx, mtx);
1439 if ((bezt->f1&SELECT)==0 && (bezt->f3&SELECT)==0)
1440 /* If the middle is selected but the sides arnt, this is needed */
1441 if (hdata==NULL) { /* if the handle was not saved by the previous handle */
1442 hdata = initTransDataCurveHandes(td, bezt);
1450 ((bezt->f2 & SELECT) && (G.f & G_HIDDENHANDLES)) ||
1451 ((bezt->f3 & SELECT) && (G.f & G_HIDDENHANDLES)==0)
1453 VECCOPY(td->iloc, bezt->vec[2]);
1454 td->loc= bezt->vec[2];
1455 VECCOPY(td->center, bezt->vec[1]);
1456 if (G.f & G_HIDDENHANDLES) {
1457 if(bezt->f2 & SELECT) td->flag= TD_SELECTED;
1460 if(bezt->f3 & SELECT) td->flag= TD_SELECTED;
1467 if (hdata==NULL) { /* if the handle was not saved by the previous handle */
1468 hdata = initTransDataCurveHandes(td, bezt);
1471 Mat3CpyMat3(td->smtx, smtx);
1472 Mat3CpyMat3(td->mtx, mtx);
1479 else if (propmode && head != tail) {
1480 calc_distanceCurveVerts(head, tail-1);
1484 if (propmode && head != tail)
1485 calc_distanceCurveVerts(head, tail-1);
1487 /* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandes
1488 * but for now just dont change handle types */
1489 if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT) == 0)
1490 testhandlesNurb(nu); /* sets the handles based on their selection, do this after the data is copied to the TransData */
1493 TransData *head, *tail;
1495 for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) {
1497 if(propmode || (bp->f1 & SELECT)) {
1498 VECCOPY(td->iloc, bp->vec);
1500 VECCOPY(td->center, td->loc);
1501 if(bp->f1 & SELECT) td->flag= TD_SELECTED;
1506 if (t->mode==TFM_CURVE_SHRINKFATTEN || t->mode==TFM_RESIZE) {
1507 td->val = &(bp->radius);
1508 td->ival = bp->radius;
1510 td->val = &(bp->alfa);
1511 td->ival = bp->alfa;
1514 Mat3CpyMat3(td->smtx, smtx);
1515 Mat3CpyMat3(td->mtx, mtx);
1522 else if (propmode && head != tail) {
1523 calc_distanceCurveVerts(head, tail-1);
1527 if (propmode && head != tail)
1528 calc_distanceCurveVerts(head, tail-1);
1534 /* ********************* lattice *************** */
1536 static void createTransLatticeVerts(bContext *C, TransInfo *t)
1540 TransData *td = NULL;
1542 float mtx[3][3], smtx[3][3];
1544 int count=0, countsel=0;
1545 int propmode = t->flag & T_PROP_EDIT;
1548 a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
1551 if(bp->f1 & SELECT) countsel++;
1552 if(propmode) count++;
1557 /* note: in prop mode we need at least 1 selected */
1558 if (countsel==0) return;
1560 if(propmode) t->total = count;
1561 else t->total = countsel;
1562 t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Lattice EditMode)");
1564 Mat3CpyMat4(mtx, t->obedit->obmat);
1569 a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
1571 if(propmode || (bp->f1 & SELECT)) {
1573 VECCOPY(td->iloc, bp->vec);
1575 VECCOPY(td->center, td->loc);
1576 if(bp->f1 & SELECT) td->flag= TD_SELECTED;
1578 Mat3CpyMat3(td->smtx, smtx);
1579 Mat3CpyMat3(td->mtx, mtx);
1594 /* ******************* particle edit **************** */
1595 static void createTransParticleVerts(bContext *C, TransInfo *t)
1599 TransData *td = NULL;
1600 TransDataExtension *tx;
1601 Base *base = BASACT;
1603 ParticleSystem *psys = PE_get_current(ob);
1604 ParticleSystemModifierData *psmd = NULL;
1605 ParticleEditSettings *pset = PE_settings();
1606 ParticleData *pa = NULL;
1608 ParticleEditKey *key;
1610 int i,k, totpart, transformparticle;
1611 int count = 0, hasselected = 0;
1612 int propmode = t->flag & T_PROP_EDIT;
1614 if(psys==NULL || t->scene->selectmode==SCE_SELECT_PATH) return;
1616 psmd = psys_get_modifier(ob,psys);
1619 totpart = psys->totpart;
1620 base->flag |= BA_HAS_RECALC_DATA;
1622 for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
1623 pa->flag &= ~PARS_TRANSFORM;
1624 transformparticle= 0;
1626 if((pa->flag & PARS_HIDE)==0) {
1627 for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++) {
1628 if((key->flag&PEK_HIDE)==0) {
1629 if(key->flag&PEK_SELECT) {
1631 transformparticle= 1;
1634 transformparticle= 1;
1639 if(transformparticle) {
1640 count += pa->totkey;
1641 pa->flag |= PARS_TRANSFORM;
1645 /* note: in prop mode we need at least 1 selected */
1646 if (hasselected==0) return;
1649 td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Particle Mode)");
1651 if(t->mode == TFM_BAKE_TIME)
1652 tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "Particle_TransExtension");
1658 Mat4Invert(ob->imat,ob->obmat);
1660 for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
1661 TransData *head, *tail;
1664 if(!(pa->flag & PARS_TRANSFORM)) continue;
1666 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat);
1668 for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++) {
1669 VECCOPY(key->world_co, key->co);
1670 Mat4MulVecfl(mat, key->world_co);
1671 td->loc = key->world_co;
1673 VECCOPY(td->iloc, td->loc);
1674 VECCOPY(td->center, td->loc);
1676 if(key->flag & PEK_SELECT)
1677 td->flag |= TD_SELECTED;
1679 td->flag |= TD_SKIP;
1684 /* don't allow moving roots */
1685 if(k==0 && pset->flag & PE_LOCK_FIRST)
1686 td->protectflag |= OB_LOCK_LOC;
1691 if(t->mode == TFM_BAKE_TIME) {
1692 td->val = key->time;
1693 td->ival = *(key->time);
1694 /* abuse size and quat for min/max values */
1695 td->flag |= TD_NO_EXT;
1696 if(k==0) tx->size = 0;
1697 else tx->size = (key - 1)->time;
1699 if(k == pa->totkey - 1) tx->quat = 0;
1700 else tx->quat = (key + 1)->time;
1708 if (propmode && head != tail)
1709 calc_distanceCurveVerts(head, tail - 1);
1714 void flushTransParticles(TransInfo *t)
1716 #if 0 // TRANSFORM_FIX_ME
1717 Scene *scene = t->scene;
1719 ParticleSystem *psys = PE_get_current(ob);
1720 ParticleSystemModifierData *psmd;
1722 ParticleEditKey *key;
1724 float mat[4][4], imat[4][4], co[3];
1725 int i, k, propmode = t->flag & T_PROP_EDIT;
1727 psmd = psys_get_modifier(ob, psys);
1729 /* we do transform in world space, so flush world space position
1730 * back to particle local space */
1732 for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++, td++) {
1733 if(!(pa->flag & PARS_TRANSFORM)) continue;
1735 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat);
1736 Mat4Invert(imat,mat);
1738 for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++) {
1739 VECCOPY(co, key->world_co);
1740 Mat4MulVecfl(imat, co);
1742 /* optimization for proportional edit */
1743 if(!propmode || !FloatCompare(key->co, co, 0.0001f)) {
1744 VECCOPY(key->co, co);
1745 pa->flag |= PARS_EDIT_RECALC;
1750 PE_update_object(OBACT, 1);
1754 /* ********************* mesh ****************** */
1756 /* proportional distance based on connectivity */
1757 #define E_VEC(a) (vectors + (3 * (a)->tmp.l))
1758 #define E_NEAR(a) (nears[((a)->tmp.l)])
1759 #define THRESHOLD 0.0001f
1760 static void editmesh_set_connectivity_distance(EditMesh *em, int total, float *vectors, EditVert **nears)
1766 /* f2 flag is used for 'selection' */
1767 /* tmp.l is offset on scratch array */
1768 for(eve= em->verts.first; eve; eve= eve->next) {
1772 if(eve->f & SELECT) {
1775 E_VEC(eve)[0] = 0.0f;
1776 E_VEC(eve)[1] = 0.0f;
1777 E_VEC(eve)[2] = 0.0f;
1786 /* Floodfill routine */
1788 At worst this is n*n of complexity where n is number of edges
1789 Best case would be n if the list is ordered perfectly.
1790 Estimate is n log n in average (so not too bad)
1795 for(eed= em->edges.first; eed; eed= eed->next) {
1797 EditVert *v1= eed->v1, *v2= eed->v2;
1798 float *vec2 = E_VEC(v2);
1799 float *vec1 = E_VEC(v1);
1801 if (v1->f2 + v2->f2 == 4)
1807 float len1 = VecLength(vec1);
1808 float len2 = VecLength(vec2);
1810 /* for v2 if not selected */
1812 VecSubf(nvec, v2->co, E_NEAR(v1)->co);
1813 lenn = VecLength(nvec);
1815 if (lenn - len1 > THRESHOLD && len2 - lenn > THRESHOLD) {
1816 VECCOPY(vec2, nvec);
1817 E_NEAR(v2) = E_NEAR(v1);
1821 else if (len2 - len1 > THRESHOLD && len1 - lenn > THRESHOLD) {
1822 VECCOPY(vec2, vec1);
1823 E_NEAR(v2) = E_NEAR(v1);
1827 /* for v1 if not selected */
1829 VecSubf(nvec, v1->co, E_NEAR(v2)->co);
1830 lenn = VecLength(nvec);
1832 if (lenn - len2 > THRESHOLD && len1 - lenn > THRESHOLD) {
1833 VECCOPY(vec1, nvec);
1834 E_NEAR(v1) = E_NEAR(v2);
1838 else if (len1 - len2 > THRESHOLD && len2 - lenn > THRESHOLD) {
1839 VECCOPY(vec1, vec2);
1840 E_NEAR(v1) = E_NEAR(v2);
1847 VecSubf(vec2, v2->co, E_NEAR(v1)->co);
1849 if (VecLength(vec1) - VecLength(vec2) > THRESHOLD) {
1850 VECCOPY(vec2, vec1);
1852 E_NEAR(v2) = E_NEAR(v1);
1858 VecSubf(vec1, v1->co, E_NEAR(v2)->co);
1860 if (VecLength(vec2) - VecLength(vec1) > THRESHOLD) {
1861 VECCOPY(vec1, vec2);
1863 E_NEAR(v1) = E_NEAR(v2);
1871 /* loop-in-a-loop I know, but we need it! (ton) */
1872 static void get_face_center(float *cent, EditMesh *em, EditVert *eve)
1876 for(efa= em->faces.first; efa; efa= efa->next)
1878 if(efa->v1==eve || efa->v2==eve || efa->v3==eve || efa->v4==eve)
1881 VECCOPY(cent, efa->cent);
1885 //way to overwrite what data is edited with transform
1886 //static void VertsToTransData(TransData *td, EditVert *eve, BakeKey *key)
1887 static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert *eve)
1891 // td->loc = key->co;
1895 VECCOPY(td->center, td->loc);
1896 if(t->around==V3D_LOCAL && (em->selectmode & SCE_SELECT_FACE))
1897 get_face_center(td->center, em, eve);
1898 VECCOPY(td->iloc, td->loc);
1901 VECCOPY(td->axismtx[2], eve->no);
1907 td->axismtx[1][2] = 0.0f;
1913 if (t->mode == TFM_BWEIGHT) {
1914 td->val = &(eve->bweight);
1915 td->ival = eve->bweight;
1919 /* *********************** CrazySpace correction. Now without doing subsurf optimal ****************** */
1921 static void make_vertexcos__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
1923 float *vec = userData;
1929 static int modifiers_disable_subsurf_temporary(Object *ob)
1934 for(md=ob->modifiers.first; md; md=md->next)
1935 if(md->type==eModifierType_Subsurf)
1936 if(md->mode & eModifierMode_OnCage) {
1937 md->mode ^= eModifierMode_DisableTemporary;
1944 /* disable subsurf temporal, get mapped cos, and enable it */
1945 static float *get_crazy_mapped_editverts(TransInfo *t)
1947 Mesh *me= t->obedit->data;
1951 /* disable subsurf temporal, get mapped cos, and enable it */
1952 if(modifiers_disable_subsurf_temporary(t->obedit)) {
1953 /* need to make new derivemesh */
1954 makeDerivedMesh(t->scene, t->obedit, me->edit_mesh, CD_MASK_BAREMESH);
1957 /* now get the cage */
1958 dm= editmesh_get_derived_cage(t->scene, t->obedit, me->edit_mesh, CD_MASK_BAREMESH);
1960 vertexcos= MEM_mallocN(3*sizeof(float)*G.totvert, "vertexcos map");
1961 dm->foreachMappedVert(dm, make_vertexcos__mapFunc, vertexcos);
1965 /* set back the flag, no new cage needs to be built, transform does it */
1966 modifiers_disable_subsurf_temporary(t->obedit);
1971 #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])
1972 static void set_crazy_vertex_quat(float *quat, float *v1, float *v2, float *v3, float *def1, float *def2, float *def3)
1974 float vecu[3], vecv[3];
1977 TAN_MAKE_VEC(vecu, v1, v2);
1978 TAN_MAKE_VEC(vecv, v1, v3);
1979 triatoquat(v1, vecu, vecv, q1);
1981 TAN_MAKE_VEC(vecu, def1, def2);
1982 TAN_MAKE_VEC(vecv, def1, def3);
1983 triatoquat(def1, vecu, vecv, q2);
1985 QuatSub(quat, q2, q1);
1989 static void set_crazyspace_quats(EditMesh *em, float *origcos, float *mappedcos, float *quats)
1991 EditVert *eve, *prev;
1993 float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4;
1996 /* two abused locations in vertices */
1997 for(eve= em->verts.first; eve; eve= eve->next, index++) {
1999 eve->prev= (EditVert *)index;
2002 /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */
2003 for(efa= em->faces.first; efa; efa= efa->next) {
2005 /* retrieve mapped coordinates */
2006 v1= mappedcos + 3*(intptr_t)(efa->v1->prev);
2007 v2= mappedcos + 3*(intptr_t)(efa->v2->prev);
2008 v3= mappedcos + 3*(intptr_t)(efa->v3->prev);
2010 co1= (origcos)? origcos + 3*(intptr_t)(efa->v1->prev): efa->v1->co;
2011 co2= (origcos)? origcos + 3*(intptr_t)(efa->v2->prev): efa->v2->co;
2012 co3= (origcos)? origcos + 3*(intptr_t)(efa->v3->prev): efa->v3->co;
2014 if(efa->v2->tmp.p==NULL && efa->v2->f1) {
2015 set_crazy_vertex_quat(quats, co2, co3, co1, v2, v3, v1);
2016 efa->v2->tmp.p= (void*)quats;
2021 v4= mappedcos + 3*(intptr_t)(efa->v4->prev);
2022 co4= (origcos)? origcos + 3*(intptr_t)(efa->v4->prev): efa->v4->co;
2024 if(efa->v1->tmp.p==NULL && efa->v1->f1) {
2025 set_crazy_vertex_quat(quats, co1, co2, co4, v1, v2, v4);
2026 efa->v1->tmp.p= (void*)quats;
2029 if(efa->v3->tmp.p==NULL && efa->v3->f1) {
2030 set_crazy_vertex_quat(quats, co3, co4, co2, v3, v4, v2);
2031 efa->v3->tmp.p= (void*)quats;
2034 if(efa->v4->tmp.p==NULL && efa->v4->f1) {
2035 set_crazy_vertex_quat(quats, co4, co1, co3, v4, v1, v3);
2036 efa->v4->tmp.p= (void*)quats;
2041 if(efa->v1->tmp.p==NULL && efa->v1->f1) {
2042 set_crazy_vertex_quat(quats, co1, co2, co3, v1, v2, v3);
2043 efa->v1->tmp.p= (void*)quats;
2046 if(efa->v3->tmp.p==NULL && efa->v3->f1) {
2047 set_crazy_vertex_quat(quats, co3, co1, co2, v3, v1, v2);
2048 efa->v3->tmp.p= (void*)quats;
2054 /* restore abused prev pointer */
2055 for(prev= NULL, eve= em->verts.first; eve; prev= eve, eve= eve->next)
2060 void createTransBMeshVerts(TransInfo *t, BME_Mesh *bm, BME_TransData_Head *td) {
2066 tob = t->data = MEM_callocN(td->len*sizeof(TransData), "TransObData(Bevel tool)");
2068 for (i=0,v=bm->verts.first;v;v=v->next) {
2069 if ( (vtd = BME_get_transdata(td,v)) ) {
2070 tob->loc = vtd->loc;
2071 tob->val = &vtd->factor;
2072 VECCOPY(tob->iloc,vtd->co);
2073 VECCOPY(tob->center,vtd->org);
2074 VECCOPY(tob->axismtx[0],vtd->vec);
2075 tob->axismtx[1][0] = vtd->max ? *vtd->max : 0;
2080 /* since td is a memarena, it can hold more transdata than actual elements
2081 * (i.e. we can't depend on td->len to determine the number of actual elements) */
2085 static void createTransEditVerts(bContext *C, TransInfo *t)
2087 Scene *scene = CTX_data_scene(C);
2088 TransData *tob = NULL;
2089 EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh;
2091 EditVert **nears = NULL;
2092 EditVert *eve_act = NULL;
2093 float *vectors = NULL, *mappedcos = NULL, *quats= NULL;
2094 float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
2095 int count=0, countsel=0, a, totleft;
2096 int propmode = t->flag & T_PROP_EDIT;
2099 if ((t->options & CTX_NO_MIRROR) == 0 && (scene->toolsettings->editbutflag & B_MESH_X_MIRROR))
2104 // transform now requires awareness for select mode, so we tag the f1 flags in verts
2105 if(scene->selectmode & SCE_SELECT_VERTEX) {
2106 for(eve= em->verts.first; eve; eve= eve->next) {
2107 if(eve->h==0 && (eve->f & SELECT))
2113 else if(scene->selectmode & SCE_SELECT_EDGE) {
2115 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
2116 for(eed= em->edges.first; eed; eed= eed->next) {
2117 if(eed->h==0 && (eed->f & SELECT))
2118 eed->v1->f1= eed->v2->f1= SELECT;
2123 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
2124 for(efa= em->faces.first; efa; efa= efa->next) {
2125 if(efa->h==0 && (efa->f & SELECT)) {
2126 efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
2127 if(efa->v4) efa->v4->f1= SELECT;
2132 /* now we can count */
2133 for(eve= em->verts.first; eve; eve= eve->next) {
2135 if(eve->f1) countsel++;
2136 if(propmode) count++;
2140 /* note: in prop mode we need at least 1 selected */
2141 if (countsel==0) return;
2144 if (em->selected.last) {
2145 EditSelection *ese = em->selected.last;
2146 if ( ese->type == EDITVERT ) {
2147 eve_act = (EditVert *)ese->data;
2155 /* allocating scratch arrays */
2156 vectors = (float *)MEM_mallocN(t->total * 3 * sizeof(float), "scratch vectors");
2157 nears = (EditVert**)MEM_mallocN(t->total * sizeof(EditVert*), "scratch nears");
2159 else t->total = countsel;
2160 tob= t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Mesh EditMode)");
2162 Mat3CpyMat4(mtx, t->obedit->obmat);
2165 if(propmode) editmesh_set_connectivity_distance(em, t->total, vectors, nears);
2167 /* detect CrazySpace [tm] */
2169 if(modifiers_getCageIndex(t->obedit, NULL)>=0) {
2170 if(modifiers_isDeformed(t->obedit)) {
2171 /* check if we can use deform matrices for modifier from the
2172 start up to stack, they are more accurate than quats */
2173 totleft= editmesh_get_first_deform_matrices(t->obedit, em, &defmats, &defcos);
2175 /* if we still have more modifiers, also do crazyspace
2176 correction with quats, relative to the coordinates after
2177 the modifiers that support deform matrices (defcos) */
2179 mappedcos= get_crazy_mapped_editverts(t);
2180 quats= MEM_mallocN( (t->total)*sizeof(float)*4, "crazy quats");
2181 set_crazyspace_quats(em, (float*)defcos, mappedcos, quats);
2183 MEM_freeN(mappedcos);
2192 /* find out which half we do */
2194 for (eve=em->verts.first; eve; eve=eve->next) {
2195 if(eve->h==0 && eve->f1 && eve->co[0]!=0.0f) {
2203 for (a=0, eve=em->verts.first; eve; eve=eve->next, a++) {
2205 if(propmode || eve->f1) {
2206 VertsToTransData(t, tob, em, eve);
2209 if(eve->f1) tob->flag |= TD_SELECTED;
2212 if(eve == eve_act) tob->flag |= TD_ACTIVE;
2217 VECCOPY(vec, E_VEC(eve));
2218 Mat3MulVecfl(mtx, vec);
2219 tob->dist= VecLength(vec);
2222 tob->flag |= TD_NOTCONNECTED;
2223 tob->dist = MAXFLOAT;
2228 if(defmats || (quats && eve->tmp.p)) {
2229 float mat[3][3], imat[3][3], qmat[3][3];
2231 /* use both or either quat and defmat correction */
2232 if(quats && eve->tmp.f) {
2233 QuatToMat3(eve->tmp.p, qmat);
2236 Mat3MulSerie(mat, mtx, qmat, defmats[a],
2237 NULL, NULL, NULL, NULL, NULL);
2239 Mat3MulMat3(mat, mtx, qmat);
2242 Mat3MulMat3(mat, mtx, defmats[a]);
2246 Mat3CpyMat3(tob->smtx, imat);
2247 Mat3CpyMat3(tob->mtx, mat);
2250 Mat3CpyMat3(tob->smtx, smtx);
2251 Mat3CpyMat3(tob->mtx, mtx);
2255 if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) {
2256 EditVert *vmir= editmesh_get_x_mirror_vert(t->obedit, em, tob->iloc); /* initializes octree on first call */
2257 if(vmir != eve) tob->extra = vmir;
2267 /* crazy space free */
2274 /* *** NODE EDITOR *** */
2275 void flushTransNodes(TransInfo *t)
2280 /* flush to 2d vector from internally used 3d vector */
2281 for(a=0, td= t->data2d; a<t->total; a++, td++) {
2282 td->loc2d[0]= td->loc[0];
2283 td->loc2d[1]= td->loc[1];
2287 /* ********************* UV ****************** */
2289 static void UVsToTransData(TransData *td, TransData2D *td2d, float *uv, int selected)
2293 transform_aspect_ratio_tface_uv(&aspx, &aspy);
2295 /* uv coords are scaled by aspects. this is needed for rotations and
2296 proportional editing to be consistent with the stretchted uv coords
2297 that are displayed. this also means that for display and numinput,
2298 and when the the uv coords are flushed, these are converted each time */
2299 td2d->loc[0] = uv[0]*aspx;
2300 td2d->loc[1] = uv[1]*aspy;
2301 td2d->loc[2] = 0.0f;
2305 td->loc = td2d->loc;
2306 VECCOPY(td->center, td->loc);
2307 VECCOPY(td->iloc, td->loc);
2309 memset(td->axismtx, 0, sizeof(td->axismtx));
2310 td->axismtx[2][2] = 1.0f;
2312 td->ext= NULL; td->tdi= NULL; td->val= NULL;
2315 td->flag |= TD_SELECTED;
2325 static void createTransUVs(bContext *C, TransInfo *t)
2329 TransData *td = NULL;
2330 TransData2D *td2d = NULL;
2332 int count=0, countsel=0;
2333 int propmode = t->flag & T_PROP_EDIT;
2334 int efa_s1,efa_s2,efa_s3,efa_s4;
2336 EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh;
2339 if(is_uv_tface_editing_allowed()==0) return;
2342 if (G.sima->flag & SI_BE_SQUARE && !propmode) {
2343 for (efa= em->faces.first; efa; efa= efa->next) {
2344 /* store face pointer for second loop, prevent second lookup */
2345 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2346 if (simaFaceDraw_Check(efa, tf)) {
2349 efa_s1 = simaUVSel_Check(efa, tf, 0);
2350 efa_s2 = simaUVSel_Check(efa, tf, 1);
2351 efa_s3 = simaUVSel_Check(efa, tf, 2);
2353 efa_s4 = simaUVSel_Check(efa, tf, 3);
2354 if ( efa_s1 || efa_s2 || efa_s3 || efa_s4 ) {
2355 countsel += 4; /* all corners of this quad need their edges moved. so we must store TD for each */
2358 /* tri's are delt with normally when SI_BE_SQUARE's enabled */
2359 if (efa_s1) countsel++;
2360 if (efa_s2) countsel++;
2361 if (efa_s3) countsel++;
2368 for (efa= em->faces.first; efa; efa= efa->next) {
2369 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2370 if (simaFaceDraw_Check(efa, tf)) {
2373 if (simaUVSel_Check(efa, tf, 0)) countsel++;
2374 if (simaUVSel_Check(efa, tf, 1)) countsel++;
2375 if (simaUVSel_Check(efa, tf, 2)) countsel++;
2376 if (efa->v4 && simaUVSel_Check(efa, tf, 3)) countsel++;
2378 count += (efa->v4)? 4: 3;
2385 /* note: in prop mode we need at least 1 selected */
2386 if (countsel==0) return;
2388 t->total= (propmode)? count: countsel;
2389 t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(UV Editing)");
2390 /* for each 2d uv coord a 3d vector is allocated, so that they can be
2391 treated just as if they were 3d verts */
2392 t->data2d= MEM_callocN(t->total*sizeof(TransData2D), "TransObData2D(UV Editing)");
2394 if(G.sima->flag & SI_CLIP_UV)
2395 t->flag |= T_CLIP_UV;
2400 if (G.sima->flag & SI_BE_SQUARE && !propmode) {
2401 for (efa= em->faces.first; efa; efa= efa->next) {
2402 tf=(MTFace *)efa->tmp.p;
2404 efa_s1 = simaUVSel_Check(efa, tf, 0);
2405 efa_s2 = simaUVSel_Check(efa, tf, 1);
2406 efa_s3 = simaUVSel_Check(efa, tf, 2);
2409 efa_s4 = simaUVSel_Check(efa, tf, 3);
2411 if ( efa_s1 || efa_s2 || efa_s3 || efa_s4 ) {
2412 /* all corners of this quad need their edges moved. so we must store TD for each */
2414 UVsToTransData(td, td2d, tf->uv[0], efa_s1);
2415 if (!efa_s1) td->flag |= TD_SKIP;
2418 UVsToTransData(td, td2d, tf->uv[1], efa_s2);
2419 if (!efa_s2) td->flag |= TD_SKIP;
2422 UVsToTransData(td, td2d, tf->uv[2], efa_s3);
2423 if (!efa_s3) td->flag |= TD_SKIP;
2426 UVsToTransData(td, td2d, tf->uv[3], efa_s4);
2427 if (!efa_s4) td->flag |= TD_SKIP;
2431 /* tri's are delt with normally when SI_BE_SQUARE's enabled */
2432 if (efa_s1) UVsToTransData(td++, td2d++, tf->uv[0], 1);
2433 if (efa_s2) UVsToTransData(td++, td2d++, tf->uv[1], 1);
2434 if (efa_s3) UVsToTransData(td++, td2d++, tf->uv[2], 1);
2439 for (efa= em->faces.first; efa; efa= efa->next) {
2440 /*tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2441 if (simaFaceDraw_Check(efa, tf)) {*/
2442 if ((tf=(MTFace *)efa->tmp.p)) {
2444 UVsToTransData(td++, td2d++, tf->uv[0], simaUVSel_Check(efa, tf, 0));
2445 UVsToTransData(td++, td2d++, tf->uv[1], simaUVSel_Check(efa, tf, 1));
2446 UVsToTransData(td++, td2d++, tf->uv[2], simaUVSel_Check(efa, tf, 2));
2448 UVsToTransData(td++, td2d++, tf->uv[3], simaUVSel_Check(efa, tf, 3));
2450 if(simaUVSel_Check(efa, tf, 0)) UVsToTransData(td++, td2d++, tf->uv[0], 1);
2451 if(simaUVSel_Check(efa, tf, 1)) UVsToTransData(td++, td2d++, tf->uv[1], 1);
2452 if(simaUVSel_Check(efa, tf, 2)) UVsToTransData(td++, td2d++, tf->uv[2], 1);
2453 if(efa->v4 && simaUVSel_Check(efa, tf, 3)) UVsToTransData(td++, td2d++, tf->uv[3], 1);
2459 if (G.sima->flag & SI_LIVE_UNWRAP)
2460 unwrap_lscm_live_begin();
2464 void flushTransUVs(TransInfo *t)
2466 #if 0 // TRANSFORM_FIX_ME
2468 int a, width, height;
2470 EditMesh *em = ((Mesh *)ob->data)->edit_mesh;
2471 float aspx, aspy, invx, invy;
2473 transform_aspect_ratio_tface_uv(&aspx, &aspy);
2474 transform_width_height_tface_uv(&width, &height);
2478 /* flush to 2d vector from internally used 3d vector */
2479 for(a=0, td= t->data2d; a<t->total; a++, td++) {
2480 td->loc2d[0]= td->loc[0]*invx;
2481 td->loc2d[1]= td->loc[1]*invy;
2483 if((G.sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)) {
2484 td->loc2d[0]= (float)floor(width*td->loc2d[0] + 0.5f)/width;
2485 td->loc2d[1]= (float)floor(height*td->loc2d[1] + 0.5f)/height;
2489 if((G.sima->flag & SI_BE_SQUARE) && (t->flag & T_PROP_EDIT)==0 && (t->state != TRANS_CANCEL))
2490 be_square_tface_uv(em);
2492 /* this is overkill if G.sima->lock is not set, but still needed */
2493 object_uvs_changed(ob);
2497 int clipUVTransform(TransInfo *t, float *vec, int resize)
2499 #if 0 // TRANSFORM_FIX_ME
2501 int a, clipx=1, clipy=1;
2502 float aspx, aspy, min[2], max[2];
2504 transform_aspect_ratio_tface_uv(&aspx, &aspy);
2505 min[0]= min[1]= 0.0f;
2506 max[0]= aspx; max[1]= aspy;
2508 for(a=0, td= t->data; a<t->total; a++, td++) {
2509 DO_MINMAX2(td->loc, min, max);
2513 if(min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < aspx*0.5f)
2514 vec[0] *= t->center[0]/(t->center[0] - min[0]);
2515 else if(max[0] > aspx && t->center[0] < aspx)
2516 vec[0] *= (t->center[0] - aspx)/(t->center[0] - max[0]);
2520 if(min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < aspy*0.5f)
2521 vec[1] *= t->center[1]/(t->center[1] - min[1]);
2522 else if(max[1] > aspy && t->center[1] < aspy)
2523 vec[1] *= (t->center[1] - aspy)/(t->center[1] - max[1]);
2530 else if(max[0] > aspx)
2531 vec[0] -= max[0]-aspx;
2537 else if(max[1] > aspy)
2538 vec[1] -= max[1]-aspy;
2543 return (clipx || clipy);
2548 /* ********************* IPO EDITOR ************************* */
2550 /* for IPO Editor transform - but actual creation of transform structures is not performed here
2551 * due to bad globals that would need to be imported specially for this
2553 static void createTransIpoData(bContext *C, TransInfo *t)
2557 /* in editipo.c due to some globals that are defined in that file... */
2558 make_ipo_transdata(t);
2562 /* this function is called on recalcData to apply the transforms applied
2563 * to the transdata on to the actual keyframe data
2565 void flushTransIpoData(TransInfo *t)
2567 #if 0 // TRANSFORM_FIX_ME
2571 /* flush to 2d vector from internally used 3d vector */
2572 for (a=0, td= t->data2d; a<t->total; a++, td++) {
2573 // FIXME: autosnap needs to be here...
2575 /* we need to unapply the nla-scaling from the time in some situations */
2577 td->loc2d[0]= get_action_frame(OBACT, td->loc[0]);
2579 td->loc2d[0]= td->loc[0];
2581 /* when the icu that point comes from is a bitflag holder, don't allow adjusting values */
2582 if ((t->data[a].flag & TD_TIMEONLY)==0)
2583 td->loc2d[1]= td->loc[1];
2588 /* ********************* ACTION/NLA EDITOR ****************** */
2590 /* Called by special_aftertrans_update to make sure selected gp-frames replace
2591 * any other gp-frames which may reside on that frame (that are not selected).
2592 * It also makes sure gp-frames are still stored in chronological order after
2595 static void posttrans_gpd_clean (bGPdata *gpd)
2599 for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
2600 ListBase sel_buffer = {NULL, NULL};
2601 bGPDframe *gpf, *gpfn;
2602 bGPDframe *gfs, *gfsn;
2604 /* loop 1: loop through and isolate selected gp-frames to buffer
2605 * (these need to be sorted as they are isolated)
2607 for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
2611 if (gpf->flag & GP_FRAME_SELECT) {
2612 BLI_remlink(&gpl->frames, gpf);
2614 /* find place to add them in buffer
2615 * - go backwards as most frames will still be in order,
2616 * so doing it this way will be faster
2618 for (gfs= sel_buffer.last; gfs; gfs= gfs->prev) {
2619 /* if current (gpf) occurs after this one in buffer, add! */
2620 if (gfs->framenum < gpf->framenum) {
2621 BLI_insertlinkafter(&sel_buffer, gfs, gpf);
2627 BLI_addhead(&sel_buffer, gpf);
2631 /* error checking: it is unlikely, but may be possible to have none selected */
2632 if (sel_buffer.first == NULL)
2635 /* if all were selected (i.e. gpl->frames is empty), then just transfer sel-buf over */
2636 if (gpl->frames.first == NULL) {
2637 gpl->frames.first= sel_buffer.first;
2638 gpl->frames.last= sel_buffer.last;
2643 /* loop 2: remove duplicates of frames in buffers */
2644 for (gpf= gpl->frames.first; gpf && sel_buffer.first; gpf= gpfn) {
2647 /* loop through sel_buffer, emptying stuff from front of buffer if ok */
2648 for (gfs= sel_buffer.first; gfs && gpf; gfs= gfsn) {
2651 /* if this buffer frame needs to go before current, add it! */
2652 if (gfs->framenum < gpf->framenum) {
2653 /* transfer buffer frame to frames list (before current) */
2654 BLI_remlink(&sel_buffer, gfs);
2655 BLI_insertlinkbefore(&gpl->frames, gpf, gfs);
2657 /* if this buffer frame is on same frame, replace current with it and stop */
2658 else if (gfs->framenum == gpf->framenum) {
2659 /* transfer buffer frame to frames list (before current) */
2660 BLI_remlink(&sel_buffer, gfs);
2661 BLI_insertlinkbefore(&gpl->frames, gpf, gfs);
2663 /* get rid of current frame */
2665 //gpencil_layer_delframe(gpl, gpf);
2670 /* if anything is still in buffer, append to end */
2671 for (gfs= sel_buffer.first; gfs; gfs= gfsn) {
2674 BLI_remlink(&sel_buffer, gfs);
2675 BLI_addtail(&gpl->frames, gfs);
2680 /* Called during special_aftertrans_update to make sure selected keyframes replace
2681 * any other keyframes which may reside on that frame (that is not selected).
2683 static void posttrans_icu_clean (IpoCurve *icu)
2685 float *selcache; /* cache for frame numbers of selected frames (icu->totvert*sizeof(float)) */
2686 int len, index, i; /* number of frames in cache, item index */
2688 /* allocate memory for the cache */
2689 // TODO: investigate using GHash for this instead?
2690 if (icu->totvert == 0)
2692 selcache= MEM_callocN(sizeof(float)*icu->totvert, "IcuSelFrameNums");
2696 /* We do 2 loops, 1 for marking keyframes for deletion, one for deleting
2697 * as there is no guarantee what order the keyframes are exactly, even though
2698 * they have been sorted by time.
2701 /* Loop 1: find selected keyframes */
2702 for (i = 0; i < icu->totvert; i++) {
2703 BezTriple *bezt= &icu->bezt[i];
2705 if (BEZSELECTED(bezt)) {
2706 selcache[index]= bezt->vec[1][0];
2712 /* Loop 2: delete unselected keyframes on the same frames (if any keyframes were found) */
2714 for (i = 0; i < icu->totvert; i++) {
2715 BezTriple *bezt= &icu->bezt[i];
2717 if (BEZSELECTED(bezt) == 0) {
2718 /* check beztriple should be removed according to cache */
2719 for (index= 0; index < len; index++) {
2720 if (IS_EQ(bezt->vec[1][0], selcache[index])) {
2721 delete_icu_key(icu, i, 0);
2724 else if (bezt->vec[1][0] > selcache[index])
2730 testhandles_ipocurve(icu);
2734 MEM_freeN(selcache);
2737 /* Called by special_aftertrans_update to make sure selected keyframes replace
2738 * any other keyframes which may reside on that frame (that is not selected).
2739 * remake_action_ipos should have already been called
2741 static void posttrans_ipo_clean (Ipo *ipo)
2748 /* loop through relevant data, removing keyframes from the ipocurves
2749 * - all keyframes are converted in/out of global time
2751 for (icu= ipo->curve.first; icu; icu= icu->next) {
2752 posttrans_icu_clean(icu);
2756 /* Called by special_aftertrans_update to make sure selected keyframes replace
2757 * any other keyframes which may reside on that frame (that is not selected).
2758 * remake_action_ipos should have already been called
2760 static void posttrans_action_clean (bAnimContext *ac, bAction *act)
2762 ListBase anim_data = {NULL, NULL};