Blender V2.61 - r43446

transform_conversions.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #ifndef WIN32
00034 #include <unistd.h>
00035 #else
00036 #include <io.h>
00037 #endif
00038 #include <string.h>
00039 #include <math.h>
00040 
00041 #include "DNA_anim_types.h"
00042 #include "DNA_armature_types.h"
00043 #include "DNA_lattice_types.h"
00044 #include "DNA_meta_types.h"
00045 #include "DNA_node_types.h"
00046 #include "DNA_screen_types.h"
00047 #include "DNA_space_types.h"
00048 #include "DNA_sequence_types.h"
00049 #include "DNA_view3d_types.h"
00050 #include "DNA_constraint_types.h"
00051 #include "DNA_scene_types.h"
00052 #include "DNA_meshdata_types.h"
00053 #include "DNA_gpencil_types.h"
00054 #include "DNA_movieclip_types.h"
00055 
00056 #include "MEM_guardedalloc.h"
00057 
00058 #include "BKE_action.h"
00059 #include "BKE_armature.h"
00060 #include "BKE_context.h"
00061 #include "BKE_curve.h"
00062 #include "BKE_constraint.h"
00063 #include "BKE_depsgraph.h"
00064 #include "BKE_fcurve.h"
00065 #include "BKE_gpencil.h"
00066 #include "BKE_global.h"
00067 #include "BKE_key.h"
00068 #include "BKE_main.h"
00069 #include "BKE_modifier.h"
00070 #include "BKE_nla.h"
00071 #include "BKE_object.h"
00072 #include "BKE_particle.h"
00073 #include "BKE_sequencer.h"
00074 #include "BKE_pointcache.h"
00075 #include "BKE_bmesh.h"
00076 #include "BKE_scene.h"
00077 #include "BKE_report.h"
00078 #include "BKE_tracking.h"
00079 #include "BKE_movieclip.h"
00080 #include "BKE_node.h"
00081 
00082 
00083 #include "ED_anim_api.h"
00084 #include "ED_armature.h"
00085 #include "ED_particle.h"
00086 #include "ED_image.h"
00087 #include "ED_keyframing.h"
00088 #include "ED_keyframes_edit.h"
00089 #include "ED_object.h"
00090 #include "ED_markers.h"
00091 #include "ED_mesh.h"
00092 #include "ED_node.h"
00093 #include "ED_types.h"
00094 #include "ED_uvedit.h"
00095 #include "ED_clip.h"
00096 #include "ED_util.h"  /* for crazyspace correction */
00097 
00098 #include "WM_api.h"     /* for WM_event_add_notifier to deal with stabilization nodes */
00099 #include "WM_types.h"
00100 
00101 #include "UI_view2d.h"
00102 
00103 #include "BLI_math.h"
00104 #include "BLI_blenlib.h"
00105 #include "BLI_editVert.h"
00106 #include "BLI_utildefines.h"
00107 
00108 #include "RNA_access.h"
00109 
00110 extern ListBase editelems;
00111 
00112 #include "transform.h"
00113 
00114 #include "BLO_sys_types.h" // for intptr_t support
00115 
00116 /* local function prototype - for Object/Bone Constraints */
00117 static short constraints_list_needinv(TransInfo *t, ListBase *list);
00118 
00119 /* ************************** Functions *************************** */
00120 
00121 static void qsort_trans_data(TransInfo *t, TransData *head, TransData *tail, TransData *temp)
00122 {
00123     TransData *ihead = head;
00124     TransData *itail = tail;
00125     *temp = *head;
00126 
00127     while (head < tail)
00128     {
00129         if (t->flag & T_PROP_CONNECTED) {
00130             while ((tail->dist >= temp->dist) && (head < tail))
00131                 tail--;
00132         }
00133         else {
00134             while ((tail->rdist >= temp->rdist) && (head < tail))
00135                 tail--;
00136         }
00137 
00138         if (head != tail)
00139         {
00140             *head = *tail;
00141             head++;
00142         }
00143 
00144         if (t->flag & T_PROP_CONNECTED) {
00145             while ((head->dist <= temp->dist) && (head < tail))
00146                 head++;
00147         }
00148         else {
00149             while ((head->rdist <= temp->rdist) && (head < tail))
00150                 head++;
00151         }
00152 
00153         if (head != tail)
00154         {
00155             *tail = *head;
00156             tail--;
00157         }
00158     }
00159 
00160     *head = *temp;
00161     if (ihead < head) {
00162         qsort_trans_data(t, ihead, head-1, temp);
00163     }
00164     if (itail > head) {
00165         qsort_trans_data(t, head+1, itail, temp);
00166     }
00167 }
00168 
00169 void sort_trans_data_dist(TransInfo *t)
00170 {
00171     TransData temp;
00172     TransData *start = t->data;
00173     int i = 1;
00174 
00175     while(i < t->total && start->flag & TD_SELECTED) {
00176         start++;
00177         i++;
00178     }
00179     qsort_trans_data(t, start, t->data + t->total - 1, &temp);
00180 }
00181 
00182 static void sort_trans_data(TransInfo *t)
00183 {
00184     TransData *sel, *unsel;
00185     TransData temp;
00186     unsel = t->data;
00187     sel = t->data;
00188     sel += t->total - 1;
00189     while (sel > unsel) {
00190         while (unsel->flag & TD_SELECTED) {
00191             unsel++;
00192             if (unsel == sel) {
00193                 return;
00194             }
00195         }
00196         while (!(sel->flag & TD_SELECTED)) {
00197             sel--;
00198             if (unsel == sel) {
00199                 return;
00200             }
00201         }
00202         temp = *unsel;
00203         *unsel = *sel;
00204         *sel = temp;
00205         sel--;
00206         unsel++;
00207     }
00208 }
00209 
00210 /* distance calculated from not-selected vertex to nearest selected vertex
00211    warning; this is loops inside loop, has minor N^2 issues, but by sorting list it is OK */
00212 static void set_prop_dist(TransInfo *t, short with_dist)
00213 {
00214     TransData *tob;
00215     int a;
00216 
00217     for(a=0, tob= t->data; a<t->total; a++, tob++) {
00218 
00219         tob->rdist= 0.0f; // init, it was mallocced
00220 
00221         if((tob->flag & TD_SELECTED)==0) {
00222             TransData *td;
00223             int i;
00224             float dist, vec[3];
00225 
00226             tob->rdist = -1.0f; // signal for next loop
00227 
00228             for (i = 0, td= t->data; i < t->total; i++, td++) {
00229                 if(td->flag & TD_SELECTED) {
00230                     sub_v3_v3v3(vec, tob->center, td->center);
00231                     mul_m3_v3(tob->mtx, vec);
00232                     dist = normalize_v3(vec);
00233                     if (tob->rdist == -1.0f) {
00234                         tob->rdist = dist;
00235                     }
00236                     else if (dist < tob->rdist) {
00237                         tob->rdist = dist;
00238                     }
00239                 }
00240                 else break; // by definition transdata has selected items in beginning
00241             }
00242             if (with_dist) {
00243                 tob->dist = tob->rdist;
00244             }
00245         }
00246     }
00247 }
00248 
00249 /* ************************** CONVERSIONS ************************* */
00250 
00251 /* ********************* texture space ********* */
00252 
00253 static void createTransTexspace(TransInfo *t)
00254 {
00255     Scene *scene = t->scene;
00256     TransData *td;
00257     Object *ob;
00258     ID *id;
00259     short *texflag;
00260 
00261     ob = OBACT;
00262 
00263     if (ob == NULL) { // Shouldn't logically happen, but still...
00264         t->total = 0;
00265         return;
00266     }
00267 
00268     id = ob->data;
00269     if(id == NULL || !ELEM3( GS(id->name), ID_ME, ID_CU, ID_MB )) {
00270         t->total = 0;
00271         return;
00272     }
00273 
00274     t->total = 1;
00275     td= t->data= MEM_callocN(sizeof(TransData), "TransTexspace");
00276     td->ext= t->ext= MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
00277 
00278     td->flag= TD_SELECTED;
00279     copy_v3_v3(td->center, ob->obmat[3]);
00280     td->ob = ob;
00281 
00282     copy_m3_m4(td->mtx, ob->obmat);
00283     copy_m3_m4(td->axismtx, ob->obmat);
00284     normalize_m3(td->axismtx);
00285     invert_m3_m3(td->smtx, td->mtx);
00286 
00287     if (give_obdata_texspace(ob, &texflag, &td->loc, &td->ext->size, &td->ext->rot)) {
00288         ob->dtx |= OB_TEXSPACE;
00289         *texflag &= ~AUTOSPACE;
00290     }
00291 
00292     copy_v3_v3(td->iloc, td->loc);
00293     copy_v3_v3(td->ext->irot, td->ext->rot);
00294     copy_v3_v3(td->ext->isize, td->ext->size);
00295 }
00296 
00297 /* ********************* edge (for crease) ***** */
00298 
00299 static void createTransEdge(TransInfo *t)
00300 {
00301     EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh;
00302     TransData *td = NULL;
00303     EditEdge *eed;
00304     float mtx[3][3], smtx[3][3];
00305     int count=0, countsel=0;
00306     int propmode = t->flag & T_PROP_EDIT;
00307 
00308     for(eed= em->edges.first; eed; eed= eed->next) {
00309         if(eed->h==0) {
00310             if (eed->f & SELECT) countsel++;
00311             if (propmode) count++;
00312         }
00313     }
00314 
00315     if (countsel == 0)
00316         return;
00317 
00318     if(propmode) {
00319         t->total = count;
00320     }
00321     else {
00322         t->total = countsel;
00323     }
00324 
00325     td= t->data= MEM_callocN(t->total * sizeof(TransData), "TransCrease");
00326 
00327     copy_m3_m4(mtx, t->obedit->obmat);
00328     invert_m3_m3(smtx, mtx);
00329 
00330     for(eed= em->edges.first; eed; eed= eed->next) {
00331         if(eed->h==0 && (eed->f & SELECT || propmode)) {
00332             /* need to set center for center calculations */
00333             add_v3_v3v3(td->center, eed->v1->co, eed->v2->co);
00334             mul_v3_fl(td->center, 0.5f);
00335 
00336             td->loc= NULL;
00337             if (eed->f & SELECT)
00338                 td->flag= TD_SELECTED;
00339             else
00340                 td->flag= 0;
00341 
00342 
00343             copy_m3_m3(td->smtx, smtx);
00344             copy_m3_m3(td->mtx, mtx);
00345 
00346             td->ext = NULL;
00347             if (t->mode == TFM_BWEIGHT) {
00348                 td->val = &(eed->bweight);
00349                 td->ival = eed->bweight;
00350             }
00351             else {
00352                 td->val = &(eed->crease);
00353                 td->ival = eed->crease;
00354             }
00355 
00356             td++;
00357         }
00358     }
00359 }
00360 
00361 /* ********************* pose mode ************* */
00362 
00363 static bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
00364 {
00365     bConstraint *con= pchan->constraints.first;
00366 
00367     for(;con; con= con->next) {
00368         if(con->type==CONSTRAINT_TYPE_KINEMATIC && (con->enforce!=0.0f)) {
00369             bKinematicConstraint *data= con->data;
00370 
00371             if(data->tar==NULL)
00372                 return data;
00373             if(data->tar->type==OB_ARMATURE && data->subtarget[0]==0)
00374                 return data;
00375         }
00376     }
00377     return NULL;
00378 }
00379 
00380 static short apply_targetless_ik(Object *ob)
00381 {
00382     bPoseChannel *pchan, *parchan, *chanlist[256];
00383     bKinematicConstraint *data;
00384     int segcount, apply= 0;
00385 
00386     /* now we got a difficult situation... we have to find the
00387        target-less IK pchans, and apply transformation to the all
00388        pchans that were in the chain */
00389 
00390     for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
00391         data= has_targetless_ik(pchan);
00392         if(data && (data->flag & CONSTRAINT_IK_AUTO)) {
00393 
00394             /* fill the array with the bones of the chain (armature.c does same, keep it synced) */
00395             segcount= 0;
00396 
00397             /* exclude tip from chain? */
00398             if(!(data->flag & CONSTRAINT_IK_TIP))
00399                 parchan= pchan->parent;
00400             else
00401                 parchan= pchan;
00402 
00403             /* Find the chain's root & count the segments needed */
00404             for (; parchan; parchan=parchan->parent){
00405                 chanlist[segcount]= parchan;
00406                 segcount++;
00407 
00408                 if(segcount==data->rootbone || segcount>255) break; // 255 is weak
00409             }
00410             for(;segcount;segcount--) {
00411                 Bone *bone;
00412                 float rmat[4][4], tmat[4][4], imat[4][4];
00413 
00414                 /* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK  */
00415                 /* we put in channel the entire result of rmat= (channel * constraint * IK) */
00416                 /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat  */
00417                 /* rmat = pose_mat(b) * inv( pose_mat(b-1) * offs_bone ) */
00418 
00419                 parchan= chanlist[segcount-1];
00420                 bone= parchan->bone;
00421                 bone->flag |= BONE_TRANSFORM;   /* ensures it gets an auto key inserted */
00422 
00423                 if(parchan->parent) {
00424                     Bone *parbone= parchan->parent->bone;
00425                     float offs_bone[4][4];
00426 
00427                     /* offs_bone =  yoffs(b-1) + root(b) + bonemat(b) */
00428                     copy_m4_m3(offs_bone, bone->bone_mat);
00429 
00430                     /* The bone's root offset (is in the parent's coordinate system) */
00431                     copy_v3_v3(offs_bone[3], bone->head);
00432 
00433                     /* Get the length translation of parent (length along y axis) */
00434                     offs_bone[3][1]+= parbone->length;
00435 
00436                     /* pose_mat(b-1) * offs_bone */
00437                     if(parchan->bone->flag & BONE_HINGE) {
00438                         /* the rotation of the parent restposition */
00439                         copy_m4_m4(rmat, parbone->arm_mat); /* rmat used as temp */
00440 
00441                         /* the location of actual parent transform */
00442                         copy_v3_v3(rmat[3], offs_bone[3]);
00443                         offs_bone[3][0]= offs_bone[3][1]= offs_bone[3][2]= 0.0f;
00444                         mul_m4_v3(parchan->parent->pose_mat, rmat[3]);
00445 
00446                         mult_m4_m4m4(tmat, rmat, offs_bone);
00447                     }
00448                     else if(parchan->bone->flag & BONE_NO_SCALE) {
00449                         mult_m4_m4m4(tmat, parchan->parent->pose_mat, offs_bone);
00450                         normalize_m4(tmat);
00451                     }
00452                     else
00453                         mult_m4_m4m4(tmat, parchan->parent->pose_mat, offs_bone);
00454 
00455                     invert_m4_m4(imat, tmat);
00456                 }
00457                 else {
00458                     copy_m4_m3(tmat, bone->bone_mat);
00459 
00460                     copy_v3_v3(tmat[3], bone->head);
00461                     invert_m4_m4(imat, tmat);
00462                 }
00463                 /* result matrix */
00464                 mult_m4_m4m4(rmat, imat, parchan->pose_mat);
00465 
00466                 /* apply and decompose, doesn't work for constraints or non-uniform scale well */
00467                 {
00468                     float rmat3[3][3], qrmat[3][3], imat3[3][3], smat[3][3];
00469                     
00470                     copy_m3_m4(rmat3, rmat);
00471                     
00472                     /* rotation */
00473                         /* [#22409] is partially caused by this, as slight numeric error introduced during 
00474                          * the solving process leads to locked-axis values changing. However, we cannot modify
00475                          * the values here, or else there are huge discreptancies between IK-solver (interactive)
00476                          * and applied poses.
00477                          */
00478                     if (parchan->rotmode > 0)
00479                         mat3_to_eulO(parchan->eul, parchan->rotmode,rmat3);
00480                     else if (parchan->rotmode == ROT_MODE_AXISANGLE)
00481                         mat3_to_axis_angle(parchan->rotAxis, &parchan->rotAngle,rmat3);
00482                     else
00483                         mat3_to_quat(parchan->quat,rmat3);
00484                     
00485                     /* for size, remove rotation */
00486                     /* causes problems with some constraints (so apply only if needed) */
00487                     if (data->flag & CONSTRAINT_IK_STRETCH) {
00488                         if (parchan->rotmode > 0)
00489                             eulO_to_mat3( qrmat,parchan->eul, parchan->rotmode);
00490                         else if (parchan->rotmode == ROT_MODE_AXISANGLE)
00491                             axis_angle_to_mat3( qrmat,parchan->rotAxis, parchan->rotAngle);
00492                         else
00493                             quat_to_mat3( qrmat,parchan->quat);
00494                         
00495                         invert_m3_m3(imat3, qrmat);
00496                         mul_m3_m3m3(smat, rmat3, imat3);
00497                         mat3_to_size( parchan->size,smat);
00498                     }
00499                     
00500                     /* causes problems with some constraints (e.g. childof), so disable this */
00501                     /* as it is IK shouldn't affect location directly */
00502                     /* copy_v3_v3(parchan->loc, rmat[3]); */
00503                 }
00504 
00505             }
00506 
00507             apply= 1;
00508             data->flag &= ~CONSTRAINT_IK_AUTO;
00509         }
00510     }
00511 
00512     return apply;
00513 }
00514 
00515 static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransData *td)
00516 {
00517     Bone *bone= pchan->bone;
00518     float pmat[3][3], omat[3][3], bmat[3][3];
00519     float cmat[3][3], tmat[3][3];
00520     float vec[3];
00521 
00522     copy_v3_v3(vec, pchan->pose_mat[3]);
00523     copy_v3_v3(td->center, vec);
00524 
00525     td->ob = ob;
00526     td->flag = TD_SELECTED;
00527     if (bone->flag & BONE_HINGE_CHILD_TRANSFORM)
00528     {
00529         td->flag |= TD_NOCENTER;
00530     }
00531 
00532     if (bone->flag & BONE_TRANSFORM_CHILD)
00533     {
00534         td->flag |= TD_NOCENTER;
00535         td->flag |= TD_NO_LOC;
00536     }
00537 
00538     td->protectflag= pchan->protectflag;
00539 
00540     td->loc = pchan->loc;
00541     copy_v3_v3(td->iloc, pchan->loc);
00542 
00543     td->ext->size= pchan->size;
00544     copy_v3_v3(td->ext->isize, pchan->size);
00545 
00546     if (pchan->rotmode > 0) {
00547         td->ext->rot= pchan->eul;
00548         td->ext->rotAxis= NULL;
00549         td->ext->rotAngle= NULL;
00550         td->ext->quat= NULL;
00551         
00552         copy_v3_v3(td->ext->irot, pchan->eul);
00553     }
00554     else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
00555         td->ext->rot= NULL;
00556         td->ext->rotAxis= pchan->rotAxis;
00557         td->ext->rotAngle= &pchan->rotAngle;
00558         td->ext->quat= NULL;
00559         
00560         td->ext->irotAngle= pchan->rotAngle;
00561         copy_v3_v3(td->ext->irotAxis, pchan->rotAxis);
00562     }
00563     else {
00564         td->ext->rot= NULL;
00565         td->ext->rotAxis= NULL;
00566         td->ext->rotAngle= NULL;
00567         td->ext->quat= pchan->quat;
00568         
00569         copy_qt_qt(td->ext->iquat, pchan->quat);
00570     }
00571     td->ext->rotOrder= pchan->rotmode;
00572     
00573 
00574     /* proper way to get parent transform + own transform + constraints transform */
00575     copy_m3_m4(omat, ob->obmat);
00576 
00577     if (ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE) && (pchan->bone->flag & BONE_NO_LOCAL_LOCATION))
00578         unit_m3(bmat);
00579     else
00580         copy_m3_m3(bmat, pchan->bone->bone_mat);
00581 
00582     if (pchan->parent) {
00583         if(pchan->bone->flag & BONE_HINGE)
00584             copy_m3_m4(pmat, pchan->parent->bone->arm_mat);
00585         else
00586             copy_m3_m4(pmat, pchan->parent->pose_mat);
00587 
00588         if (constraints_list_needinv(t, &pchan->constraints)) {
00589             copy_m3_m4(tmat, pchan->constinv);
00590             invert_m3_m3(cmat, tmat);
00591             mul_serie_m3(td->mtx, bmat, pmat, omat, cmat, NULL,NULL,NULL,NULL);    // dang mulserie swaps args
00592         }
00593         else
00594             mul_serie_m3(td->mtx, bmat, pmat, omat, NULL,NULL,NULL,NULL,NULL);    // dang mulserie swaps args
00595     }
00596     else {
00597         if (constraints_list_needinv(t, &pchan->constraints)) {
00598             copy_m3_m4(tmat, pchan->constinv);
00599             invert_m3_m3(cmat, tmat);
00600             mul_serie_m3(td->mtx, bmat, omat, cmat, NULL,NULL,NULL,NULL,NULL);    // dang mulserie swaps args
00601         }
00602         else
00603             mul_m3_m3m3(td->mtx, omat, bmat);  // Mat3MulMat3 has swapped args!
00604     }
00605 
00606     invert_m3_m3(td->smtx, td->mtx);
00607 
00608     /* exceptional case: rotate the pose bone which also applies transformation
00609      * when a parentless bone has BONE_NO_LOCAL_LOCATION [] */
00610     if (!ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE) && (pchan->bone->flag & BONE_NO_LOCAL_LOCATION)) {
00611         if(pchan->parent) {
00612             /* same as td->smtx but without pchan->bone->bone_mat */
00613             td->flag |= TD_PBONE_LOCAL_MTX_C;
00614             mul_m3_m3m3(td->ext->l_smtx, pchan->bone->bone_mat, td->smtx);
00615         }
00616         else {
00617             td->flag |= TD_PBONE_LOCAL_MTX_P;
00618         }
00619     }
00620     
00621     /* for axismat we use bone's own transform */
00622     copy_m3_m4(pmat, pchan->pose_mat);
00623     mul_m3_m3m3(td->axismtx, omat, pmat);
00624     normalize_m3(td->axismtx);
00625 
00626     if (t->mode==TFM_BONESIZE) {
00627         bArmature *arm= t->poseobj->data;
00628 
00629         if(arm->drawtype==ARM_ENVELOPE) {
00630             td->loc= NULL;
00631             td->val= &bone->dist;
00632             td->ival= bone->dist;
00633         }
00634         else {
00635             // abusive storage of scale in the loc pointer :)
00636             td->loc= &bone->xwidth;
00637             copy_v3_v3(td->iloc, td->loc);
00638             td->val= NULL;
00639         }
00640     }
00641 
00642     /* in this case we can do target-less IK grabbing */
00643     if (t->mode==TFM_TRANSLATION) {
00644         bKinematicConstraint *data= has_targetless_ik(pchan);
00645         if(data) {
00646             if(data->flag & CONSTRAINT_IK_TIP) {
00647                 copy_v3_v3(data->grabtarget, pchan->pose_tail);
00648             }
00649             else {
00650                 copy_v3_v3(data->grabtarget, pchan->pose_head);
00651             }
00652             td->loc = data->grabtarget;
00653             copy_v3_v3(td->iloc, td->loc);
00654             data->flag |= CONSTRAINT_IK_AUTO;
00655 
00656             /* only object matrix correction */
00657             copy_m3_m3(td->mtx, omat);
00658             invert_m3_m3(td->smtx, td->mtx);
00659         }
00660     }
00661 
00662     /* store reference to first constraint */
00663     td->con= pchan->constraints.first;
00664 }
00665 
00666 static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
00667 {
00668     Bone *bone= lb->first;
00669 
00670     for(;bone;bone= bone->next) {
00671         if((bone->flag & BONE_HINGE) && (bone->flag & BONE_CONNECTED))
00672         {
00673             bone->flag |= BONE_HINGE_CHILD_TRANSFORM;
00674         }
00675         else if (bone->flag & BONE_TRANSFORM && (mode == TFM_ROTATION || mode == TFM_TRACKBALL) && around == V3D_LOCAL)
00676         {
00677             bone->flag |= BONE_TRANSFORM_CHILD;
00678         }
00679         else
00680         {
00681             bone->flag &= ~BONE_TRANSFORM;
00682         }
00683 
00684         bone_children_clear_transflag(mode, around, &bone->childbase);
00685     }
00686 }
00687 
00688 /* sets transform flags in the bones
00689  * returns total number of bones with BONE_TRANSFORM */
00690 int count_set_pose_transflags(int *out_mode, short around, Object *ob)
00691 {
00692     bArmature *arm= ob->data;
00693     bPoseChannel *pchan;
00694     Bone *bone;
00695     int mode = *out_mode;
00696     int hastranslation = 0;
00697     int total = 0;
00698 
00699     for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
00700         bone = pchan->bone;
00701         if (PBONE_VISIBLE(arm, bone)) {
00702             if ((bone->flag & BONE_SELECTED))
00703                 bone->flag |= BONE_TRANSFORM;
00704             else
00705                 bone->flag &= ~BONE_TRANSFORM;
00706             
00707             bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
00708             bone->flag &= ~BONE_TRANSFORM_CHILD;
00709         }
00710         else
00711             bone->flag &= ~BONE_TRANSFORM;
00712     }
00713 
00714     /* make sure no bone can be transformed when a parent is transformed */
00715     /* since pchans are depsgraph sorted, the parents are in beginning of list */
00716     if(mode != TFM_BONESIZE) {
00717         for(pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
00718             bone = pchan->bone;
00719             if(bone->flag & BONE_TRANSFORM)
00720                 bone_children_clear_transflag(mode, around, &bone->childbase);
00721         }
00722     }
00723     /* now count, and check if we have autoIK or have to switch from translate to rotate */
00724     hastranslation = 0;
00725 
00726     for(pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
00727         bone = pchan->bone;
00728         if(bone->flag & BONE_TRANSFORM) {
00729             total++;
00730             
00731             if(mode == TFM_TRANSLATION) {
00732                 if( has_targetless_ik(pchan)==NULL ) {
00733                     if(pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
00734                         if(pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM)
00735                             hastranslation = 1;
00736                     }
00737                     else if((pchan->protectflag & OB_LOCK_LOC)!=OB_LOCK_LOC)
00738                         hastranslation = 1;
00739                 }
00740                 else
00741                     hastranslation = 1;
00742             }
00743         }
00744     }
00745 
00746     /* if there are no translatable bones, do rotation */
00747     if(mode == TFM_TRANSLATION && !hastranslation)
00748     {
00749         *out_mode = TFM_ROTATION;
00750     }
00751 
00752     return total;
00753 }
00754 
00755 
00756 /* -------- Auto-IK ---------- */
00757 
00758 /* adjust pose-channel's auto-ik chainlen */
00759 static void pchan_autoik_adjust (bPoseChannel *pchan, short chainlen)
00760 {
00761     bConstraint *con;
00762 
00763     /* don't bother to search if no valid constraints */
00764     if ((pchan->constflag & (PCHAN_HAS_IK|PCHAN_HAS_TARGET))==0)
00765         return;
00766 
00767     /* check if pchan has ik-constraint */
00768     for (con= pchan->constraints.first; con; con= con->next) {
00769         if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce!=0.0f)) {
00770             bKinematicConstraint *data= con->data;
00771             
00772             /* only accept if a temporary one (for auto-ik) */
00773             if (data->flag & CONSTRAINT_IK_TEMP) {
00774                 /* chainlen is new chainlen, but is limited by maximum chainlen */
00775                 if ((chainlen==0) || (chainlen > data->max_rootbone))
00776                     data->rootbone= data->max_rootbone;
00777                 else
00778                     data->rootbone= chainlen;
00779             }
00780         }
00781     }
00782 }
00783 
00784 /* change the chain-length of auto-ik */
00785 void transform_autoik_update (TransInfo *t, short mode)
00786 {
00787     short *chainlen= &t->settings->autoik_chainlen;
00788     bPoseChannel *pchan;
00789 
00790     /* mode determines what change to apply to chainlen */
00791     if (mode == 1) {
00792         /* mode=1 is from WHEELMOUSEDOWN... increases len */
00793         (*chainlen)++;
00794     }
00795     else if (mode == -1) {
00796         /* mode==-1 is from WHEELMOUSEUP... decreases len */
00797         if (*chainlen > 0) (*chainlen)--;
00798     }
00799 
00800     /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */
00801     if (ELEM(NULL, t->poseobj, t->poseobj->pose))
00802         return;
00803 
00804     /* apply to all pose-channels */
00805     for (pchan=t->poseobj->pose->chanbase.first; pchan; pchan=pchan->next) {
00806         pchan_autoik_adjust(pchan, *chainlen);
00807     }
00808 }
00809 
00810 /* frees temporal IKs */
00811 static void pose_grab_with_ik_clear(Object *ob)
00812 {
00813     bKinematicConstraint *data;
00814     bPoseChannel *pchan;
00815     bConstraint *con, *next;
00816 
00817     for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
00818         /* clear all temporary lock flags */
00819         pchan->ikflag &= ~(BONE_IK_NO_XDOF_TEMP|BONE_IK_NO_YDOF_TEMP|BONE_IK_NO_ZDOF_TEMP);
00820         
00821         pchan->constflag &= ~(PCHAN_HAS_IK|PCHAN_HAS_TARGET);
00822         
00823         /* remove all temporary IK-constraints added */
00824         for (con= pchan->constraints.first; con; con= next) {
00825             next= con->next;
00826             if (con->type==CONSTRAINT_TYPE_KINEMATIC) {
00827                 data= con->data;
00828                 if (data->flag & CONSTRAINT_IK_TEMP) {
00829                     BLI_remlink(&pchan->constraints, con);
00830                     MEM_freeN(con->data);
00831                     MEM_freeN(con);
00832                     continue;
00833                 }
00834                 pchan->constflag |= PCHAN_HAS_IK;
00835                 if(data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]==0))
00836                     pchan->constflag |= PCHAN_HAS_TARGET;
00837             }
00838         }
00839     }
00840 }
00841 
00842 /* adds the IK to pchan - returns if added */
00843 static short pose_grab_with_ik_add(bPoseChannel *pchan)
00844 {
00845     bKinematicConstraint *targetless = NULL;
00846     bKinematicConstraint *data;
00847     bConstraint *con;
00848 
00849     /* Sanity check */
00850     if (pchan == NULL)
00851         return 0;
00852 
00853     /* Rule: not if there's already an IK on this channel */
00854     for (con= pchan->constraints.first; con; con= con->next) {
00855         if (con->type==CONSTRAINT_TYPE_KINEMATIC) {
00856             data= con->data;
00857             
00858             if (data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]=='\0')) {
00859                 /* make reference to constraint to base things off later (if it's the last targetless constraint encountered) */
00860                 targetless = (bKinematicConstraint *)con->data;
00861                 
00862                 /* but, if this is a targetless IK, we make it auto anyway (for the children loop) */
00863                 if (con->enforce!=0.0f) {
00864                     data->flag |= CONSTRAINT_IK_AUTO;
00865                     
00866                     /* if no chain length has been specified, just make things obey standard rotation locks too */
00867                     if (data->rootbone == 0) {
00868                         for (; pchan; pchan=pchan->parent) {
00869                             /* here, we set ik-settings for bone from pchan->protectflag */
00870                             // XXX: careful with quats/axis-angle rotations where we're locking 4d components
00871                             if (pchan->protectflag & OB_LOCK_ROTX) pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
00872                             if (pchan->protectflag & OB_LOCK_ROTY) pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
00873                             if (pchan->protectflag & OB_LOCK_ROTZ) pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
00874                         }
00875                     }
00876                     
00877                     return 0; 
00878                 }
00879             }
00880             
00881             if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0f))
00882                 return 0;
00883         }
00884     }
00885 
00886     con = add_pose_constraint(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
00887     pchan->constflag |= (PCHAN_HAS_IK|PCHAN_HAS_TARGET);    /* for draw, but also for detecting while pose solving */
00888     data= con->data;
00889     if (targetless) { 
00890         /* if exists, use values from last targetless (but disabled) IK-constraint as base */
00891         *data = *targetless;
00892     }
00893     else
00894         data->flag= CONSTRAINT_IK_TIP;
00895     data->flag |= CONSTRAINT_IK_TEMP|CONSTRAINT_IK_AUTO;
00896     copy_v3_v3(data->grabtarget, pchan->pose_tail);
00897     data->rootbone= 0; /* watch-it! has to be 0 here, since we're still on the same bone for the first time through the loop [#25885] */
00898     
00899     /* we only include bones that are part of a continual connected chain */
00900     while (pchan) {
00901         /* here, we set ik-settings for bone from pchan->protectflag */
00902         // XXX: careful with quats/axis-angle rotations where we're locking 4d components
00903         if (pchan->protectflag & OB_LOCK_ROTX) pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
00904         if (pchan->protectflag & OB_LOCK_ROTY) pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
00905         if (pchan->protectflag & OB_LOCK_ROTZ) pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
00906         
00907         /* now we count this pchan as being included */
00908         data->rootbone++;
00909         
00910         /* continue to parent, but only if we're connected to it */
00911         if (pchan->bone->flag & BONE_CONNECTED)
00912             pchan = pchan->parent;
00913         else
00914             pchan = NULL;
00915     }
00916 
00917     /* make a copy of maximum chain-length */
00918     data->max_rootbone= data->rootbone;
00919 
00920     return 1;
00921 }
00922 
00923 /* bone is a candidate to get IK, but we don't do it if it has children connected */
00924 static short pose_grab_with_ik_children(bPose *pose, Bone *bone)
00925 {
00926     Bone *bonec;
00927     short wentdeeper=0, added=0;
00928 
00929     /* go deeper if children & children are connected */
00930     for (bonec= bone->childbase.first; bonec; bonec= bonec->next) {
00931         if (bonec->flag & BONE_CONNECTED) {
00932             wentdeeper= 1;
00933             added+= pose_grab_with_ik_children(pose, bonec);
00934         }
00935     }
00936     if (wentdeeper==0) {
00937         bPoseChannel *pchan= get_pose_channel(pose, bone->name);
00938         if (pchan)
00939             added+= pose_grab_with_ik_add(pchan);
00940     }
00941 
00942     return added;
00943 }
00944 
00945 /* main call which adds temporal IK chains */
00946 static short pose_grab_with_ik(Object *ob)
00947 {
00948     bArmature *arm;
00949     bPoseChannel *pchan, *parent;
00950     Bone *bonec;
00951     short tot_ik= 0;
00952 
00953     if ((ob==NULL) || (ob->pose==NULL) || (ob->mode & OB_MODE_POSE)==0)
00954         return 0;
00955 
00956     arm = ob->data;
00957 
00958     /* Rule: allow multiple Bones (but they must be selected, and only one ik-solver per chain should get added) */
00959     for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
00960         if (pchan->bone->layer & arm->layer) {
00961             if (pchan->bone->flag & BONE_SELECTED) {
00962                 /* Rule: no IK for solitatry (unconnected) bones */
00963                 for (bonec=pchan->bone->childbase.first; bonec; bonec=bonec->next) {
00964                     if (bonec->flag & BONE_CONNECTED) {
00965                         break;
00966                     }
00967                 }
00968                 if ((pchan->bone->flag & BONE_CONNECTED)==0 && (bonec == NULL))
00969                     continue;
00970 
00971                 /* rule: if selected Bone is not a root bone, it gets a temporal IK */
00972                 if (pchan->parent) {
00973                     /* only adds if there's no IK yet (and no parent bone was selected) */
00974                     for (parent= pchan->parent; parent; parent= parent->parent) {
00975                         if (parent->bone->flag & BONE_SELECTED)
00976                             break;
00977                     }
00978                     if (parent == NULL)
00979                         tot_ik += pose_grab_with_ik_add(pchan);
00980                 }
00981                 else {
00982                     /* rule: go over the children and add IK to the tips */
00983                     tot_ik += pose_grab_with_ik_children(ob->pose, pchan->bone);
00984                 }
00985             }
00986         }
00987     }
00988 
00989     return (tot_ik) ? 1 : 0;
00990 }
00991 
00992 
00993 /* only called with pose mode active object now */
00994 static void createTransPose(TransInfo *t, Object *ob)
00995 {
00996     bArmature *arm;
00997     bPoseChannel *pchan;
00998     TransData *td;
00999     TransDataExtension *tdx;
01000     short ik_on= 0;
01001     int i;
01002 
01003     t->total= 0;
01004 
01005     /* check validity of state */
01006     arm= get_armature(ob);
01007     if ((arm==NULL) || (ob->pose==NULL)) return;
01008 
01009     if (arm->flag & ARM_RESTPOS) {
01010         if (ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE)==0) {
01011             // XXX use transform operator reports
01012             // BKE_report(op->reports, RPT_ERROR, "Can't select linked when sync selection is enabled");
01013             return;
01014         }
01015     }
01016 
01017     /* do we need to add temporal IK chains? */
01018     if ((arm->flag & ARM_AUTO_IK) && t->mode==TFM_TRANSLATION) {
01019         ik_on= pose_grab_with_ik(ob);
01020         if (ik_on) t->flag |= T_AUTOIK;
01021     }
01022 
01023     /* set flags and count total (warning, can change transform to rotate) */
01024     t->total = count_set_pose_transflags(&t->mode, t->around, ob);
01025 
01026     if(t->total == 0) return;
01027 
01028     t->flag |= T_POSE;
01029     t->poseobj= ob; /* we also allow non-active objects to be transformed, in weightpaint */
01030 
01031     /* init trans data */
01032     td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransPoseBone");
01033     tdx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "TransPoseBoneExt");
01034     for(i=0; i<t->total; i++, td++, tdx++) {
01035         td->ext= tdx;
01036         td->val = NULL;
01037     }
01038 
01039     /* use pose channels to fill trans data */
01040     td= t->data;
01041     for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
01042         if (pchan->bone->flag & BONE_TRANSFORM) {
01043             add_pose_transdata(t, pchan, ob, td);
01044             td++;
01045         }
01046     }
01047 
01048     if(td != (t->data+t->total)) {
01049         // XXX use transform operator reports
01050         // BKE_report(op->reports, RPT_DEBUG, "Bone selection count error");
01051     }
01052 
01053     /* initialise initial auto=ik chainlen's? */
01054     if (ik_on) transform_autoik_update(t, 0);
01055 }
01056 
01057 /* ********************* armature ************** */
01058 
01059 static void createTransArmatureVerts(TransInfo *t)
01060 {
01061     EditBone *ebo;
01062     bArmature *arm= t->obedit->data;
01063     ListBase *edbo = arm->edbo;
01064     TransData *td;
01065     float mtx[3][3], smtx[3][3], delta[3], bonemat[3][3];
01066     
01067     /* special hack for envelope drawmode and scaling:
01068      *  to allow scaling the size of the envelope around single points,
01069      *  mode should become TFM_BONE_ENVELOPE in this case
01070      */
01071     // TODO: maybe we need a separate hotkey for it, but this is consistent with 2.4x for now
01072     if ((t->mode == TFM_RESIZE) && (arm->drawtype==ARM_ENVELOPE))
01073         t->mode= TFM_BONE_ENVELOPE;
01074     
01075     t->total = 0;
01076     for (ebo = edbo->first; ebo; ebo = ebo->next)
01077     {
01078         if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) 
01079         {
01080             if (t->mode==TFM_BONESIZE)
01081             {
01082                 if (ebo->flag & BONE_SELECTED)
01083                     t->total++;
01084             }
01085             else if (t->mode==TFM_BONE_ROLL)
01086             {
01087                 if (ebo->flag & BONE_SELECTED)
01088                     t->total++;
01089             }
01090             else
01091             {
01092                 if (ebo->flag & BONE_TIPSEL)
01093                     t->total++;
01094                 if (ebo->flag & BONE_ROOTSEL)
01095                     t->total++;
01096             }
01097         }
01098     }
01099 
01100     if (!t->total) return;
01101 
01102     copy_m3_m4(mtx, t->obedit->obmat);
01103     invert_m3_m3(smtx, mtx);
01104 
01105     td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransEditBone");
01106 
01107     for (ebo = edbo->first; ebo; ebo = ebo->next)
01108     {
01109         ebo->oldlength = ebo->length;   // length==0.0 on extrude, used for scaling radius of bone points
01110 
01111         if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) 
01112         {
01113             if (t->mode==TFM_BONE_ENVELOPE)
01114             {
01115                 if (ebo->flag & BONE_ROOTSEL)
01116                 {
01117                     td->val= &ebo->rad_head;
01118                     td->ival= *td->val;
01119 
01120                     copy_v3_v3(td->center, ebo->head);
01121                     td->flag= TD_SELECTED;
01122 
01123                     copy_m3_m3(td->smtx, smtx);
01124                     copy_m3_m3(td->mtx, mtx);
01125 
01126                     td->loc = NULL;
01127                     td->ext = NULL;
01128                     td->ob = t->obedit;
01129 
01130                     td++;
01131                 }
01132                 if (ebo->flag & BONE_TIPSEL)
01133                 {
01134                     td->val= &ebo->rad_tail;
01135                     td->ival= *td->val;
01136                     copy_v3_v3(td->center, ebo->tail);
01137                     td->flag= TD_SELECTED;
01138 
01139                     copy_m3_m3(td->smtx, smtx);
01140                     copy_m3_m3(td->mtx, mtx);
01141 
01142                     td->loc = NULL;
01143                     td->ext = NULL;
01144                     td->ob = t->obedit;
01145 
01146                     td++;
01147                 }
01148 
01149             }
01150             else if (t->mode==TFM_BONESIZE)
01151             {
01152                 if (ebo->flag & BONE_SELECTED) {
01153                     if(arm->drawtype==ARM_ENVELOPE)
01154                     {
01155                         td->loc= NULL;
01156                         td->val= &ebo->dist;
01157                         td->ival= ebo->dist;
01158                     }
01159                     else
01160                     {
01161                         // abusive storage of scale in the loc pointer :)
01162                         td->loc= &ebo->xwidth;
01163                         copy_v3_v3(td->iloc, td->loc);
01164                         td->val= NULL;
01165                     }
01166                     copy_v3_v3(td->center, ebo->head);
01167                     td->flag= TD_SELECTED;
01168 
01169                     /* use local bone matrix */
01170                     sub_v3_v3v3(delta, ebo->tail, ebo->head);
01171                     vec_roll_to_mat3(delta, ebo->roll, bonemat);
01172                     mul_m3_m3m3(td->mtx, mtx, bonemat);
01173                     invert_m3_m3(td->smtx, td->mtx);
01174 
01175                     copy_m3_m3(td->axismtx, td->mtx);
01176                     normalize_m3(td->axismtx);
01177 
01178                     td->ext = NULL;
01179                     td->ob = t->obedit;
01180 
01181                     td++;
01182                 }
01183             }
01184             else if (t->mode==TFM_BONE_ROLL)
01185             {
01186                 if (ebo->flag & BONE_SELECTED)
01187                 {
01188                     td->loc= NULL;
01189                     td->val= &(ebo->roll);
01190                     td->ival= ebo->roll;
01191 
01192                     copy_v3_v3(td->center, ebo->head);
01193                     td->flag= TD_SELECTED;
01194 
01195                     td->ext = NULL;
01196                     td->ob = t->obedit;
01197 
01198                     td++;
01199                 }
01200             }
01201             else
01202             {
01203                 if (ebo->flag & BONE_TIPSEL)
01204                 {
01205                     copy_v3_v3(td->iloc, ebo->tail);
01206                     copy_v3_v3(td->center, (t->around==V3D_LOCAL) ? ebo->head : td->iloc);
01207                     td->loc= ebo->tail;
01208                     td->flag= TD_SELECTED;
01209                     if (ebo->flag & BONE_EDITMODE_LOCKED)
01210                         td->protectflag = OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE;
01211 
01212                     copy_m3_m3(td->smtx, smtx);
01213                     copy_m3_m3(td->mtx, mtx);
01214 
01215                     sub_v3_v3v3(delta, ebo->tail, ebo->head);
01216                     vec_roll_to_mat3(delta, ebo->roll, td->axismtx);
01217 
01218                     if ((ebo->flag & BONE_ROOTSEL) == 0)
01219                     {
01220                         td->extra = ebo;
01221                     }
01222 
01223                     td->ext = NULL;
01224                     td->val = NULL;
01225                     td->ob = t->obedit;
01226 
01227                     td++;
01228                 }
01229                 if (ebo->flag & BONE_ROOTSEL)
01230                 {
01231                     copy_v3_v3(td->iloc, ebo->head);
01232                     copy_v3_v3(td->center, td->iloc);
01233                     td->loc= ebo->head;
01234                     td->flag= TD_SELECTED;
01235                     if (ebo->flag & BONE_EDITMODE_LOCKED)
01236                         td->protectflag = OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE;
01237 
01238                     copy_m3_m3(td->smtx, smtx);
01239                     copy_m3_m3(td->mtx, mtx);
01240 
01241                     sub_v3_v3v3(delta, ebo->tail, ebo->head);
01242                     vec_roll_to_mat3(delta, ebo->roll, td->axismtx);
01243 
01244                     td->extra = ebo; /* to fix roll */
01245 
01246                     td->ext = NULL;
01247                     td->val = NULL;
01248                     td->ob = t->obedit;
01249 
01250                     td++;
01251                 }
01252             }
01253         }
01254     }
01255 }
01256 
01257 /* ********************* meta elements ********* */
01258 
01259 static void createTransMBallVerts(TransInfo *t)
01260 {
01261     MetaBall *mb = (MetaBall*)t->obedit->data;
01262     MetaElem *ml;
01263     TransData *td;
01264     TransDataExtension *tx;
01265     float mtx[3][3], smtx[3][3];
01266     int count=0, countsel=0;
01267     int propmode = t->flag & T_PROP_EDIT;
01268 
01269     /* count totals */
01270     for(ml= mb->editelems->first; ml; ml= ml->next) {
01271         if(ml->flag & SELECT) countsel++;
01272         if(propmode) count++;
01273     }
01274 
01275     /* note: in prop mode we need at least 1 selected */
01276     if (countsel==0) return;
01277 
01278     if(propmode) t->total = count;
01279     else t->total = countsel;
01280 
01281     td = t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(MBall EditMode)");
01282     tx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "MetaElement_TransExtension");
01283 
01284     copy_m3_m4(mtx, t->obedit->obmat);
01285     invert_m3_m3(smtx, mtx);
01286 
01287     for(ml= mb->editelems->first; ml; ml= ml->next) {
01288         if(propmode || (ml->flag & SELECT)) {
01289             td->loc= &ml->x;
01290             copy_v3_v3(td->iloc, td->loc);
01291             copy_v3_v3(td->center, td->loc);
01292 
01293             if(ml->flag & SELECT) td->flag= TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
01294             else td->flag= TD_USEQUAT;
01295 
01296             copy_m3_m3(td->smtx, smtx);
01297             copy_m3_m3(td->mtx, mtx);
01298 
01299             td->ext = tx;
01300 
01301             /* Radius of MetaElem (mass of MetaElem influence) */
01302             if(ml->flag & MB_SCALE_RAD){
01303                 td->val = &ml->rad;
01304                 td->ival = ml->rad;
01305             }
01306             else{
01307                 td->val = &ml->s;
01308                 td->ival = ml->s;
01309             }
01310 
01311             /* expx/expy/expz determine "shape" of some MetaElem types */
01312             tx->size = &ml->expx;
01313             tx->isize[0] = ml->expx;
01314             tx->isize[1] = ml->expy;
01315             tx->isize[2] = ml->expz;
01316 
01317             /* quat is used for rotation of MetaElem */
01318             tx->quat = ml->quat;
01319             copy_qt_qt(tx->iquat, ml->quat);
01320 
01321             tx->rot = NULL;
01322 
01323             td++;
01324             tx++;
01325         }
01326     }
01327 }
01328 
01329 /* ********************* curve/surface ********* */
01330 
01331 static void calc_distanceCurveVerts(TransData *head, TransData *tail)
01332 {
01333     TransData *td, *td_near = NULL;
01334     for (td = head; td<=tail; td++) {
01335         if (td->flag & TD_SELECTED) {
01336             td_near = td;
01337             td->dist = 0.0f;
01338         }
01339         else if(td_near) {
01340             float dist;
01341             dist = len_v3v3(td_near->center, td->center);
01342             if (dist < (td-1)->dist) {
01343                 td->dist = (td-1)->dist;
01344             }
01345             else {
01346                 td->dist = dist;
01347             }
01348         }
01349         else {
01350             td->dist = MAXFLOAT;
01351             td->flag |= TD_NOTCONNECTED;
01352         }
01353     }
01354     td_near = NULL;
01355     for (td = tail; td>=head; td--) {
01356         if (td->flag & TD_SELECTED) {
01357             td_near = td;
01358             td->dist = 0.0f;
01359         }
01360         else if(td_near) {
01361             float dist;
01362             dist = len_v3v3(td_near->center, td->center);
01363             if (td->flag & TD_NOTCONNECTED || dist < td->dist || (td+1)->dist < td->dist) {
01364                 td->flag &= ~TD_NOTCONNECTED;
01365                 if (dist < (td+1)->dist) {
01366                     td->dist = (td+1)->dist;
01367                 }
01368                 else {
01369                     td->dist = dist;
01370                 }
01371             }
01372         }
01373     }
01374 }
01375 
01376 /* Utility function for getting the handle data from bezier's */
01377 static TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt)
01378 {
01379     TransDataCurveHandleFlags *hdata;
01380     td->flag |= TD_BEZTRIPLE;
01381     hdata = td->hdata = MEM_mallocN(sizeof(TransDataCurveHandleFlags), "CuHandle Data");
01382     hdata->ih1 = bezt->h1;
01383     hdata->h1 = &bezt->h1;
01384     hdata->ih2 = bezt->h2; /* incase the second is not selected */
01385     hdata->h2 = &bezt->h2;
01386     return hdata;
01387 }
01388 
01389 static void createTransCurveVerts(bContext *C, TransInfo *t)
01390 {
01391     Object *obedit= CTX_data_edit_object(C);
01392     Curve *cu= obedit->data;
01393     TransData *td = NULL;
01394       Nurb *nu;
01395     BezTriple *bezt;
01396     BPoint *bp;
01397     float mtx[3][3], smtx[3][3];
01398     int a;
01399     int count=0, countsel=0;
01400     int propmode = t->flag & T_PROP_EDIT;
01401     short hide_handles = (cu->drawflag & CU_HIDE_HANDLES);
01402     ListBase *nurbs;
01403 
01404     /* to be sure */
01405     if(cu->editnurb==NULL) return;
01406 
01407     /* count total of vertices, check identical as in 2nd loop for making transdata! */
01408     nurbs= curve_editnurbs(cu);
01409     for(nu= nurbs->first; nu; nu= nu->next) {
01410         if(nu->type == CU_BEZIER) {
01411             for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) {
01412                 if(bezt->hide==0) {
01413                     if (hide_handles) {
01414                         if(bezt->f2 & SELECT) countsel+=3;
01415                         if(propmode) count+= 3;
01416                     } else {
01417                         if(bezt->f1 & SELECT) countsel++;
01418                         if(bezt->f2 & SELECT) countsel++;
01419                         if(bezt->f3 & SELECT) countsel++;
01420                         if(propmode) count+= 3;
01421                     }
01422                 }
01423             }
01424         }
01425         else {
01426             for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) {
01427                 if(bp->hide==0) {
01428                     if(propmode) count++;
01429                     if(bp->f1 & SELECT) countsel++;
01430                 }
01431             }
01432         }
01433     }
01434     /* note: in prop mode we need at least 1 selected */
01435     if (countsel==0) return;
01436 
01437     if(propmode) t->total = count;
01438     else t->total = countsel;
01439     t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Curve EditMode)");
01440 
01441     copy_m3_m4(mtx, t->obedit->obmat);
01442     invert_m3_m3(smtx, mtx);
01443 
01444     td = t->data;
01445     for(nu= nurbs->first; nu; nu= nu->next) {
01446         if(nu->type == CU_BEZIER) {
01447             TransData *head, *tail;
01448             head = tail = td;
01449             for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) {
01450                 if(bezt->hide==0) {
01451                     TransDataCurveHandleFlags *hdata = NULL;
01452 
01453                     if(     propmode ||
01454                             ((bezt->f2 & SELECT) && hide_handles) ||
01455                             ((bezt->f1 & SELECT) && hide_handles == 0)
01456                       ) {
01457                         copy_v3_v3(td->iloc, bezt->vec[0]);
01458                         td->loc= bezt->vec[0];
01459                         copy_v3_v3(td->center, bezt->vec[(hide_handles || bezt->f2 & SELECT) ? 1:0]);
01460                         if (hide_handles) {
01461                             if(bezt->f2 & SELECT) td->flag= TD_SELECTED;
01462                             else td->flag= 0;
01463                         } else {
01464                             if(bezt->f1 & SELECT) td->flag= TD_SELECTED;
01465                             else td->flag= 0;
01466                         }
01467                         td->ext = NULL;
01468                         td->val = NULL;
01469 
01470                         hdata = initTransDataCurveHandles(td, bezt);
01471 
01472                         copy_m3_m3(td->smtx, smtx);
01473                         copy_m3_m3(td->mtx, mtx);
01474 
01475                         td++;
01476                         count++;
01477                         tail++;
01478                     }
01479 
01480                     /* This is the Curve Point, the other two are handles */
01481                     if(propmode || (bezt->f2 & SELECT)) {
01482                         copy_v3_v3(td->iloc, bezt->vec[1]);
01483                         td->loc= bezt->vec[1];
01484                         copy_v3_v3(td->center, td->loc);
01485                         if(bezt->f2 & SELECT) td->flag= TD_SELECTED;
01486                         else td->flag= 0;
01487                         td->ext = NULL;
01488 
01489                         if (t->mode==TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/ /* TODO - make points scale */
01490                             td->val = &(bezt->radius);
01491                             td->ival = bezt->radius;
01492                         } else if (t->mode==TFM_TILT) {
01493                             td->val = &(bezt->alfa);
01494                             td->ival = bezt->alfa;
01495                         } else {
01496                             td->val = NULL;
01497                         }
01498 
01499                         copy_m3_m3(td->smtx, smtx);
01500                         copy_m3_m3(td->mtx, mtx);
01501 
01502                         if ((bezt->f1&SELECT)==0 && (bezt->f3&SELECT)==0)
01503                         /* If the middle is selected but the sides arnt, this is needed */
01504                         if (hdata==NULL) { /* if the handle was not saved by the previous handle */
01505                             hdata = initTransDataCurveHandles(td, bezt);
01506                         }
01507 
01508                         td++;
01509                         count++;
01510                         tail++;
01511                     }
01512                     if(     propmode ||
01513                             ((bezt->f2 & SELECT) && hide_handles) ||
01514                             ((bezt->f3 & SELECT) && hide_handles == 0)
01515                       ) {
01516                         copy_v3_v3(td->iloc, bezt->vec[2]);
01517                         td->loc= bezt->vec[2];
01518                         copy_v3_v3(td->center, bezt->vec[(hide_handles || bezt->f2 & SELECT) ? 1:2]);
01519                         if (hide_handles) {
01520                             if(bezt->f2 & SELECT) td->flag= TD_SELECTED;
01521                             else td->flag= 0;
01522                         } else {
01523                             if(bezt->f3 & SELECT) td->flag= TD_SELECTED;
01524                             else td->flag= 0;
01525                         }
01526                         td->ext = NULL;
01527                         td->val = NULL;
01528 
01529                         if (hdata==NULL) { /* if the handle was not saved by the previous handle */
01530                             hdata = initTransDataCurveHandles(td, bezt);
01531                         }
01532 
01533                         copy_m3_m3(td->smtx, smtx);
01534                         copy_m3_m3(td->mtx, mtx);
01535 
01536                         td++;
01537                         count++;
01538                         tail++;
01539                     }
01540                 }
01541                 else if (propmode && head != tail) {
01542                     calc_distanceCurveVerts(head, tail-1);
01543                     head = tail;
01544                 }
01545             }
01546             if (propmode && head != tail)
01547                 calc_distanceCurveVerts(head, tail-1);
01548 
01549             /* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandles
01550              * but for now just dont change handle types */
01551             if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT) == 0) {
01552                 /* sets the handles based on their selection, do this after the data is copied to the TransData */
01553                 testhandlesNurb(nu);
01554             }
01555         }
01556         else {
01557             TransData *head, *tail;
01558             head = tail = td;
01559             for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) {
01560                 if(bp->hide==0) {
01561                     if(propmode || (bp->f1 & SELECT)) {
01562                         copy_v3_v3(td->iloc, bp->vec);
01563                         td->loc= bp->vec;
01564                         copy_v3_v3(td->center, td->loc);
01565                         if(bp->f1 & SELECT) td->flag= TD_SELECTED;
01566                         else td->flag= 0;
01567                         td->ext = NULL;
01568 
01569                         if (t->mode==TFM_CURVE_SHRINKFATTEN || t->mode==TFM_RESIZE) {
01570                             td->val = &(bp->radius);
01571                             td->ival = bp->radius;
01572                         } else {
01573                             td->val = &(bp->alfa);
01574                             td->ival = bp->alfa;
01575                         }
01576 
01577                         copy_m3_m3(td->smtx, smtx);
01578                         copy_m3_m3(td->mtx, mtx);
01579 
01580                         td++;
01581                         count++;
01582                         tail++;
01583                     }
01584                 }
01585                 else if (propmode && head != tail) {
01586                     calc_distanceCurveVerts(head, tail-1);
01587                     head = tail;
01588                 }
01589             }
01590             if (propmode && head != tail)
01591                 calc_distanceCurveVerts(head, tail-1);
01592         }
01593     }
01594 }
01595 
01596 /* ********************* lattice *************** */
01597 
01598 static void createTransLatticeVerts(TransInfo *t)
01599 {
01600     Lattice *latt = ((Lattice*)t->obedit->data)->editlatt->latt;
01601     TransData *td = NULL;
01602     BPoint *bp;
01603     float mtx[3][3], smtx[3][3];
01604     int a;
01605     int count=0, countsel=0;
01606     int propmode = t->flag & T_PROP_EDIT;
01607 
01608     bp = latt->def;
01609     a  = latt->pntsu * latt->pntsv * latt->pntsw;
01610     while(a--) {
01611         if(bp->hide==0) {
01612             if(bp->f1 & SELECT) countsel++;
01613             if(propmode) count++;
01614         }
01615         bp++;
01616     }
01617 
01618      /* note: in prop mode we need at least 1 selected */
01619     if (countsel==0) return;
01620 
01621     if(propmode) t->total = count;
01622     else t->total = countsel;
01623     t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Lattice EditMode)");
01624 
01625     copy_m3_m4(mtx, t->obedit->obmat);
01626     invert_m3_m3(smtx, mtx);
01627 
01628     td = t->data;
01629     bp = latt->def;
01630     a  = latt->pntsu * latt->pntsv * latt->pntsw;
01631     while(a--) {
01632         if(propmode || (bp->f1 & SELECT)) {
01633             if(bp->hide==0) {
01634                 copy_v3_v3(td->iloc, bp->vec);
01635                 td->loc= bp->vec;
01636                 copy_v3_v3(td->center, td->loc);
01637                 if(bp->f1 & SELECT) td->flag= TD_SELECTED;
01638                 else td->flag= 0;
01639                 copy_m3_m3(td->smtx, smtx);
01640                 copy_m3_m3(td->mtx, mtx);
01641 
01642                 td->ext = NULL;
01643                 td->val = NULL;
01644 
01645                 td++;
01646                 count++;
01647             }
01648         }
01649         bp++;
01650     }
01651 }
01652 
01653 /* ******************* particle edit **************** */
01654 static void createTransParticleVerts(bContext *C, TransInfo *t)
01655 {
01656     TransData *td = NULL;
01657     TransDataExtension *tx;
01658     Base *base = CTX_data_active_base(C);
01659     Object *ob = CTX_data_active_object(C);
01660     ParticleEditSettings *pset = PE_settings(t->scene);
01661     PTCacheEdit *edit = PE_get_current(t->scene, ob);
01662     ParticleSystem *psys = NULL;
01663     ParticleSystemModifierData *psmd = NULL;
01664     PTCacheEditPoint *point;
01665     PTCacheEditKey *key;
01666     float mat[4][4];
01667     int i,k, transformparticle;
01668     int count = 0, hasselected = 0;
01669     int propmode = t->flag & T_PROP_EDIT;
01670 
01671     if(edit==NULL || t->settings->particle.selectmode==SCE_SELECT_PATH) return;
01672 
01673     psys = edit->psys;
01674 
01675     if(psys)
01676         psmd = psys_get_modifier(ob,psys);
01677 
01678     base->flag |= BA_HAS_RECALC_DATA;
01679 
01680     for(i=0, point=edit->points; i<edit->totpoint; i++, point++) {
01681         point->flag &= ~PEP_TRANSFORM;
01682         transformparticle= 0;
01683 
01684         if((point->flag & PEP_HIDE)==0) {
01685             for(k=0, key=point->keys; k<point->totkey; k++, key++) {
01686                 if((key->flag&PEK_HIDE)==0) {
01687                     if(key->flag&PEK_SELECT) {
01688                         hasselected= 1;
01689                         transformparticle= 1;
01690                     }
01691                     else if(propmode)
01692                         transformparticle= 1;
01693                 }
01694             }
01695         }
01696 
01697         if(transformparticle) {
01698             count += point->totkey;
01699             point->flag |= PEP_TRANSFORM;
01700         }
01701     }
01702 
01703      /* note: in prop mode we need at least 1 selected */
01704     if (hasselected==0) return;
01705 
01706     t->total = count;
01707     td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Particle Mode)");
01708 
01709     if(t->mode == TFM_BAKE_TIME)
01710         tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "Particle_TransExtension");
01711     else
01712         tx = t->ext = NULL;
01713 
01714     unit_m4(mat);
01715 
01716     invert_m4_m4(ob->imat,ob->obmat);
01717 
01718     for(i=0, point=edit->points; i<edit->totpoint; i++, point++) {
01719         TransData *head, *tail;
01720         head = tail = td;
01721 
01722         if(!(point->flag & PEP_TRANSFORM)) continue;
01723 
01724         if(psys && !(psys->flag & PSYS_GLOBAL_HAIR))
01725             psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + i, mat);
01726 
01727         for(k=0, key=point->keys; k<point->totkey; k++, key++) {
01728             if(key->flag & PEK_USE_WCO) {
01729                 copy_v3_v3(key->world_co, key->co);
01730                 mul_m4_v3(mat, key->world_co);
01731                 td->loc = key->world_co;
01732             }
01733             else
01734                 td->loc = key->co;
01735 
01736             copy_v3_v3(td->iloc, td->loc);
01737             copy_v3_v3(td->center, td->loc);
01738 
01739             if(key->flag & PEK_SELECT)
01740                 td->flag |= TD_SELECTED;
01741             else if(!propmode)
01742                 td->flag |= TD_SKIP;
01743 
01744             unit_m3(td->mtx);
01745             unit_m3(td->smtx);
01746 
01747             /* don't allow moving roots */
01748             if(k==0 && pset->flag & PE_LOCK_FIRST && (!psys || !(psys->flag & PSYS_GLOBAL_HAIR)))
01749                 td->protectflag |= OB_LOCK_LOC;
01750 
01751             td->ob = ob;
01752             td->ext = tx;
01753             if(t->mode == TFM_BAKE_TIME) {
01754                 td->val = key->time;
01755                 td->ival = *(key->time);
01756                 /* abuse size and quat for min/max values */
01757                 td->flag |= TD_NO_EXT;
01758                 if(k==0) tx->size = NULL;
01759                 else tx->size = (key - 1)->time;
01760 
01761                 if(k == point->totkey - 1) tx->quat = NULL;
01762                 else tx->quat = (key + 1)->time;
01763             }
01764 
01765             td++;
01766             if(tx)
01767                 tx++;
01768             tail++;
01769         }
01770         if (propmode && head != tail)
01771             calc_distanceCurveVerts(head, tail - 1);
01772     }
01773 }
01774 
01775 void flushTransParticles(TransInfo *t)
01776 {
01777     Scene *scene = t->scene;
01778     Object *ob = OBACT;
01779     PTCacheEdit *edit = PE_get_current(scene, ob);
01780     ParticleSystem *psys = edit->psys;
01781     ParticleSystemModifierData *psmd = NULL;
01782     PTCacheEditPoint *point;
01783     PTCacheEditKey *key;
01784     TransData *td;
01785     float mat[4][4], imat[4][4], co[3];
01786     int i, k, propmode = t->flag & T_PROP_EDIT;
01787 
01788     if(psys)
01789         psmd = psys_get_modifier(ob, psys);
01790 
01791     /* we do transform in world space, so flush world space position
01792      * back to particle local space (only for hair particles) */
01793     td= t->data;
01794     for(i=0, point=edit->points; i<edit->totpoint; i++, point++, td++) {
01795         if(!(point->flag & PEP_TRANSFORM)) continue;
01796 
01797         if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
01798             psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + i, mat);
01799             invert_m4_m4(imat,mat);
01800 
01801             for(k=0, key=point->keys; k<point->totkey; k++, key++) {
01802                 copy_v3_v3(co, key->world_co);
01803                 mul_m4_v3(imat, co);
01804 
01805 
01806                 /* optimization for proportional edit */
01807                 if(!propmode || !compare_v3v3(key->co, co, 0.0001f)) {
01808                     copy_v3_v3(key->co, co);
01809                     point->flag |= PEP_EDIT_RECALC;
01810                 }
01811             }
01812         }
01813         else
01814             point->flag |= PEP_EDIT_RECALC;
01815     }
01816 
01817     PE_update_object(scene, OBACT, 1);
01818 }
01819 
01820 /* ********************* mesh ****************** */
01821 
01822 /* proportional distance based on connectivity  */
01823 #define THRESHOLDFACTOR (1.0f-0.0001f)
01824 
01825 static int connectivity_edge(float mtx[][3], EditVert *v1, EditVert *v2)
01826 {
01827     float edge_vec[3];
01828     float edge_len;
01829     int done = 0;
01830 
01831     /* note: hidden verts are not being checked for, this assumes
01832      * flushing of hidden faces & edges is working right */
01833     
01834     if (v1->f2 + v2->f2 == 4)
01835         return 0;
01836     
01837     sub_v3_v3v3(edge_vec, v1->co, v2->co);
01838     mul_m3_v3(mtx, edge_vec);
01839 
01840     edge_len = len_v3(edge_vec);
01841 
01842     if (v1->f2) {
01843         if (v2->f2) {
01844             if (v2->tmp.fp + edge_len < THRESHOLDFACTOR * v1->tmp.fp) {
01845                 v1->tmp.fp = v2->tmp.fp + edge_len;
01846                 done = 1;
01847             } else if (v1->tmp.fp + edge_len < THRESHOLDFACTOR * v2->tmp.fp) {
01848                 v2->tmp.fp = v1->tmp.fp + edge_len;
01849                 done = 1;
01850             }
01851         }
01852         else {
01853             v2->f2 = 1;
01854             v2->tmp.fp = v1->tmp.fp + edge_len;
01855             done = 1;
01856         }
01857     }
01858     else if (v2->f2) {
01859         v1->f2 = 1;
01860         v1->tmp.fp = v2->tmp.fp + edge_len;
01861         done = 1;
01862     }
01863 
01864     return done;
01865 }
01866 
01867 static void editmesh_set_connectivity_distance(EditMesh *em, float mtx[][3])
01868 {
01869     EditVert *eve;
01870     EditEdge *eed;
01871     EditFace *efa;
01872     int done= 1;
01873 
01874     /* f2 flag is used for 'selection' */
01875     /* tmp.l is offset on scratch array   */
01876     for(eve= em->verts.first; eve; eve= eve->next) {
01877         if(eve->h==0) {
01878             eve->tmp.fp = 0;
01879 
01880             if(eve->f & SELECT) {
01881                 eve->f2= 2;
01882             }
01883             else {
01884                 eve->f2 = 0;
01885             }
01886         }
01887     }
01888 
01889 
01890     /* Floodfill routine */
01891     /*
01892     At worst this is n*n of complexity where n is number of edges
01893     Best case would be n if the list is ordered perfectly.
01894     Estimate is n log n in average (so not too bad)
01895     */
01896     while(done) {
01897         done= 0;
01898 
01899         for(eed= em->edges.first; eed; eed= eed->next) {
01900             if(eed->h==0) {
01901                 done |= connectivity_edge(mtx, eed->v1, eed->v2);
01902             }
01903         }
01904 
01905         /* do internal edges for quads */
01906         for(efa= em->faces.first; efa; efa= efa->next) {
01907             if (efa->v4 && efa->h==0) {
01908                 done |= connectivity_edge(mtx, efa->v1, efa->v3);
01909                 done |= connectivity_edge(mtx, efa->v2, efa->v4);
01910             }
01911         }
01912     }
01913 }
01914 
01915 /* loop-in-a-loop I know, but we need it! (ton) */
01916 static void get_face_center(float *cent, EditMesh *em, EditVert *eve)
01917 {
01918     EditFace *efa;
01919 
01920     for(efa= em->faces.first; efa; efa= efa->next)
01921         if(efa->f & SELECT)
01922             if(efa->v1==eve || efa->v2==eve || efa->v3==eve || efa->v4==eve)
01923                 break;
01924     if(efa) {
01925         copy_v3_v3(cent, efa->cent);
01926     }
01927 }
01928 
01929 static void get_edge_center(float *cent, EditMesh *em, EditVert *eve)
01930 {
01931     EditEdge *eed;
01932 
01933     for(eed= em->edges.first; eed; eed= eed->next)
01934         if(eed->f & SELECT)
01935             if(eed->v1==eve || eed->v2==eve)
01936                 break;
01937     if(eed) {
01938         mid_v3_v3v3(cent, eed->v1->co, eed->v2->co);
01939     }
01940 }
01941 
01942 /* way to overwrite what data is edited with transform
01943  * static void VertsToTransData(TransData *td, EditVert *eve, BakeKey *key) */
01944 static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert *eve)
01945 {
01946     td->flag = 0;
01947     //if(key)
01948     //  td->loc = key->co;
01949     //else
01950     td->loc = eve->co;
01951 
01952     copy_v3_v3(td->center, td->loc);
01953     if(t->around==V3D_LOCAL) {
01954         if(em->selectmode & SCE_SELECT_FACE)
01955             get_face_center(td->center, em, eve);
01956         else if(em->selectmode & SCE_SELECT_EDGE)
01957             get_edge_center(td->center, em, eve);
01958     }
01959     copy_v3_v3(td->iloc, td->loc);
01960 
01961     // Setting normals
01962     copy_v3_v3(td->axismtx[2], eve->no);
01963     td->axismtx[0][0]       =
01964         td->axismtx[0][1]   =
01965         td->axismtx[0][2]   =
01966         td->axismtx[1][0]   =
01967         td->axismtx[1][1]   =
01968         td->axismtx[1][2]   = 0.0f;
01969 
01970     td->ext = NULL;
01971     td->val = NULL;
01972     td->extra = NULL;
01973     if (t->mode == TFM_BWEIGHT) {
01974         td->val = &(eve->bweight);
01975         td->ival = eve->bweight;
01976     }
01977 }
01978 
01979 static void createTransEditVerts(bContext *C, TransInfo *t)
01980 {
01981     ToolSettings *ts = CTX_data_tool_settings(C);
01982     TransData *tob = NULL;
01983     EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh;
01984     EditVert *eve;
01985     EditVert *eve_act = NULL;
01986     float *mappedcos = NULL, *quats= NULL;
01987     float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
01988     int count=0, countsel=0, a, totleft;
01989     int propmode = (t->flag & T_PROP_EDIT) ? (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) : 0;
01990     int mirror = 0;
01991     short selectmode = ts->selectmode;
01992 
01993     if (t->flag & T_MIRROR)
01994     {
01995         mirror = 1;
01996     }
01997 
01998     /* edge slide forces edge select */
01999     if (t->mode == TFM_EDGE_SLIDE) {
02000         selectmode = SCE_SELECT_EDGE;
02001     }
02002 
02003     // transform now requires awareness for select mode, so we tag the f1 flags in verts
02004     if(selectmode & SCE_SELECT_VERTEX) {
02005         for(eve= em->verts.first; eve; eve= eve->next) {
02006             if(eve->h==0 && (eve->f & SELECT))
02007                 eve->f1= SELECT;
02008             else
02009                 eve->f1= 0;
02010         }
02011     }
02012     else if(selectmode & SCE_SELECT_EDGE) {
02013         EditEdge *eed;
02014         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
02015         for(eed= em->edges.first; eed; eed= eed->next) {
02016             if(eed->h==0 && (eed->f & SELECT))
02017                 eed->v1->f1= eed->v2->f1= SELECT;
02018         }
02019     }
02020     else {
02021         EditFace *efa;
02022         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
02023         for(efa= em->faces.first; efa; efa= efa->next) {
02024             if(efa->h==0 && (efa->f & SELECT)) {
02025                 efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
02026                 if(efa->v4) efa->v4->f1= SELECT;
02027             }
02028         }
02029     }
02030 
02031     /* now we can count */
02032     for(eve= em->verts.first; eve; eve= eve->next) {
02033         if(eve->h==0) {
02034             if(eve->f1) countsel++;
02035             if(propmode) count++;
02036         }
02037     }
02038 
02039      /* note: in prop mode we need at least 1 selected */
02040     if (countsel==0) return;
02041 
02042     /* check active */
02043     if (em->selected.last) {
02044         EditSelection *ese = em->selected.last;
02045         if ( ese->type == EDITVERT ) {
02046             eve_act = (EditVert *)ese->data;
02047         }
02048     }
02049 
02050 
02051     if(propmode) t->total = count;
02052     else t->total = countsel;
02053 
02054     tob= t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Mesh EditMode)");
02055 
02056     copy_m3_m4(mtx, t->obedit->obmat);
02057     invert_m3_m3(smtx, mtx);
02058 
02059     if(propmode & T_PROP_CONNECTED) {
02060         editmesh_set_connectivity_distance(em, mtx);
02061     }
02062 
02063     /* detect CrazySpace [tm] */
02064     if(modifiers_getCageIndex(t->scene, t->obedit, NULL, 1)>=0) {
02065         if(modifiers_isCorrectableDeformed(t->obedit)) {
02066             /* check if we can use deform matrices for modifier from the
02067                start up to stack, they are more accurate than quats */
02068             totleft= editmesh_get_first_deform_matrices(t->scene, t->obedit, em, &defmats, &defcos);
02069 
02070             /* if we still have more modifiers, also do crazyspace
02071                correction with quats, relative to the coordinates after
02072                the modifiers that support deform matrices (defcos) */
02073             if(totleft > 0) {
02074                 mappedcos= crazyspace_get_mapped_editverts(t->scene, t->obedit);
02075                 quats= MEM_mallocN( (t->total)*sizeof(float)*4, "crazy quats");
02076                 crazyspace_set_quats_editmesh(em, (float*)defcos, mappedcos, quats);
02077                 if(mappedcos)
02078                     MEM_freeN(mappedcos);
02079             }
02080 
02081             if(defcos)
02082                 MEM_freeN(defcos);
02083         }
02084     }
02085 
02086     /* find out which half we do */
02087     if(mirror) {
02088         for (eve=em->verts.first; eve; eve=eve->next) {
02089             if(eve->h==0 && eve->f1 && eve->co[0]!=0.0f) {
02090                 if(eve->co[0]<0.0f)
02091                 {
02092                     t->mirror = -1;
02093                     mirror = -1;
02094                 }
02095                 break;
02096             }
02097         }
02098     }
02099 
02100     for (a=0, eve=em->verts.first; eve; eve=eve->next, a++) {
02101         if(eve->h==0) {
02102             if(propmode || eve->f1) {
02103                 VertsToTransData(t, tob, em, eve);
02104 
02105                 /* selected */
02106                 if(eve->f1) tob->flag |= TD_SELECTED;
02107 
02108                 /* active */
02109                 if(eve == eve_act) tob->flag |= TD_ACTIVE;
02110 
02111                 if(propmode) {
02112                     if (eve->f2) {
02113                         tob->dist= eve->tmp.fp;
02114                     }
02115                     else {
02116                         tob->flag |= TD_NOTCONNECTED;
02117                         tob->dist = MAXFLOAT;
02118                     }
02119                 }
02120 
02121                 /* CrazySpace */
02122                 if(defmats || (quats && eve->tmp.p)) {
02123                     float mat[3][3], imat[3][3], qmat[3][3];
02124 
02125                     /* use both or either quat and defmat correction */
02126                     if(quats && eve->tmp.f) {
02127                         quat_to_mat3( qmat,eve->tmp.p);
02128 
02129                         if(defmats)
02130                             mul_serie_m3(mat, mtx, qmat, defmats[a],
02131                                 NULL, NULL, NULL, NULL, NULL);
02132                         else
02133                             mul_m3_m3m3(mat, mtx, qmat);
02134                     }
02135                     else
02136                         mul_m3_m3m3(mat, mtx, defmats[a]);
02137 
02138                     invert_m3_m3(imat, mat);
02139 
02140                     copy_m3_m3(tob->smtx, imat);
02141                     copy_m3_m3(tob->mtx, mat);
02142                 }
02143                 else {
02144                     copy_m3_m3(tob->smtx, smtx);
02145                     copy_m3_m3(tob->mtx, mtx);
02146                 }
02147 
02148                 /* Mirror? */
02149                 if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) {
02150                     EditVert *vmir= editmesh_get_x_mirror_vert(t->obedit, em, eve, tob->iloc, a);   /* initializes octree on first call */
02151                     if(vmir != eve) {
02152                         tob->extra = vmir;
02153                     }
02154                 }
02155                 tob++;
02156             }
02157         }
02158     }
02159     
02160     if (mirror != 0)
02161     {
02162         tob = t->data;
02163         for( a = 0; a < t->total; a++, tob++ )
02164         {
02165             if (ABS(tob->loc[0]) <= 0.00001f)
02166             {
02167                 tob->flag |= TD_MIRROR_EDGE;
02168             }
02169         }
02170     }
02171     
02172     /* crazy space free */
02173     if(quats)
02174         MEM_freeN(quats);
02175     if(defmats)
02176         MEM_freeN(defmats);
02177 }
02178 
02179 /* *** NODE EDITOR *** */
02180 void flushTransNodes(TransInfo *t)
02181 {
02182     int a;
02183     TransData2D *td;
02184 
02185     /* flush to 2d vector from internally used 3d vector */
02186     for(a=0, td= t->data2d; a<t->total; a++, td++) {
02187         td->loc2d[0]= td->loc[0];
02188         td->loc2d[1]= td->loc[1];
02189     }
02190     
02191     /* handle intersection with noodles */
02192     if(t->total==1) {
02193         ED_node_link_intersect_test(t->sa, 1);
02194     }
02195     
02196 }
02197 
02198 /* *** SEQUENCE EDITOR *** */
02199 
02200 /* commented _only_ because the meta may have animaion data which
02201  * needs moving too [#28158] */
02202 
02203 #define SEQ_TX_NESTED_METAS
02204 
02205 void flushTransSeq(TransInfo *t)
02206 {
02207     ListBase *seqbasep= seq_give_editing(t->scene, FALSE)->seqbasep; /* Editing null check already done */
02208     int a, new_frame, old_start;
02209     TransData *td= NULL;
02210     TransData2D *td2d= NULL;
02211     TransDataSeq *tdsq= NULL;
02212     Sequence *seq;
02213 
02214 
02215 
02216     /* prevent updating the same seq twice
02217      * if the transdata order is changed this will mess up
02218      * but so will TransDataSeq */
02219     Sequence *seq_prev= NULL;
02220 
02221     /* flush to 2d vector from internally used 3d vector */
02222     for(a=0, td= t->data, td2d= t->data2d; a<t->total; a++, td++, td2d++) {
02223         tdsq= (TransDataSeq *)td->extra;
02224         seq= tdsq->seq;
02225         old_start = seq->start;
02226         new_frame= (int)floor(td2d->loc[0] + 0.5f);
02227 
02228         switch (tdsq->sel_flag) {
02229         case SELECT:
02230 #ifdef SEQ_TX_NESTED_METAS
02231             if ((seq->depth != 0 || seq_tx_test(seq))) /* for meta's, their children move */
02232                 seq->start= new_frame - tdsq->start_offset;
02233 #else
02234             if (seq->type != SEQ_META && (seq->depth != 0 || seq_tx_test(seq))) /* for meta's, their children move */
02235                 seq->start= new_frame - tdsq->start_offset;
02236 #endif
02237             if (seq->depth==0) {
02238                 seq->machine= (int)floor(td2d->loc[1] + 0.5f);
02239                 CLAMP(seq->machine, 1, MAXSEQ);
02240             }
02241             break;
02242         case SEQ_LEFTSEL: /* no vertical transform  */
02243             seq_tx_set_final_left(seq, new_frame);
02244             seq_tx_handle_xlimits(seq, tdsq->flag&SEQ_LEFTSEL, tdsq->flag&SEQ_RIGHTSEL);
02245             seq_single_fix(seq); /* todo - move this into aftertrans update? - old seq tx needed it anyway */
02246             break;
02247         case SEQ_RIGHTSEL: /* no vertical transform  */
02248             seq_tx_set_final_right(seq, new_frame);
02249             seq_tx_handle_xlimits(seq, tdsq->flag&SEQ_LEFTSEL, tdsq->flag&SEQ_RIGHTSEL);
02250             seq_single_fix(seq); /* todo - move this into aftertrans update? - old seq tx needed it anyway */
02251             break;
02252         }
02253 
02254         if (seq != seq_prev) {
02255             if(seq->depth==0) {
02256                 /* Calculate this strip and all nested strips
02257                  * children are ALWAYS transformed first
02258                  * so we dont need to do this in another loop. */
02259                 calc_sequence(t->scene, seq);
02260             }
02261             else {
02262                 calc_sequence_disp(t->scene, seq);
02263             }
02264 
02265             if(tdsq->sel_flag == SELECT)
02266                 seq_offset_animdata(t->scene, seq, seq->start - old_start);
02267         }
02268         seq_prev= seq;
02269     }
02270 
02271     /* need to do the overlap check in a new loop otherwise adjacent strips
02272      * will not be updated and we'll get false positives */
02273     seq_prev= NULL;
02274     for(a=0, td= t->data, td2d= t->data2d; a<t->total; a++, td++, td2d++) {
02275 
02276         tdsq= (TransDataSeq *)td->extra;
02277         seq= tdsq->seq;
02278 
02279         if (seq != seq_prev) {
02280             if(seq->depth==0) {
02281                 /* test overlap, displayes red outline */
02282                 seq->flag &= ~SEQ_OVERLAP;
02283                 if( seq_test_overlap(seqbasep, seq) ) {
02284                     seq->flag |= SEQ_OVERLAP;
02285                 }
02286             }
02287         }
02288         seq_prev= seq;
02289     }
02290 
02291     if (t->mode == TFM_SEQ_SLIDE) { /* originally TFM_TIME_EXTEND, transform changes */
02292         /* Special annoying case here, need to calc metas with TFM_TIME_EXTEND only */
02293         seq= seqbasep->first;
02294 
02295         while(seq) {
02296             if (seq->type == SEQ_META && seq->flag & SELECT)
02297                 calc_sequence(t->scene, seq);
02298             seq= seq->next;
02299         }
02300     }
02301 }
02302 
02303 /* ********************* UV ****************** */
02304 
02305 static void UVsToTransData(SpaceImage *sima, TransData *td, TransData2D *td2d, float *uv, int selected)
02306 {
02307     float aspx, aspy;
02308 
02309     ED_space_image_uv_aspect(sima, &aspx, &aspy);
02310 
02311     /* uv coords are scaled by aspects. this is needed for rotations and
02312        proportional editing to be consistent with the stretchted uv coords
02313        that are displayed. this also means that for display and numinput,
02314        and when the the uv coords are flushed, these are converted each time */
02315     td2d->loc[0] = uv[0]*aspx;
02316     td2d->loc[1] = uv[1]*aspy;
02317     td2d->loc[2] = 0.0f;
02318     td2d->loc2d = uv;
02319 
02320     td->flag = 0;
02321     td->loc = td2d->loc;
02322     copy_v3_v3(td->center, td->loc);
02323     copy_v3_v3(td->iloc, td->loc);
02324 
02325     memset(td->axismtx, 0, sizeof(td->axismtx));
02326     td->axismtx[2][2] = 1.0f;
02327 
02328     td->ext= NULL; td->val= NULL;
02329 
02330     if(selected) {
02331         td->flag |= TD_SELECTED;
02332         td->dist= 0.0;
02333     }
02334     else {
02335         td->dist= MAXFLOAT;
02336     }
02337     unit_m3(td->mtx);
02338     unit_m3(td->smtx);
02339 }
02340 
02341 static void createTransUVs(bContext *C, TransInfo *t)
02342 {
02343     SpaceImage *sima = CTX_wm_space_image(C);
02344     Image *ima = CTX_data_edit_image(C);
02345     Scene *scene = t->scene;
02346     TransData *td = NULL;
02347     TransData2D *td2d = NULL;
02348     MTFace *tf;
02349     int count=0, countsel=0;
02350     int propmode = t->flag & T_PROP_EDIT;
02351 
02352     EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh;
02353     EditFace *efa;
02354 
02355     if(!ED_space_image_show_uvedit(sima, t->obedit)) return;
02356 
02357     /* count */
02358     for (efa= em->faces.first; efa; efa= efa->next) {
02359         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02360 
02361         if(uvedit_face_visible(scene, ima, efa, tf)) {
02362             efa->tmp.p = tf;
02363 
02364             if (uvedit_uv_selected(scene, efa, tf, 0)) countsel++;
02365             if (uvedit_uv_selected(scene, efa, tf, 1)) countsel++;
02366             if (uvedit_uv_selected(scene, efa, tf, 2)) countsel++;
02367             if (efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) countsel++;
02368             if(propmode)
02369                 count += (efa->v4)? 4: 3;
02370         } else {
02371             efa->tmp.p = NULL;
02372         }
02373     }
02374 
02375      /* note: in prop mode we need at least 1 selected */
02376     if (countsel==0) return;
02377 
02378     t->total= (propmode)? count: countsel;
02379     t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(UV Editing)");
02380     /* for each 2d uv coord a 3d vector is allocated, so that they can be
02381        treated just as if they were 3d verts */
02382     t->data2d= MEM_callocN(t->total*sizeof(TransData2D), "TransObData2D(UV Editing)");
02383 
02384     if(sima->flag & SI_CLIP_UV)
02385         t->flag |= T_CLIP_UV;
02386 
02387     td= t->data;
02388     td2d= t->data2d;
02389 
02390     for (efa= em->faces.first; efa; efa= efa->next) {
02391         if ((tf=(MTFace *)efa->tmp.p)) {
02392             if (propmode) {
02393                 UVsToTransData(sima, td++, td2d++, tf->uv[0], uvedit_uv_selected(scene, efa, tf, 0));
02394                 UVsToTransData(sima, td++, td2d++, tf->uv[1], uvedit_uv_selected(scene, efa, tf, 1));
02395                 UVsToTransData(sima, td++, td2d++, tf->uv[2], uvedit_uv_selected(scene, efa, tf, 2));
02396                 if(efa->v4)
02397                     UVsToTransData(sima, td++, td2d++, tf->uv[3], uvedit_uv_selected(scene, efa, tf, 3));
02398             } else {
02399                 if(uvedit_uv_selected(scene, efa, tf, 0))               UVsToTransData(sima, td++, td2d++, tf->uv[0], 1);
02400                 if(uvedit_uv_selected(scene, efa, tf, 1))               UVsToTransData(sima, td++, td2d++, tf->uv[1], 1);
02401                 if(uvedit_uv_selected(scene, efa, tf, 2))               UVsToTransData(sima, td++, td2d++, tf->uv[2], 1);
02402                 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))    UVsToTransData(sima, td++, td2d++, tf->uv[3], 1);
02403             }
02404         }
02405     }
02406 
02407     if (sima->flag & SI_LIVE_UNWRAP)
02408         ED_uvedit_live_unwrap_begin(t->scene, t->obedit);
02409 }
02410 
02411 void flushTransUVs(TransInfo *t)
02412 {
02413     SpaceImage *sima = t->sa->spacedata.first;
02414     TransData2D *td;
02415     int a, width, height;
02416     float aspx, aspy, invx, invy;
02417 
02418     ED_space_image_uv_aspect(sima, &aspx, &aspy);
02419     ED_space_image_size(sima, &width, &height);
02420     invx= 1.0f/aspx;
02421     invy= 1.0f/aspy;
02422 
02423     /* flush to 2d vector from internally used 3d vector */
02424     for(a=0, td= t->data2d; a<t->total; a++, td++) {
02425         td->loc2d[0]= td->loc[0]*invx;
02426         td->loc2d[1]= td->loc[1]*invy;
02427 
02428         if((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)) {
02429             td->loc2d[0]= (float)floor(width*td->loc2d[0] + 0.5f)/width;
02430             td->loc2d[1]= (float)floor(height*td->loc2d[1] + 0.5f)/height;
02431         }
02432     }
02433 }
02434 
02435 int clipUVTransform(TransInfo *t, float *vec, int resize)
02436 {
02437     TransData *td;
02438     int a, clipx=1, clipy=1;
02439     float aspx, aspy, min[2], max[2];
02440 
02441     ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
02442     min[0]= min[1]= 0.0f;
02443     max[0]= aspx; max[1]= aspy;
02444 
02445     for(a=0, td= t->data; a<t->total; a++, td++) {
02446         DO_MINMAX2(td->loc, min, max);
02447     }
02448 
02449     if(resize) {
02450         if(min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < aspx*0.5f)
02451             vec[0] *= t->center[0]/(t->center[0] - min[0]);
02452         else if(max[0] > aspx && t->center[0] < aspx)
02453             vec[0] *= (t->center[0] - aspx)/(t->center[0] - max[0]);
02454         else
02455             clipx= 0;
02456 
02457         if(min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < aspy*0.5f)
02458             vec[1] *= t->center[1]/(t->center[1] - min[1]);
02459         else if(max[1] > aspy && t->center[1] < aspy)
02460             vec[1] *= (t->center[1] - aspy)/(t->center[1] - max[1]);
02461         else
02462             clipy= 0;
02463     }
02464     else {
02465         if(min[0] < 0.0f)
02466             vec[0] -= min[0];
02467         else if(max[0] > aspx)
02468             vec[0] -= max[0]-aspx;
02469         else
02470             clipx= 0;
02471 
02472         if(min[1] < 0.0f)
02473             vec[1] -= min[1];
02474         else if(max[1] > aspy)
02475             vec[1] -= max[1]-aspy;
02476         else
02477             clipy= 0;
02478     }
02479 
02480     return (clipx || clipy);
02481 }
02482 
02483 /* ********************* ANIMATION EDITORS (GENERAL) ************************* */
02484 
02485 /* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
02486 static short FrameOnMouseSide(char side, float frame, float cframe)
02487 {
02488     /* both sides, so it doesn't matter */
02489     if (side == 'B') return 1;
02490 
02491     /* only on the named side */
02492     if (side == 'R')
02493         return (frame >= cframe) ? 1 : 0;
02494     else
02495         return (frame <= cframe) ? 1 : 0;
02496 }
02497 
02498 /* ********************* NLA EDITOR ************************* */
02499 
02500 static void createTransNlaData(bContext *C, TransInfo *t)
02501 {
02502     Scene *scene= t->scene;
02503     SpaceNla *snla = NULL;
02504     TransData *td = NULL;
02505     TransDataNla *tdn = NULL;
02506     
02507     bAnimContext ac;
02508     ListBase anim_data = {NULL, NULL};
02509     bAnimListElem *ale;
02510     int filter;
02511     
02512     int count=0;
02513     
02514     /* determine what type of data we are operating on */
02515     if (ANIM_animdata_get_context(C, &ac) == 0)
02516         return;
02517     snla = (SpaceNla *)ac.sl;
02518     
02519     /* filter data */
02520     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
02521     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
02522     
02523     /* which side of the current frame should be allowed */
02524     if (t->mode == TFM_TIME_EXTEND) {
02525         /* only side on which mouse is gets transformed */
02526         float xmouse, ymouse;
02527         
02528         UI_view2d_region_to_view(&ac.ar->v2d, t->imval[0], t->imval[1], &xmouse, &ymouse);
02529         t->frame_side= (xmouse > CFRA) ? 'R' : 'L';
02530     }
02531     else {
02532         /* normal transform - both sides of current frame are considered */
02533         t->frame_side = 'B';
02534     }
02535     
02536     /* loop 1: count how many strips are selected (consider each strip as 2 points) */
02537     for (ale= anim_data.first; ale; ale= ale->next) {
02538         NlaTrack *nlt= (NlaTrack *)ale->data;
02539         NlaStrip *strip;
02540         
02541         /* make some meta-strips for chains of selected strips */
02542         BKE_nlastrips_make_metas(&nlt->strips, 1);
02543         
02544         /* only consider selected strips */
02545         for (strip= nlt->strips.first; strip; strip= strip->next) {
02546             // TODO: we can make strips have handles later on...
02547             /* transition strips can't get directly transformed */
02548             if (strip->type != NLASTRIP_TYPE_TRANSITION) {
02549                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
02550                     if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) count++;
02551                     if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) count++;
02552                 }
02553             }
02554         }
02555     }
02556     
02557     /* stop if trying to build list if nothing selected */
02558     if (count == 0) {
02559         /* cleanup temp list */
02560         BLI_freelistN(&anim_data);
02561         return;
02562     }
02563     
02564     /* allocate memory for data */
02565     t->total= count;
02566     
02567     t->data= MEM_callocN(t->total*sizeof(TransData), "TransData(NLA Editor)");
02568     td= t->data;
02569     t->customData= MEM_callocN(t->total*sizeof(TransDataNla), "TransDataNla (NLA Editor)");
02570     tdn= t->customData;
02571     
02572     /* loop 2: build transdata array */
02573     for (ale= anim_data.first; ale; ale= ale->next) {
02574         /* only if a real NLA-track */
02575         if (ale->type == ANIMTYPE_NLATRACK) {
02576             AnimData *adt = ale->adt;
02577             NlaTrack *nlt= (NlaTrack *)ale->data;
02578             NlaStrip *strip;
02579             
02580             /* only consider selected strips */
02581             for (strip= nlt->strips.first; strip; strip= strip->next) {
02582                 // TODO: we can make strips have handles later on...
02583                 /* transition strips can't get directly transformed */
02584                 if (strip->type != NLASTRIP_TYPE_TRANSITION) {
02585                     if (strip->flag & NLASTRIP_FLAG_SELECT) {
02586                         /* our transform data is constructed as follows:
02587                          *  - only the handles on the right side of the current-frame get included
02588                          *  - td structs are transform-elements operated on by the transform system
02589                          *    and represent a single handle. The storage/pointer used (val or loc) depends on
02590                          *    whether we're scaling or transforming. Ultimately though, the handles
02591                          *    the td writes to will simply be a dummy in tdn
02592                          *  - for each strip being transformed, a single tdn struct is used, so in some
02593                          *    cases, there will need to be 1 of these tdn elements in the array skipped...
02594                          */
02595                         float center[3], yval;
02596                         
02597                         /* firstly, init tdn settings */
02598                         tdn->id= ale->id;
02599                         tdn->oldTrack= tdn->nlt= nlt;
02600                         tdn->strip= strip;
02601                         tdn->trackIndex= BLI_findindex(&adt->nla_tracks, nlt);
02602                         
02603                         yval= (float)(tdn->trackIndex * NLACHANNEL_STEP(snla));
02604                         
02605                         tdn->h1[0]= strip->start;
02606                         tdn->h1[1]= yval;
02607                         tdn->h2[0]= strip->end;
02608                         tdn->h2[1]= yval;
02609                         
02610                         center[0]= (float)CFRA;
02611                         center[1]= yval;
02612                         center[2]= 0.0f;
02613                         
02614                         /* set td's based on which handles are applicable */
02615                         if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA))
02616                         {
02617                             /* just set tdn to assume that it only has one handle for now */
02618                             tdn->handle= -1;
02619                             
02620                             /* now, link the transform data up to this data */
02621                             if (ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_EXTEND)) {
02622                                 td->loc= tdn->h1;
02623                                 copy_v3_v3(td->iloc, tdn->h1);
02624                                 
02625                                 /* store all the other gunk that is required by transform */
02626                                 copy_v3_v3(td->center, center);
02627                                 memset(td->axismtx, 0, sizeof(td->axismtx));
02628                                 td->axismtx[2][2] = 1.0f;
02629                                 
02630                                 td->ext= NULL; td->val= NULL;
02631                                 
02632                                 td->flag |= TD_SELECTED;
02633                                 td->dist= 0.0f;
02634                                 
02635                                 unit_m3(td->mtx);
02636                                 unit_m3(td->smtx);
02637                             }
02638                             else {
02639                                 /* time scaling only needs single value */
02640                                 td->val= &tdn->h1[0];
02641                                 td->ival= tdn->h1[0];
02642                             }
02643                             
02644                             td->extra= tdn;
02645                             td++;
02646                         }
02647                         if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA))
02648                         {
02649                             /* if tdn is already holding the start handle, then we're doing both, otherwise, only end */
02650                             tdn->handle= (tdn->handle) ? 2 : 1;
02651                             
02652                             /* now, link the transform data up to this data */
02653                             if (ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_EXTEND)) {
02654                                 td->loc= tdn->h2;
02655                                 copy_v3_v3(td->iloc, tdn->h2);
02656                                 
02657                                 /* store all the other gunk that is required by transform */
02658                                 copy_v3_v3(td->center, center);
02659                                 memset(td->axismtx, 0, sizeof(td->axismtx));
02660                                 td->axismtx[2][2] = 1.0f;
02661                                 
02662                                 td->ext= NULL; td->val= NULL;
02663                                 
02664                                 td->flag |= TD_SELECTED;
02665                                 td->dist= 0.0f;
02666                                 
02667                                 unit_m3(td->mtx);
02668                                 unit_m3(td->smtx);
02669                             }
02670                             else {
02671                                 /* time scaling only needs single value */
02672                                 td->val= &tdn->h2[0];
02673                                 td->ival= tdn->h2[0];
02674                             }
02675                             
02676                             td->extra= tdn;
02677                             td++;
02678                         }
02679                         
02680                         /* if both handles were used, skip the next tdn (i.e. leave it blank) since the counting code is dumb...
02681                          * otherwise, just advance to the next one...
02682                          */
02683                         if (tdn->handle == 2)
02684                             tdn += 2;
02685                         else
02686                             tdn++;
02687                     }
02688                 }
02689             }
02690         }
02691     }
02692     
02693     /* cleanup temp list */
02694     BLI_freelistN(&anim_data);
02695 }
02696 
02697 /* ********************* ACTION EDITOR ****************** */
02698 
02699 /* Called by special_aftertrans_update to make sure selected gp-frames replace
02700  * any other gp-frames which may reside on that frame (that are not selected).
02701  * It also makes sure gp-frames are still stored in chronological order after
02702  * transform.
02703  */
02704 static void posttrans_gpd_clean (bGPdata *gpd)
02705 {
02706     bGPDlayer *gpl;
02707     
02708     for (gpl= gpd->layers.first; gpl; gpl= gpl->next) {
02709         ListBase sel_buffer = {NULL, NULL};
02710         bGPDframe *gpf, *gpfn;
02711         bGPDframe *gfs, *gfsn;
02712         
02713         /* loop 1: loop through and isolate selected gp-frames to buffer
02714          * (these need to be sorted as they are isolated)
02715          */
02716         for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
02717             short added= 0;
02718             gpfn= gpf->next;
02719             
02720             if (gpf->flag & GP_FRAME_SELECT) {
02721                 BLI_remlink(&gpl->frames, gpf);
02722                 
02723                 /* find place to add them in buffer
02724                  * - go backwards as most frames will still be in order,
02725                  *   so doing it this way will be faster
02726                  */
02727                 for (gfs= sel_buffer.last; gfs; gfs= gfs->prev) {
02728                     /* if current (gpf) occurs after this one in buffer, add! */
02729                     if (gfs->framenum < gpf->framenum) {
02730                         BLI_insertlinkafter(&sel_buffer, gfs, gpf);
02731                         added= 1;
02732                         break;
02733                     }
02734                 }
02735                 if (added == 0)
02736                     BLI_addhead(&sel_buffer, gpf);
02737             }
02738         }
02739         
02740         /* error checking: it is unlikely, but may be possible to have none selected */
02741         if (sel_buffer.first == NULL)
02742             continue;
02743         
02744         /* if all were selected (i.e. gpl->frames is empty), then just transfer sel-buf over */
02745         if (gpl->frames.first == NULL) {
02746             gpl->frames.first= sel_buffer.first;
02747             gpl->frames.last= sel_buffer.last;
02748             
02749             continue;
02750         }
02751         
02752         /* loop 2: remove duplicates of frames in buffers */
02753         for (gpf= gpl->frames.first; gpf && sel_buffer.first; gpf= gpfn) {
02754             gpfn= gpf->next;
02755             
02756             /* loop through sel_buffer, emptying stuff from front of buffer if ok */
02757             for (gfs= sel_buffer.first; gfs && gpf; gfs= gfsn) {
02758                 gfsn= gfs->next;
02759                 
02760                 /* if this buffer frame needs to go before current, add it! */
02761                 if (gfs->framenum < gpf->framenum) {
02762                     /* transfer buffer frame to frames list (before current) */
02763                     BLI_remlink(&sel_buffer, gfs);
02764                     BLI_insertlinkbefore(&gpl->frames, gpf, gfs);
02765                 }
02766                 /* if this buffer frame is on same frame, replace current with it and stop */
02767                 else if (gfs->framenum == gpf->framenum) {
02768                     /* transfer buffer frame to frames list (before current) */
02769                     BLI_remlink(&sel_buffer, gfs);
02770                     BLI_insertlinkbefore(&gpl->frames, gpf, gfs);
02771                     
02772                     /* get rid of current frame */
02773                     gpencil_layer_delframe(gpl, gpf);
02774                 }
02775             }
02776         }
02777         
02778         /* if anything is still in buffer, append to end */
02779         for (gfs= sel_buffer.first; gfs; gfs= gfsn) {
02780             gfsn= gfs->next;
02781             
02782             BLI_remlink(&sel_buffer, gfs);
02783             BLI_addtail(&gpl->frames, gfs);
02784         }
02785     }
02786 }
02787 
02788 /* Called during special_aftertrans_update to make sure selected keyframes replace
02789  * any other keyframes which may reside on that frame (that is not selected).
02790  */
02791 static void posttrans_fcurve_clean (FCurve *fcu, const short use_handle)
02792 {
02793     float *selcache;    /* cache for frame numbers of selected frames (fcu->totvert*sizeof(float)) */
02794     int len, index, i;  /* number of frames in cache, item index */
02795 
02796     /* allocate memory for the cache */
02797     // TODO: investigate using BezTriple columns instead?
02798     if (fcu->totvert == 0 || fcu->bezt==NULL)
02799         return;
02800     selcache= MEM_callocN(sizeof(float)*fcu->totvert, "FCurveSelFrameNums");
02801     len= 0;
02802     index= 0;
02803 
02804     /* We do 2 loops, 1 for marking keyframes for deletion, one for deleting
02805      * as there is no guarantee what order the keyframes are exactly, even though
02806      * they have been sorted by time.
02807      */
02808 
02809     /*  Loop 1: find selected keyframes   */
02810     for (i = 0; i < fcu->totvert; i++) {
02811         BezTriple *bezt= &fcu->bezt[i];
02812         
02813         if (BEZSELECTED(bezt)) {
02814             selcache[index]= bezt->vec[1][0];
02815             index++;
02816             len++;
02817         }
02818     }
02819 
02820     /* Loop 2: delete unselected keyframes on the same frames 
02821      * (if any keyframes were found, or the whole curve wasn't affected) 
02822      */
02823     if ((len) && (len != fcu->totvert)) {
02824         for (i= fcu->totvert-1; i >= 0; i--) {
02825             BezTriple *bezt= &fcu->bezt[i];
02826             
02827             if (BEZSELECTED(bezt) == 0) {
02828                 /* check beztriple should be removed according to cache */
02829                 for (index= 0; index < len; index++) {
02830                     if (IS_EQF(bezt->vec[1][0], selcache[index])) {
02831                         delete_fcurve_key(fcu, i, 0);
02832                         break;
02833                     }
02834                     else if (bezt->vec[1][0] < selcache[index])
02835                         break;
02836                 }
02837             }
02838         }
02839         
02840         testhandles_fcurve(fcu, use_handle);
02841     }
02842 
02843     /* free cache */
02844     MEM_freeN(selcache);
02845 }
02846 
02847 
02848 
02849 /* Called by special_aftertrans_update to make sure selected keyframes replace
02850  * any other keyframes which may reside on that frame (that is not selected).
02851  * remake_action_ipos should have already been called
02852  */
02853 static void posttrans_action_clean (bAnimContext *ac, bAction *act)
02854 {
02855     ListBase anim_data = {NULL, NULL};
02856     bAnimListElem *ale;
02857     int filter;
02858 
02859     /* filter data */
02860     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
02861     ANIM_animdata_filter(ac, &anim_data, filter, act, ANIMCONT_ACTION);
02862 
02863     /* loop through relevant data, removing keyframes as appropriate
02864      *      - all keyframes are converted in/out of global time
02865      */
02866     for (ale= anim_data.first; ale; ale= ale->next) {
02867         AnimData *adt= ANIM_nla_mapping_get(ac, ale);
02868         
02869         if (adt) {
02870             ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
02871             posttrans_fcurve_clean(ale->key_data, FALSE); /* only use handles in graph editor */
02872             ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
02873         }
02874         else
02875             posttrans_fcurve_clean(ale->key_data, FALSE); /* only use handles in graph editor */
02876     }
02877 
02878     /* free temp data */
02879     BLI_freelistN(&anim_data);
02880 }
02881 
02882 /* ----------------------------- */
02883 
02884 /* fully select selected beztriples, but only include if it's on the right side of cfra */
02885 static int count_fcurve_keys(FCurve *fcu, char side, float cfra)
02886 {
02887     BezTriple *bezt;
02888     int i, count = 0;
02889 
02890     if (ELEM(NULL, fcu, fcu->bezt))
02891         return count;
02892 
02893     /* only include points that occur on the right side of cfra */
02894     for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
02895         if (bezt->f2 & SELECT) {
02896             /* no need to adjust the handle selection since they are assumed
02897              * selected (like graph editor with SIPO_NOHANDLES) */
02898             if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
02899                 count += 1;
02900             }
02901         }
02902     }
02903 
02904     return count;
02905 }
02906 
02907 /* fully select selected beztriples, but only include if it's on the right side of cfra */
02908 static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra)
02909 {
02910     bGPDframe *gpf;
02911     int count = 0;
02912     
02913     if (gpl == NULL)
02914         return count;
02915     
02916     /* only include points that occur on the right side of cfra */
02917     for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
02918         if (gpf->flag & GP_FRAME_SELECT) {
02919             if (FrameOnMouseSide(side, (float)gpf->framenum, cfra))
02920                 count++;
02921         }
02922     }
02923     
02924     return count;
02925 }
02926 
02927 /* This function assigns the information to transdata */
02928 static void TimeToTransData(TransData *td, float *time, AnimData *adt)
02929 {
02930     /* memory is calloc'ed, so that should zero everything nicely for us */
02931     td->val = time;
02932     td->ival = *(time);
02933 
02934     /* store the AnimData where this keyframe exists as a keyframe of the
02935      * active action as td->extra.
02936      */
02937     td->extra= adt;
02938 }
02939 
02940 /* This function advances the address to which td points to, so it must return
02941  * the new address so that the next time new transform data is added, it doesn't
02942  * overwrite the existing ones...  i.e.   td = IcuToTransData(td, icu, ob, side, cfra);
02943  *
02944  * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
02945  * on the named side are used.
02946  */
02947 static TransData *ActionFCurveToTransData(TransData *td, TransData2D **td2dv, FCurve *fcu, AnimData *adt, char side, float cfra)
02948 {
02949     BezTriple *bezt;
02950     TransData2D *td2d = *td2dv;
02951     int i;
02952 
02953     if (ELEM(NULL, fcu, fcu->bezt))
02954         return td;
02955 
02956     for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
02957         /* only add selected keyframes (for now, proportional edit is not enabled) */
02958         if (bezt->f2 & SELECT) { /* note this MUST match count_fcurve_keys(), so can't use BEZSELECTED() macro */
02959             /* only add if on the right 'side' of the current frame */
02960             if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
02961                 TimeToTransData(td, bezt->vec[1], adt);
02962                 
02963                 /*set flags to move handles as necassary*/
02964                 td->flag |= TD_MOVEHANDLE1|TD_MOVEHANDLE2;
02965                 td2d->h1 = bezt->vec[0];
02966                 td2d->h2 = bezt->vec[2];
02967                 
02968                 copy_v2_v2(td2d->ih1, td2d->h1);
02969                 copy_v2_v2(td2d->ih2, td2d->h2);
02970                 
02971                 td++;
02972                 td2d++;
02973             }
02974         }
02975     }
02976     
02977     *td2dv = td2d;
02978     
02979     return td;
02980 }
02981 
02982 /* helper struct for gp-frame transforms (only used here) */
02983 typedef struct tGPFtransdata {
02984     float val;          /* where transdata writes transform */
02985     int *sdata;         /* pointer to gpf->framenum */
02986 } tGPFtransdata;
02987 
02988 /* This function helps flush transdata written to tempdata into the gp-frames  */
02989 void flushTransGPactionData (TransInfo *t)
02990 {
02991     tGPFtransdata *tfd;
02992     int i;
02993 
02994     /* find the first one to start from */
02995     if (t->mode == TFM_TIME_SLIDE)
02996         tfd= (tGPFtransdata *)( (float *)(t->customData) + 2 );
02997     else
02998         tfd= (tGPFtransdata *)(t->customData);
02999 
03000     /* flush data! */
03001     for (i = 0; i < t->total; i++, tfd++) {
03002         *(tfd->sdata)= (int)floor(tfd->val + 0.5f);
03003     }
03004 }
03005 
03006 /* This function advances the address to which td points to, so it must return
03007  * the new address so that the next time new transform data is added, it doesn't
03008  * overwrite the existing ones...  i.e.   td = GPLayerToTransData(td, ipo, ob, side, cfra);
03009  *
03010  * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
03011  * on the named side are used.
03012  */
03013 static int GPLayerToTransData (TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra)
03014 {
03015     bGPDframe *gpf;
03016     int count= 0;
03017     
03018     /* check for select frames on right side of current frame */
03019     for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
03020         if (gpf->flag & GP_FRAME_SELECT) {
03021             if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) {
03022                 /* memory is calloc'ed, so that should zero everything nicely for us */
03023                 td->val= &tfd->val;
03024                 td->ival= (float)gpf->framenum;
03025                 
03026                 tfd->val= (float)gpf->framenum;
03027                 tfd->sdata= &gpf->framenum;
03028                 
03029                 /* advance td now */
03030                 td++;
03031                 tfd++;
03032                 count++;
03033             }
03034         }
03035     }
03036     
03037     return count;
03038 }
03039 
03040 static void createTransActionData(bContext *C, TransInfo *t)
03041 {
03042     Scene *scene= t->scene;
03043     TransData *td = NULL;
03044     TransData2D *td2d = NULL;
03045     tGPFtransdata *tfd = NULL;
03046     
03047     bAnimContext ac;
03048     ListBase anim_data = {NULL, NULL};
03049     bAnimListElem *ale;
03050     int filter;
03051     
03052     int count=0;
03053     float cfra;
03054     
03055     /* determine what type of data we are operating on */
03056     if (ANIM_animdata_get_context(C, &ac) == 0)
03057         return;
03058     
03059     /* filter data */
03060     if (ac.datatype == ANIMCONT_GPENCIL)
03061         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
03062     else
03063         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
03064     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
03065     
03066     /* which side of the current frame should be allowed */
03067     if (t->mode == TFM_TIME_EXTEND) {
03068         /* only side on which mouse is gets transformed */
03069         float xmouse, ymouse;
03070         
03071         UI_view2d_region_to_view(&ac.ar->v2d, t->imval[0], t->imval[1], &xmouse, &ymouse);
03072         t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
03073     }
03074     else {
03075         /* normal transform - both sides of current frame are considered */
03076         t->frame_side = 'B';
03077     }
03078     
03079     /* loop 1: fully select ipo-keys and count how many BezTriples are selected */
03080     for (ale= anim_data.first; ale; ale= ale->next) {
03081         AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
03082         
03083         /* convert current-frame to action-time (slightly less accurate, espcially under
03084          * higher scaling ratios, but is faster than converting all points)
03085          */
03086         if (adt)
03087             cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
03088         else
03089             cfra = (float)CFRA;
03090         
03091         if (ale->type == ANIMTYPE_FCURVE)
03092             count += count_fcurve_keys(ale->key_data, t->frame_side, cfra);
03093         else
03094             count += count_gplayer_frames(ale->data, t->frame_side, cfra);
03095     }
03096     
03097     /* stop if trying to build list if nothing selected */
03098     if (count == 0) {
03099         /* cleanup temp list */
03100         BLI_freelistN(&anim_data);
03101         return;
03102     }
03103     
03104     /* allocate memory for data */
03105     t->total= count;
03106     
03107     t->data= MEM_callocN(t->total*sizeof(TransData), "TransData(Action Editor)");
03108     t->data2d= MEM_callocN(t->total*sizeof(TransData2D), "transdata2d");
03109     td= t->data;
03110     td2d = t->data2d;
03111     
03112     if (ac.datatype == ANIMCONT_GPENCIL) {
03113         if (t->mode == TFM_TIME_SLIDE) {
03114             t->customData= MEM_callocN((sizeof(float)*2)+(sizeof(tGPFtransdata)*count), "TimeSlide + tGPFtransdata");
03115             tfd= (tGPFtransdata *)( (float *)(t->customData) + 2 );
03116         }
03117         else {
03118             t->customData= MEM_callocN(sizeof(tGPFtransdata)*count, "tGPFtransdata");
03119             tfd= (tGPFtransdata *)(t->customData);
03120         }
03121     }
03122     else if (t->mode == TFM_TIME_SLIDE)
03123         t->customData= MEM_callocN(sizeof(float)*2, "TimeSlide Min/Max");
03124     
03125     /* loop 2: build transdata array */
03126     for (ale= anim_data.first; ale; ale= ale->next) {
03127         if (ale->type == ANIMTYPE_GPLAYER) {
03128             bGPDlayer *gpl= (bGPDlayer *)ale->data;
03129             int i;
03130             
03131             i = GPLayerToTransData(td, tfd, gpl, t->frame_side, cfra);
03132             td += i;
03133             tfd += i;
03134         }
03135         else {
03136             AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
03137             FCurve *fcu= (FCurve *)ale->key_data;
03138             
03139             /* convert current-frame to action-time (slightly less accurate, espcially under
03140              * higher scaling ratios, but is faster than converting all points)
03141              */
03142             if (adt)
03143                 cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
03144             else
03145                 cfra = (float)CFRA;
03146             
03147             td= ActionFCurveToTransData(td, &td2d, fcu, adt, t->frame_side, cfra);
03148         }
03149     }
03150     
03151     /* check if we're supposed to be setting minx/maxx for TimeSlide */
03152     if (t->mode == TFM_TIME_SLIDE) {
03153         float min=999999999.0f, max=-999999999.0f;
03154         int i;
03155         
03156         td= t->data;
03157         for (i=0; i < count; i++, td++) {
03158             if (min > *(td->val)) min= *(td->val);
03159             if (max < *(td->val)) max= *(td->val);
03160         }
03161         
03162         if (min == max) {
03163             /* just use the current frame ranges */
03164             min = (float)PSFRA;
03165             max = (float)PEFRA;
03166         }
03167         
03168         /* minx/maxx values used by TimeSlide are stored as a
03169          * calloced 2-float array in t->customData. This gets freed
03170          * in postTrans (T_FREE_CUSTOMDATA).
03171          */
03172         *((float *)(t->customData)) = min;
03173         *((float *)(t->customData) + 1) = max;
03174     }
03175 
03176     /* cleanup temp list */
03177     BLI_freelistN(&anim_data);
03178 }
03179 
03180 /* ********************* GRAPH EDITOR ************************* */
03181 
03182 /* Helper function for createTransGraphEditData, which is reponsible for associating
03183  * source data with transform data
03184  */
03185 static void bezt_to_transdata (TransData *td, TransData2D *td2d, AnimData *adt, BezTriple *bezt, 
03186                 int bi, short selected, short ishandle, short intvals, 
03187                 float mtx[3][3], float smtx[3][3])
03188 {
03189     float *loc = bezt->vec[bi];
03190     float *cent = bezt->vec[1];
03191 
03192     /* New location from td gets dumped onto the old-location of td2d, which then
03193      * gets copied to the actual data at td2d->loc2d (bezt->vec[n])
03194      *
03195      * Due to NLA mapping, we apply NLA mapping to some of the verts here,
03196      * and then that mapping will be undone after transform is done.
03197      */
03198     
03199     if (adt) {
03200         td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_MAP);
03201         td2d->loc[1] = loc[1];
03202         td2d->loc[2] = 0.0f;
03203         td2d->loc2d = loc;
03204         
03205         td->loc = td2d->loc;
03206         td->center[0] = BKE_nla_tweakedit_remap(adt, cent[0], NLATIME_CONVERT_MAP);
03207         td->center[1] = cent[1];
03208         td->center[2] = 0.0f;
03209         
03210         copy_v3_v3(td->iloc, td->loc);
03211     }
03212     else {
03213         td2d->loc[0] = loc[0];
03214         td2d->loc[1] = loc[1];
03215         td2d->loc[2] = 0.0f;
03216         td2d->loc2d = loc;
03217         
03218         td->loc = td2d->loc;
03219         copy_v3_v3(td->center, cent);
03220         copy_v3_v3(td->iloc, td->loc);
03221     }
03222 
03223     if (td->flag & TD_MOVEHANDLE1) {
03224         td2d->h1 = bezt->vec[0];
03225         copy_v2_v2(td2d->ih1, td2d->h1);
03226     } 
03227     else    
03228         td2d->h1 = NULL;
03229 
03230     if (td->flag & TD_MOVEHANDLE2) {
03231         td2d->h2 = bezt->vec[2];
03232         copy_v2_v2(td2d->ih2, td2d->h2);
03233     } 
03234     else 
03235         td2d->h2 = NULL;
03236 
03237     memset(td->axismtx, 0, sizeof(td->axismtx));
03238     td->axismtx[2][2] = 1.0f;
03239     
03240     td->ext= NULL; td->val= NULL;
03241     
03242     /* store AnimData info in td->extra, for applying mapping when flushing */
03243     td->extra= adt;
03244     
03245     if (selected) {
03246         td->flag |= TD_SELECTED;
03247         td->dist= 0.0f;
03248     }
03249     else
03250         td->dist= MAXFLOAT;
03251     
03252     if (ishandle)
03253         td->flag |= TD_NOTIMESNAP;
03254     if (intvals)
03255         td->flag |= TD_INTVALUES;
03256 
03257     /* copy space-conversion matrices for dealing with non-uniform scales */
03258     copy_m3_m3(td->mtx, mtx);
03259     copy_m3_m3(td->smtx, smtx);
03260 }
03261 
03262 static void createTransGraphEditData(bContext *C, TransInfo *t)
03263 {
03264     SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
03265     Scene *scene= t->scene;
03266     ARegion *ar= t->ar;
03267     View2D *v2d= &ar->v2d;
03268     
03269     TransData *td = NULL;
03270     TransData2D *td2d = NULL;
03271     
03272     bAnimContext ac;
03273     ListBase anim_data = {NULL, NULL};
03274     bAnimListElem *ale;
03275     int filter;
03276     
03277     BezTriple *bezt;
03278     int count=0, i;
03279     float cfra;
03280     float mtx[3][3], smtx[3][3];
03281     const short use_handle = !(sipo->flag & SIPO_NOHANDLES);
03282     
03283     /* determine what type of data we are operating on */
03284     if (ANIM_animdata_get_context(C, &ac) == 0)
03285         return;
03286     
03287     /* filter data */
03288     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
03289     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
03290     
03291     /* which side of the current frame should be allowed */
03292         // XXX we still want this mode, but how to get this using standard transform too?
03293     if (t->mode == TFM_TIME_EXTEND) {
03294         /* only side on which mouse is gets transformed */
03295         float xmouse, ymouse;
03296         
03297         UI_view2d_region_to_view(v2d, t->imval[0], t->imval[1], &xmouse, &ymouse);
03298         t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
03299     }
03300     else {
03301         /* normal transform - both sides of current frame are considered */
03302         t->frame_side = 'B';
03303     }
03304     
03305     /* loop 1: count how many BezTriples (specifically their verts) are selected (or should be edited) */
03306     for (ale= anim_data.first; ale; ale= ale->next) {
03307         AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
03308         FCurve *fcu= (FCurve *)ale->key_data;
03309         
03310         /* convert current-frame to action-time (slightly less accurate, espcially under
03311          * higher scaling ratios, but is faster than converting all points)
03312          */
03313         if (adt)
03314             cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
03315         else
03316             cfra = (float)CFRA;
03317         
03318         /* F-Curve may not have any keyframes */
03319         if (fcu->bezt == NULL)
03320             continue;
03321         
03322         /* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse */
03323         for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) {
03324             if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
03325                 const char sel2= bezt->f2 & SELECT;
03326                 const char sel1= use_handle ? bezt->f1 & SELECT : sel2;
03327                 const char sel3= use_handle ? bezt->f3 & SELECT : sel2;
03328 
03329                 if (ELEM3(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE)) {
03330                     /* for 'normal' pivots - just include anything that is selected.
03331                        this works a bit differently in translation modes */
03332                     if (sel2) count++;
03333                     else {
03334                         if (sel1) count++;
03335                         if (sel3) count++;
03336                     }
03337                 } 
03338                 else if (sipo->around == V3D_LOCAL) {
03339                     /* for local-pivot we only need to count the number of selected handles only, so that centerpoints don't
03340                      * don't get moved wrong
03341                      */
03342                     if (bezt->ipo == BEZT_IPO_BEZ) {
03343                         if (sel1) count++;
03344                         if (sel3) count++;
03345                     }
03346                     /* else if (sel2) count++; // TODO: could this cause problems? */
03347                     /* - yes this causes problems, because no td is created for the center point */
03348                 }
03349                 else {
03350                     /* for 'normal' pivots - just include anything that is selected */
03351                     if (sel1) count++;
03352                     if (sel2) count++;
03353                     if (sel3) count++;
03354                 }
03355             }
03356         }
03357     }
03358     
03359     /* stop if trying to build list if nothing selected */
03360     if (count == 0) {
03361         /* cleanup temp list */
03362         BLI_freelistN(&anim_data);
03363         return;
03364     }
03365     
03366     /* allocate memory for data */
03367     t->total= count;
03368     
03369     t->data= MEM_callocN(t->total*sizeof(TransData), "TransData (Graph Editor)");
03370         /* for each 2d vert a 3d vector is allocated, so that they can be treated just as if they were 3d verts */
03371     t->data2d= MEM_callocN(t->total*sizeof(TransData2D), "TransData2D (Graph Editor)");
03372     
03373     td= t->data;
03374     td2d= t->data2d;
03375     
03376     /* precompute space-conversion matrices for dealing with non-uniform scaling of Graph Editor */
03377     unit_m3(mtx);
03378     unit_m3(smtx);
03379     
03380     if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
03381         float xscale, yscale;
03382         
03383         /* apply scale factors to x and y axes of space-conversion matrices */
03384         UI_view2d_getscale(v2d, &xscale, &yscale);
03385         
03386         /* mtx is data to global (i.e. view) conversion */
03387         mul_v3_fl(mtx[0], xscale);
03388         mul_v3_fl(mtx[1], yscale);
03389         
03390         /* smtx is global (i.e. view) to data conversion */
03391         if (IS_EQF(xscale, 0.0f) == 0) mul_v3_fl(smtx[0], 1.0f/xscale);
03392         if (IS_EQF(yscale, 0.0f) == 0) mul_v3_fl(smtx[1], 1.0f/yscale);
03393     }
03394     
03395     /* loop 2: build transdata arrays */
03396     for (ale= anim_data.first; ale; ale= ale->next) {
03397         AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
03398         FCurve *fcu= (FCurve *)ale->key_data;
03399         short intvals= (fcu->flag & FCURVE_INT_VALUES);
03400         
03401         /* convert current-frame to action-time (slightly less accurate, espcially under
03402          * higher scaling ratios, but is faster than converting all points)
03403          */
03404         if (adt)
03405             cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
03406         else
03407             cfra = (float)CFRA;
03408             
03409         /* F-Curve may not have any keyframes */
03410         if (fcu->bezt == NULL)
03411             continue;
03412         
03413         ANIM_unit_mapping_apply_fcurve(ac.scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYSEL|ANIM_UNITCONV_SELVERTS);
03414         
03415         /* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */
03416         for (i=0, bezt= fcu->bezt; i < fcu->totvert; i++, bezt++) {
03417             if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
03418                 const char sel2= bezt->f2 & SELECT;
03419                 const char sel1= use_handle ? bezt->f1 & SELECT : sel2;
03420                 const char sel3= use_handle ? bezt->f3 & SELECT : sel2;
03421 
03422                 TransDataCurveHandleFlags *hdata = NULL;
03423                 /* short h1=1, h2=1; */ /* UNUSED */
03424                 
03425                 /* only include handles if selected, irrespective of the interpolation modes.
03426                  * also, only treat handles specially if the center point isn't selected. 
03427                  */
03428                 if (!ELEM3(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE) || !(sel2)) {
03429                     if (sel1) {
03430                         hdata = initTransDataCurveHandles(td, bezt);
03431                         bezt_to_transdata(td++, td2d++, adt, bezt, 0, 1, 1, intvals, mtx, smtx);
03432                     } 
03433                     else {
03434                         /* h1= 0; */ /* UNUSED */
03435                     }
03436                     
03437                     if (sel3) {
03438                         if (hdata==NULL)
03439                             hdata = initTransDataCurveHandles(td, bezt);
03440                         bezt_to_transdata(td++, td2d++, adt, bezt, 2, 1, 1, intvals, mtx, smtx);
03441                     } 
03442                     else {
03443                         /* h2= 0; */ /* UNUSED */
03444                     }
03445                 }
03446                 
03447                 /* only include main vert if selected */
03448                 if (sel2 && (sipo->around != V3D_LOCAL || ELEM3(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE))) {
03449 
03450                     /* move handles relative to center */
03451                     if (ELEM3(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE)) {
03452                         if (sel1) td->flag |= TD_MOVEHANDLE1;
03453                         if (sel3) td->flag |= TD_MOVEHANDLE2;
03454                     }
03455                     
03456                     /* if handles were not selected, store their selection status */
03457                     if (!(sel1) && !(sel3)) {
03458                         if (hdata == NULL)
03459                             hdata = initTransDataCurveHandles(td, bezt);
03460                     }
03461                 
03462                     bezt_to_transdata(td++, td2d++, adt, bezt, 1, 1, 0, intvals, mtx, smtx);
03463                     
03464                 }
03465                 /* special hack (must be done after initTransDataCurveHandles(), as that stores handle settings to restore...):
03466                  *  - Check if we've got entire BezTriple selected and we're scaling/rotating that point,
03467                  *    then check if we're using auto-handles.
03468                  *  - If so, change them auto-handles to aligned handles so that handles get affected too
03469                  */
03470                 if ( ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) &&
03471                      ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM) &&
03472                      ELEM(t->mode, TFM_ROTATION, TFM_RESIZE))
03473                 {
03474                     if (hdata && (sel1) && (sel3)) {
03475                         bezt->h1= HD_ALIGN;
03476                         bezt->h2= HD_ALIGN;
03477                     }
03478                 }
03479             }
03480         }
03481         
03482         /* Sets handles based on the selection */
03483         testhandles_fcurve(fcu, use_handle);
03484     }
03485     
03486     /* cleanup temp list */
03487     BLI_freelistN(&anim_data);
03488 }
03489 
03490 
03491 /* ------------------------ */
03492 
03493 /* struct for use in re-sorting BezTriples during Graph Editor transform */
03494 typedef struct BeztMap {
03495     BezTriple *bezt;
03496     unsigned int oldIndex;      /* index of bezt in fcu->bezt array before sorting */
03497     unsigned int newIndex;      /* index of bezt in fcu->bezt array after sorting */
03498     short swapHs;               /* swap order of handles (-1=clear; 0=not checked, 1=swap) */
03499     char pipo, cipo;            /* interpolation of current and next segments */
03500 } BeztMap;
03501 
03502 
03503 /* This function converts an FCurve's BezTriple array to a BeztMap array
03504  * NOTE: this allocates memory that will need to get freed later
03505  */
03506 static BeztMap *bezt_to_beztmaps (BezTriple *bezts, int totvert, const short UNUSED(use_handle))
03507 {
03508     BezTriple *bezt= bezts;
03509     BezTriple *prevbezt= NULL;
03510     BeztMap *bezm, *bezms;
03511     int i;
03512     
03513     /* allocate memory for this array */
03514     if (totvert==0 || bezts==NULL)
03515         return NULL;
03516     bezm= bezms= MEM_callocN(sizeof(BeztMap)*totvert, "BeztMaps");
03517     
03518     /* assign beztriples to beztmaps */
03519     for (i=0; i < totvert; i++, bezm++, prevbezt=bezt, bezt++) {
03520         bezm->bezt= bezt;
03521         
03522         bezm->oldIndex= i;
03523         bezm->newIndex= i;
03524         
03525         bezm->pipo= (prevbezt) ? prevbezt->ipo : bezt->ipo;
03526         bezm->cipo= bezt->ipo;
03527     }
03528 
03529     return bezms;
03530 }
03531 
03532 /* This function copies the code of sort_time_ipocurve, but acts on BeztMap structs instead */
03533 static void sort_time_beztmaps (BeztMap *bezms, int totvert, const short UNUSED(use_handle))
03534 {
03535     BeztMap *bezm;
03536     int i, ok= 1;
03537     
03538     /* keep repeating the process until nothing is out of place anymore */
03539     while (ok) {
03540         ok= 0;
03541         
03542         bezm= bezms;
03543         i= totvert;
03544         while (i--) {
03545             /* is current bezm out of order (i.e. occurs later than next)? */
03546             if (i > 0) {
03547                 if (bezm->bezt->vec[1][0] > (bezm+1)->bezt->vec[1][0]) {
03548                     bezm->newIndex++;
03549                     (bezm+1)->newIndex--;
03550                     
03551                     SWAP(BeztMap, *bezm, *(bezm+1));
03552                     
03553                     ok= 1;
03554                 }
03555             }
03556             
03557             /* do we need to check if the handles need to be swapped?
03558              * optimisation: this only needs to be performed in the first loop
03559              */
03560             if (bezm->swapHs == 0) {
03561                 if ( (bezm->bezt->vec[0][0] > bezm->bezt->vec[1][0]) &&
03562                      (bezm->bezt->vec[2][0] < bezm->bezt->vec[1][0]) )
03563                 {
03564                     /* handles need to be swapped */
03565                     bezm->swapHs = 1;
03566                 }
03567                 else {
03568                     /* handles need to be cleared */
03569                     bezm->swapHs = -1;
03570                 }
03571             }
03572             
03573             bezm++;
03574         }
03575     }
03576 }
03577 
03578 /* This function firstly adjusts the pointers that the transdata has to each BezTriple */
03579 static void beztmap_to_data (TransInfo *t, FCurve *fcu, BeztMap *bezms, int totvert, const short UNUSED(use_handle))
03580 {
03581     BezTriple *bezts = fcu->bezt;
03582     BeztMap *bezm;
03583     TransData2D *td2d;
03584     TransData *td;
03585     int i, j;
03586     char *adjusted;
03587     
03588     /* dynamically allocate an array of chars to mark whether an TransData's
03589      * pointers have been fixed already, so that we don't override ones that are
03590      * already done
03591       */
03592     adjusted= MEM_callocN(t->total, "beztmap_adjusted_map");
03593     
03594     /* for each beztmap item, find if it is used anywhere */
03595     bezm= bezms;
03596     for (i= 0; i < totvert; i++, bezm++) {
03597         /* loop through transdata, testing if we have a hit
03598          * for the handles (vec[0]/vec[2]), we must also check if they need to be swapped...
03599          */
03600         td2d= t->data2d;
03601         td= t->data;
03602         for (j= 0; j < t->total; j++, td2d++, td++) {
03603             /* skip item if already marked */
03604             if (adjusted[j] != 0) continue;
03605             
03606             /* update all transdata pointers, no need to check for selections etc,
03607              * since only points that are really needed were created as transdata
03608              */
03609             if (td2d->loc2d == bezm->bezt->vec[0]) {
03610                 if (bezm->swapHs == 1)
03611                     td2d->loc2d= (bezts + bezm->newIndex)->vec[2];
03612                 else
03613                     td2d->loc2d= (bezts + bezm->newIndex)->vec[0];
03614                 adjusted[j] = 1;
03615             }
03616             else if (td2d->loc2d == bezm->bezt->vec[2]) {
03617                 if (bezm->swapHs == 1)
03618                     td2d->loc2d= (bezts + bezm->newIndex)->vec[0];
03619                 else
03620                     td2d->loc2d= (bezts + bezm->newIndex)->vec[2];
03621                 adjusted[j] = 1;
03622             }
03623             else if (td2d->loc2d == bezm->bezt->vec[1]) {
03624                 td2d->loc2d= (bezts + bezm->newIndex)->vec[1];
03625                     
03626                 /* if only control point is selected, the handle pointers need to be updated as well */
03627                 if(td2d->h1)
03628                     td2d->h1= (bezts + bezm->newIndex)->vec[0];
03629                 if(td2d->h2)
03630                     td2d->h2= (bezts + bezm->newIndex)->vec[2];
03631                     
03632                 adjusted[j] = 1;
03633             }
03634 
03635             /* the handle type pointer has to be updated too */
03636             if (adjusted[j] && td->flag & TD_BEZTRIPLE && td->hdata) {
03637                 if(bezm->swapHs == 1) {
03638                     td->hdata->h1 = &(bezts + bezm->newIndex)->h2;
03639                     td->hdata->h2 = &(bezts + bezm->newIndex)->h1;
03640                 }
03641                 else {
03642                     td->hdata->h1 = &(bezts + bezm->newIndex)->h1;
03643                     td->hdata->h2 = &(bezts + bezm->newIndex)->h2;
03644                 }
03645             }
03646         }
03647         
03648     }
03649     
03650     /* free temp memory used for 'adjusted' array */
03651     MEM_freeN(adjusted);
03652 }
03653 
03654 /* This function is called by recalcData during the Transform loop to recalculate
03655  * the handles of curves and sort the keyframes so that the curves draw correctly.
03656  * It is only called if some keyframes have moved out of order.
03657  *
03658  * anim_data is the list of channels (F-Curves) retrieved already containing the
03659  * channels to work on. It should not be freed here as it may still need to be used.
03660  */
03661 void remake_graph_transdata (TransInfo *t, ListBase *anim_data)
03662 {
03663     SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
03664     bAnimListElem *ale;
03665     const short use_handle = !(sipo->flag & SIPO_NOHANDLES);
03666     
03667     /* sort and reassign verts */
03668     for (ale= anim_data->first; ale; ale= ale->next) {
03669         FCurve *fcu= (FCurve *)ale->key_data;
03670         
03671         if (fcu->bezt) {
03672             BeztMap *bezm;
03673             
03674             /* adjust transform-data pointers */
03675             /* note, none of these functions use 'use_handle', it could be removed */
03676             bezm= bezt_to_beztmaps(fcu->bezt, fcu->totvert, use_handle);
03677             sort_time_beztmaps(bezm, fcu->totvert, use_handle);
03678             beztmap_to_data(t, fcu, bezm, fcu->totvert, use_handle);
03679             
03680             /* free mapping stuff */
03681             MEM_freeN(bezm);
03682             
03683             /* re-sort actual beztriples (perhaps this could be done using the beztmaps to save time?) */
03684             sort_time_fcurve(fcu);
03685             
03686             /* make sure handles are all set correctly */
03687             testhandles_fcurve(fcu, use_handle);
03688         }
03689     }
03690 }
03691 
03692 /* this function is called on recalcData to apply the transforms applied
03693  * to the transdata on to the actual keyframe data
03694  */
03695 void flushTransGraphData(TransInfo *t)
03696 {
03697     SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
03698     TransData *td;
03699     TransData2D *td2d;
03700     Scene *scene= t->scene;
03701     double secf= FPS;
03702     int a;
03703 
03704     /* flush to 2d vector from internally used 3d vector */
03705     for (a=0, td= t->data, td2d=t->data2d; a<t->total; a++, td++, td2d++) {
03706         AnimData *adt= (AnimData *)td->extra; /* pointers to relevant AnimData blocks are stored in the td->extra pointers */
03707         
03708         /* handle snapping for time values
03709          *  - we should still be in NLA-mapping timespace
03710          *  - only apply to keyframes (but never to handles)
03711          */
03712         if ((td->flag & TD_NOTIMESNAP)==0) {
03713             switch (sipo->autosnap) {
03714                 case SACTSNAP_FRAME: /* snap to nearest frame (or second if drawing seconds) */
03715                     if (sipo->flag & SIPO_DRAWTIME)
03716                         td2d->loc[0]= (float)( floor((td2d->loc[0]/secf) + 0.5f) * secf );
03717                     else
03718                         td2d->loc[0]= (float)( floor(td2d->loc[0]+0.5f) );
03719                     break;
03720                 
03721                 case SACTSNAP_MARKER: /* snap to nearest marker */
03722                     td2d->loc[0]= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, td2d->loc[0]);
03723                     break;
03724             }
03725         }
03726         
03727         /* we need to unapply the nla-mapping from the time in some situations */
03728         if (adt)
03729             td2d->loc2d[0]= BKE_nla_tweakedit_remap(adt, td2d->loc[0], NLATIME_CONVERT_UNMAP);
03730         else
03731             td2d->loc2d[0]= td2d->loc[0];
03732         
03733         /* if int-values only, truncate to integers */
03734         if (td->flag & TD_INTVALUES)
03735             td2d->loc2d[1]= floorf(td2d->loc[1] + 0.5f);
03736         else
03737             td2d->loc2d[1]= td2d->loc[1];
03738         
03739         if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
03740             td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0];
03741             td2d->h1[1] = td2d->ih1[1] + td->loc[1] - td->iloc[1];
03742         }
03743         
03744         if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) {
03745             td2d->h2[0] = td2d->ih2[0] + td->loc[0] - td->iloc[0];
03746             td2d->h2[1] = td2d->ih2[1] + td->loc[1] - td->iloc[1];
03747         }
03748     }
03749 }
03750 
03751 /* ******************* Sequencer Transform data ******************* */
03752 
03753 /* This function applies the rules for transforming a strip so duplicate
03754  * checks dont need to be added in multiple places.
03755  *
03756  * recursive, count and flag MUST be set.
03757  *
03758  * seq->depth must be set before running this function so we know if the strips
03759  * are root level or not
03760  */
03761 static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count, int *flag)
03762 {
03763     /* for extend we need to do some tricks */
03764     if (t->mode == TFM_TIME_EXTEND) {
03765 
03766         /* *** Extend Transform *** */
03767 
03768         Scene * scene= t->scene;
03769         int cfra= CFRA;
03770         int left= seq_tx_get_final_left(seq, 0);
03771         int right= seq_tx_get_final_right(seq, 0);
03772 
03773         if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) {
03774             *recursive= 0;
03775             *count= 0;
03776             *flag= 0;
03777         }
03778         else if (seq->type ==SEQ_META) {
03779 
03780             /* for meta's we only ever need to extend their children, no matter what depth
03781              * just check the meta's are in the bounds */
03782             if (t->frame_side=='R' && right <= cfra)        *recursive= 0;
03783             else if (t->frame_side=='L' && left >= cfra)    *recursive= 0;
03784             else                                            *recursive= 1;
03785 
03786             *count= 0;
03787             *flag= 0;
03788         }
03789         else {
03790 
03791             *recursive= 0;  /* not a meta, so no thinking here */
03792             *count= 1;      /* unless its set to 0, extend will never set 2 handles at once */
03793             *flag= (seq->flag | SELECT) & ~(SEQ_LEFTSEL|SEQ_RIGHTSEL);
03794 
03795             if (t->frame_side=='R') {
03796                 if (right <= cfra)      *count= *flag= 0;   /* ignore */
03797                 else if (left > cfra)   ;   /* keep the selection */
03798                 else                    *flag |= SEQ_RIGHTSEL;
03799             }
03800             else {
03801                 if (left >= cfra)       *count= *flag= 0;   /* ignore */
03802                 else if (right < cfra)  ;   /* keep the selection */
03803                 else                    *flag |= SEQ_LEFTSEL;
03804             }
03805         }
03806     } else {
03807 
03808         t->frame_side= 'B';
03809 
03810         /* *** Normal Transform *** */
03811 
03812         if (seq->depth == 0) {
03813 
03814             /* Count */
03815 
03816             /* Non nested strips (resect selection and handles) */
03817             if ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK)) {
03818                 *recursive= 0;
03819                 *count= 0;
03820                 *flag= 0;
03821             }
03822             else {
03823                 if ((seq->flag & (SEQ_LEFTSEL|SEQ_RIGHTSEL)) == (SEQ_LEFTSEL|SEQ_RIGHTSEL)) {
03824                     *flag= seq->flag;
03825                     *count= 2; /* we need 2 transdata's */
03826                 } else {
03827                     *flag= seq->flag;
03828                     *count= 1; /* selected or with a handle selected */
03829                 }
03830 
03831                 /* Recursive */
03832 
03833                 if ((seq->type == SEQ_META) && ((seq->flag & (SEQ_LEFTSEL|SEQ_RIGHTSEL)) == 0)) {
03834                     /* if any handles are selected, dont recurse */
03835                     *recursive = 1;
03836                 }
03837                 else {
03838                     *recursive = 0;
03839                 }
03840             }
03841         }
03842         else {
03843             /* Nested, different rules apply */
03844 
03845 #ifdef SEQ_TX_NESTED_METAS
03846             *flag= (seq->flag | SELECT) & ~(SEQ_LEFTSEL|SEQ_RIGHTSEL);
03847             *count= 1; /* ignore the selection for nested */
03848             *recursive = (seq->type == SEQ_META );
03849 #else
03850             if (seq->type == SEQ_META) {
03851                 /* Meta's can only directly be moved between channels since they
03852                  * dont have their start and length set directly (children affect that)
03853                  * since this Meta is nested we dont need any of its data infact.
03854                  * calc_sequence() will update its settings when run on the toplevel meta */
03855                 *flag= 0;
03856                 *count= 0;
03857                 *recursive = 1;
03858             }
03859             else {
03860                 *flag= (seq->flag | SELECT) & ~(SEQ_LEFTSEL|SEQ_RIGHTSEL);
03861                 *count= 1; /* ignore the selection for nested */
03862                 *recursive = 0;
03863             }
03864 #endif
03865         }
03866     }
03867 }
03868 
03869 
03870 
03871 static int SeqTransCount(TransInfo *t, ListBase *seqbase, int depth)
03872 {
03873     Sequence *seq;
03874     int tot= 0, recursive, count, flag;
03875 
03876     for (seq= seqbase->first; seq; seq= seq->next) {
03877         seq->depth= depth;
03878 
03879         SeqTransInfo(t, seq, &recursive, &count, &flag); /* ignore the flag */
03880         tot += count;
03881 
03882         if (recursive) {
03883             tot += SeqTransCount(t, &seq->seqbase, depth+1);
03884         }
03885     }
03886 
03887     return tot;
03888 }
03889 
03890 
03891 static TransData *SeqToTransData(TransData *td, TransData2D *td2d, TransDataSeq *tdsq, Sequence *seq, int flag, int sel_flag)
03892 {
03893     int start_left;
03894 
03895     switch(sel_flag) {
03896     case SELECT:
03897         /* Use seq_tx_get_final_left() and an offset here
03898          * so transform has the left hand location of the strip.
03899          * tdsq->start_offset is used when flushing the tx data back */
03900         start_left= seq_tx_get_final_left(seq, 0);
03901         td2d->loc[0]= start_left;
03902         tdsq->start_offset= start_left - seq->start; /* use to apply the original location */
03903         break;
03904     case SEQ_LEFTSEL:
03905         start_left= seq_tx_get_final_left(seq, 0);
03906         td2d->loc[0] = start_left;
03907         break;
03908     case SEQ_RIGHTSEL:
03909         td2d->loc[0] = seq_tx_get_final_right(seq, 0);
03910         break;
03911     }
03912 
03913     td2d->loc[1] = seq->machine; /* channel - Y location */
03914     td2d->loc[2] = 0.0f;
03915     td2d->loc2d = NULL;
03916 
03917 
03918     tdsq->seq= seq;
03919 
03920     /* Use instead of seq->flag for nested strips and other
03921      * cases where the selection may need to be modified */
03922     tdsq->flag= flag;
03923     tdsq->sel_flag= sel_flag;
03924 
03925 
03926     td->extra= (void *)tdsq; /* allow us to update the strip from here */
03927 
03928     td->flag = 0;
03929     td->loc = td2d->loc;
03930     copy_v3_v3(td->center, td->loc);
03931     copy_v3_v3(td->iloc, td->loc);
03932 
03933     memset(td->axismtx, 0, sizeof(td->axismtx));
03934     td->axismtx[2][2] = 1.0f;
03935 
03936     td->ext= NULL; td->val= NULL;
03937 
03938     td->flag |= TD_SELECTED;
03939     td->dist= 0.0;
03940 
03941     unit_m3(td->mtx);
03942     unit_m3(td->smtx);
03943 
03944     /* Time Transform (extend) */
03945     td->val= td2d->loc;
03946     td->ival= td2d->loc[0];
03947 
03948     return td;
03949 }
03950 
03951 static int SeqToTransData_Recursive(TransInfo *t, ListBase *seqbase, TransData *td, TransData2D *td2d, TransDataSeq *tdsq)
03952 {
03953     Sequence *seq;
03954     int recursive, count, flag;
03955     int tot= 0;
03956 
03957     for (seq= seqbase->first; seq; seq= seq->next) {
03958 
03959         SeqTransInfo(t, seq, &recursive, &count, &flag);
03960 
03961         /* add children first so recalculating metastrips does nested strips first */
03962         if (recursive) {
03963             int tot_children= SeqToTransData_Recursive(t, &seq->seqbase, td, td2d, tdsq);
03964 
03965             td=     td +    tot_children;
03966             td2d=   td2d +  tot_children;
03967             tdsq=   tdsq +  tot_children;
03968 
03969             tot += tot_children;
03970         }
03971 
03972         /* use 'flag' which is derived from seq->flag but modified for special cases */
03973         if (flag & SELECT) {
03974             if (flag & (SEQ_LEFTSEL|SEQ_RIGHTSEL)) {
03975                 if (flag & SEQ_LEFTSEL) {
03976                     SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_LEFTSEL);
03977                     tot++;
03978                 }
03979                 if (flag & SEQ_RIGHTSEL) {
03980                     SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_RIGHTSEL);
03981                     tot++;
03982                 }
03983             }
03984             else {
03985                 SeqToTransData(td++, td2d++, tdsq++, seq, flag, SELECT);
03986                 tot++;
03987             }
03988         }
03989     }
03990 
03991     return tot;
03992 }
03993 
03994 static void freeSeqData(TransInfo *t)
03995 {
03996     Editing *ed= seq_give_editing(t->scene, FALSE);
03997 
03998     if(ed != NULL) {
03999         ListBase *seqbasep= ed->seqbasep;
04000         TransData *td= t->data;
04001         int a;
04002 
04003         /* prevent updating the same seq twice
04004          * if the transdata order is changed this will mess up
04005          * but so will TransDataSeq */
04006         Sequence *seq_prev= NULL;
04007         Sequence *seq;
04008 
04009 
04010         if (!(t->state == TRANS_CANCEL)) {
04011 
04012 #if 0       // default 2.4 behavior
04013 
04014             /* flush to 2d vector from internally used 3d vector */
04015             for(a=0; a<t->total; a++, td++) {
04016                 if ((seq != seq_prev) && (seq->depth==0) && (seq->flag & SEQ_OVERLAP)) {
04017                 seq= ((TransDataSeq *)td->extra)->seq;
04018                     shuffle_seq(seqbasep, seq);
04019                 }
04020 
04021                 seq_prev= seq;
04022             }
04023 
04024 #else       // durian hack
04025             {
04026                 int overlap= 0;
04027 
04028                 for(a=0; a<t->total; a++, td++) {
04029                     seq_prev= NULL;
04030                     seq= ((TransDataSeq *)td->extra)->seq;
04031                     if ((seq != seq_prev) && (seq->depth==0) && (seq->flag & SEQ_OVERLAP)) {
04032                         overlap= 1;
04033                         break;
04034                     }
04035                     seq_prev= seq;
04036                 }
04037 
04038                 if(overlap) {
04039                     int has_effect= 0;
04040                     for(seq= seqbasep->first; seq; seq= seq->next)
04041                         seq->tmp= NULL;
04042 
04043                     td= t->data;
04044                     seq_prev= NULL;
04045                     for(a=0; a<t->total; a++, td++) {
04046                         seq= ((TransDataSeq *)td->extra)->seq;
04047                         if ((seq != seq_prev)) {
04048                             /* check effects strips, we cant change their time */
04049                             if((seq->type & SEQ_EFFECT) && seq->seq1) {
04050                                 has_effect= TRUE;
04051                             }
04052                             else {
04053                                 /* Tag seq with a non zero value, used by shuffle_seq_time to identify the ones to shuffle */
04054                                 seq->tmp= (void*)1;
04055                             }
04056                         }
04057                     }
04058 
04059                     shuffle_seq_time(seqbasep, t->scene);
04060 
04061                     if(has_effect) {
04062                         /* update effects strips based on strips just moved in time */
04063                         td= t->data;
04064                         seq_prev= NULL;
04065                         for(a=0; a<t->total; a++, td++) {
04066                             seq= ((TransDataSeq *)td->extra)->seq;
04067                             if ((seq != seq_prev)) {
04068                                 if((seq->type & SEQ_EFFECT) && seq->seq1) {
04069                                     calc_sequence(t->scene, seq);
04070                                 }
04071                             }
04072                         }
04073 
04074                         /* now if any effects _still_ overlap, we need to move them up */
04075                         td= t->data;
04076                         seq_prev= NULL;
04077                         for(a=0; a<t->total; a++, td++) {
04078                             seq= ((TransDataSeq *)td->extra)->seq;
04079                             if ((seq != seq_prev)) {
04080                                 if((seq->type & SEQ_EFFECT) && seq->seq1) {
04081                                     if(seq_test_overlap(seqbasep, seq)) {
04082                                         shuffle_seq(seqbasep, seq, t->scene);
04083                                     }
04084                                 }
04085                             }
04086                         }
04087                         /* done with effects */
04088                     }
04089                 }
04090             }
04091 #endif
04092 
04093             for(seq= seqbasep->first; seq; seq= seq->next) {
04094                 /* We might want to build a list of effects that need to be updated during transform */
04095                 if(seq->type & SEQ_EFFECT) {
04096                     if      (seq->seq1 && seq->seq1->flag & SELECT) calc_sequence(t->scene, seq);
04097                     else if (seq->seq2 && seq->seq2->flag & SELECT) calc_sequence(t->scene, seq);
04098                     else if (seq->seq3 && seq->seq3->flag & SELECT) calc_sequence(t->scene, seq);
04099                 }
04100             }
04101 
04102             sort_seq(t->scene);
04103         }
04104         else {
04105             /* Cancelled, need to update the strips display */
04106             for(a=0; a<t->total; a++, td++) {
04107                 seq= ((TransDataSeq *)td->extra)->seq;
04108                 if ((seq != seq_prev) && (seq->depth==0)) {
04109                     calc_sequence_disp(t->scene, seq);
04110                 }
04111                 seq_prev= seq;
04112             }
04113         }
04114     }
04115 
04116     if (t->customData) {
04117         MEM_freeN(t->customData);
04118         t->customData= NULL;
04119     }
04120     if (t->data) {
04121         MEM_freeN(t->data); // XXX postTrans usually does this
04122         t->data= NULL;
04123     }
04124 }
04125 
04126 static void createTransSeqData(bContext *C, TransInfo *t)
04127 {
04128 #define XXX_DURIAN_ANIM_TX_HACK
04129 
04130     View2D *v2d= UI_view2d_fromcontext(C);
04131     Scene *scene= t->scene;
04132     Editing *ed= seq_give_editing(t->scene, FALSE);
04133     TransData *td = NULL;
04134     TransData2D *td2d= NULL;
04135     TransDataSeq *tdsq= NULL;
04136 
04137     int count=0;
04138 
04139     if (ed==NULL) {
04140         t->total= 0;
04141         return;
04142     }
04143 
04144     t->customFree= freeSeqData;
04145 
04146     /* which side of the current frame should be allowed */
04147     if (t->mode == TFM_TIME_EXTEND) {
04148         /* only side on which mouse is gets transformed */
04149         float xmouse, ymouse;
04150 
04151         UI_view2d_region_to_view(v2d, t->imval[0], t->imval[1], &xmouse, &ymouse);
04152         t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
04153     }
04154     else {
04155         /* normal transform - both sides of current frame are considered */
04156         t->frame_side = 'B';
04157     }
04158 
04159 #ifdef XXX_DURIAN_ANIM_TX_HACK
04160     {
04161         Sequence *seq;
04162         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
04163             /* hack */
04164             if((seq->flag & SELECT)==0 && seq->type & SEQ_EFFECT) {
04165                 Sequence *seq_user;
04166                 int i;
04167                 for(i=0; i<3; i++) {
04168                     seq_user= *((&seq->seq1) + i);
04169                     if ( seq_user && (seq_user->flag & SELECT) &&
04170                          !(seq_user->flag & SEQ_LOCK) &&
04171                          !(seq_user->flag & (SEQ_LEFTSEL|SEQ_RIGHTSEL)))
04172                     {
04173                         seq->flag |= SELECT;
04174                     }
04175                 }
04176             }
04177         }
04178     }
04179 #endif
04180 
04181     count = SeqTransCount(t, ed->seqbasep, 0);
04182 
04183     /* allocate memory for data */
04184     t->total= count;
04185 
04186     /* stop if trying to build list if nothing selected */
04187     if (count == 0) {
04188         return;
04189     }
04190 
04191     td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransSeq TransData");
04192     td2d = t->data2d = MEM_callocN(t->total*sizeof(TransData2D), "TransSeq TransData2D");
04193     tdsq = t->customData= MEM_callocN(t->total*sizeof(TransDataSeq), "TransSeq TransDataSeq");
04194 
04195 
04196 
04197     /* loop 2: build transdata array */
04198     SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
04199 
04200 #undef XXX_DURIAN_ANIM_TX_HACK
04201 }
04202 
04203 
04204 /* *********************** Object Transform data ******************* */
04205 
04206 /* Little helper function for ObjectToTransData used to give certain
04207  * constraints (ChildOf, FollowPath, and others that may be added)
04208  * inverse corrections for transform, so that they aren't in CrazySpace.
04209  * These particular constraints benefit from this, but others don't, hence
04210  * this semi-hack ;-)    - Aligorith
04211  */
04212 static short constraints_list_needinv(TransInfo *t, ListBase *list)
04213 {
04214     bConstraint *con;
04215 
04216     /* loop through constraints, checking if there's one of the mentioned
04217      * constraints needing special crazyspace corrections
04218      */
04219     if (list) {
04220         for (con= list->first; con; con=con->next) {
04221             /* only consider constraint if it is enabled, and has influence on result */
04222             if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0f)) {
04223                 /* (affirmative) returns for specific constraints here... */
04224                     /* constraints that require this regardless  */
04225                 if (con->type == CONSTRAINT_TYPE_CHILDOF) return 1;
04226                 if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) return 1;
04227                 if (con->type == CONSTRAINT_TYPE_CLAMPTO) return 1;
04228                 if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) return 1;
04229                 
04230                     /* constraints that require this only under special conditions */
04231                 if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
04232                     /* CopyRot constraint only does this when rotating, and offset is on */
04233                     bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
04234                     
04235                     if ((data->flag & ROTLIKE_OFFSET) && (t->mode == TFM_ROTATION))
04236                         return 1;
04237                 }
04238             }
04239         }
04240     }
04241 
04242     /* no appropriate candidates found */
04243     return 0;
04244 }
04245 
04246 /* transcribe given object into TransData for Transforming */
04247 static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
04248 {
04249     Scene *scene = t->scene;
04250     float obmtx[3][3];
04251     short constinv;
04252     short skip_invert = 0;
04253 
04254     /* axismtx has the real orientation */
04255     copy_m3_m4(td->axismtx, ob->obmat);
04256     normalize_m3(td->axismtx);
04257 
04258     td->con= ob->constraints.first;
04259 
04260     /* hack: tempolarily disable tracking and/or constraints when getting
04261      *      object matrix, if tracking is on, or if constraints don't need
04262      *      inverse correction to stop it from screwing up space conversion
04263      *      matrix later
04264      */
04265     constinv = constraints_list_needinv(t, &ob->constraints);
04266 
04267     /* disable constraints inversion for dummy pass */
04268     if (t->mode == TFM_DUMMY)
04269         skip_invert = 1;
04270 
04271     if (skip_invert == 0 && constinv == 0) {
04272         if (constinv == 0)
04273             ob->transflag |= OB_NO_CONSTRAINTS; /* where_is_object_time checks this */
04274         
04275         where_is_object(t->scene, ob);
04276         
04277         if (constinv == 0)
04278             ob->transflag &= ~OB_NO_CONSTRAINTS;
04279     }
04280     else
04281         where_is_object(t->scene, ob);
04282 
04283     td->ob = ob;
04284 
04285     td->loc = ob->loc;
04286     copy_v3_v3(td->iloc, td->loc);
04287     
04288     if (ob->rotmode > 0) {
04289         td->ext->rot= ob->rot;
04290         td->ext->rotAxis= NULL;
04291         td->ext->rotAngle= NULL;
04292         td->ext->quat= NULL;
04293         
04294         copy_v3_v3(td->ext->irot, ob->rot);
04295         copy_v3_v3(td->ext->drot, ob->drot);
04296     }
04297     else if (ob->rotmode == ROT_MODE_AXISANGLE) {
04298         td->ext->rot= NULL;
04299         td->ext->rotAxis= ob->rotAxis;
04300         td->ext->rotAngle= &ob->rotAngle;
04301         td->ext->quat= NULL;
04302         
04303         td->ext->irotAngle= ob->rotAngle;
04304         copy_v3_v3(td->ext->irotAxis, ob->rotAxis);
04305         // td->ext->drotAngle= ob->drotAngle;           // XXX, not implimented
04306         // copy_v3_v3(td->ext->drotAxis, ob->drotAxis); // XXX, not implimented
04307     }
04308     else {
04309         td->ext->rot= NULL;
04310         td->ext->rotAxis= NULL;
04311         td->ext->rotAngle= NULL;
04312         td->ext->quat= ob->quat;
04313         
04314         copy_qt_qt(td->ext->iquat, ob->quat);
04315         copy_qt_qt(td->ext->dquat, ob->dquat);
04316     }
04317     td->ext->rotOrder=ob->rotmode;
04318 
04319     td->ext->size = ob->size;
04320     copy_v3_v3(td->ext->isize, ob->size);
04321     copy_v3_v3(td->ext->dscale, ob->dscale);
04322 
04323     copy_v3_v3(td->center, ob->obmat[3]);
04324 
04325     copy_m4_m4(td->ext->obmat, ob->obmat);
04326 
04327     /* is there a need to set the global<->data space conversion matrices? */
04328     if (ob->parent || constinv) {
04329         float totmat[3][3], obinv[3][3];
04330 
04331         /* Get the effect of parenting, and/or certain constraints.
04332          * NOTE: some Constraints, and also Tracking should never get this
04333          *      done, as it doesn't work well.
04334          */
04335         object_to_mat3(ob, obmtx);
04336         copy_m3_m4(totmat, ob->obmat);
04337         invert_m3_m3(obinv, totmat);
04338         mul_m3_m3m3(td->smtx, obmtx, obinv);
04339         invert_m3_m3(td->mtx, td->smtx);
04340     }
04341     else {
04342         /* no conversion to/from dataspace */
04343         unit_m3(td->smtx);
04344         unit_m3(td->mtx);
04345     }
04346 
04347     /* set active flag */
04348     if (ob == OBACT)
04349     {
04350         td->flag |= TD_ACTIVE;
04351     }
04352 }
04353 
04354 
04355 /* sets flags in Bases to define whether they take part in transform */
04356 /* it deselects Bases, so we have to call the clear function always after */
04357 static void set_trans_object_base_flags(TransInfo *t)
04358 {
04359     Scene *scene = t->scene;
04360     View3D *v3d = t->view;
04361 
04362     /*
04363      if Base selected and has parent selected:
04364      base->flag= BA_WAS_SEL
04365      */
04366     Base *base;
04367 
04368     /* don't do it if we're not actually going to recalculate anything */
04369     if(t->mode == TFM_DUMMY)
04370         return;
04371 
04372     /* makes sure base flags and object flags are identical */
04373     copy_baseflags(t->scene);
04374 
04375     /* handle pending update events, otherwise they got copied below */
04376     for (base= scene->base.first; base; base= base->next) {
04377         if(base->object->recalc)
04378             object_handle_update(t->scene, base->object);
04379     }
04380 
04381     for (base= scene->base.first; base; base= base->next) {
04382         base->flag &= ~BA_WAS_SEL;
04383 
04384         if(TESTBASELIB_BGMODE(v3d, scene, base)) {
04385             Object *ob= base->object;
04386             Object *parsel= ob->parent;
04387 
04388             /* if parent selected, deselect */
04389             while(parsel) {
04390                 if(parsel->flag & SELECT) {
04391                     Base *parbase = object_in_scene(parsel, scene);
04392                     if(parbase) { /* in rare cases this can fail */
04393                         if TESTBASELIB_BGMODE(v3d, scene, parbase) {
04394                             break;
04395                         }
04396                     }
04397                 }
04398                 parsel= parsel->parent;
04399             }
04400 
04401             if(parsel)
04402             {
04403                 /* rotation around local centers are allowed to propagate */
04404                 if ((t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)  && t->around == V3D_LOCAL) {
04405                     base->flag |= BA_TRANSFORM_CHILD;
04406                 } else {
04407                     base->flag &= ~SELECT;
04408                     base->flag |= BA_WAS_SEL;
04409                 }
04410             }
04411             /* used for flush, depgraph will change recalcs if needed :) */
04412             ob->recalc |= OB_RECALC_OB;
04413         }
04414     }
04415 
04416     /* all recalc flags get flushed to all layers, so a layer flip later on works fine */
04417     DAG_scene_flush_update(G.main, t->scene, -1, 0);
04418 
04419     /* and we store them temporal in base (only used for transform code) */
04420     /* this because after doing updates, the object->recalc is cleared */
04421     for (base= scene->base.first; base; base= base->next) {
04422         if(base->object->recalc & OB_RECALC_OB)
04423             base->flag |= BA_HAS_RECALC_OB;
04424         if(base->object->recalc & OB_RECALC_DATA)
04425             base->flag |= BA_HAS_RECALC_DATA;
04426     }
04427 }
04428 
04429 static int mark_children(Object *ob)
04430 {
04431     if (ob->flag & (SELECT|BA_TRANSFORM_CHILD))
04432         return 1;
04433 
04434     if (ob->parent)
04435     {
04436         if (mark_children(ob->parent))
04437         {
04438             ob->flag |= BA_TRANSFORM_CHILD;
04439             return 1;
04440         }
04441     }
04442     
04443     return 0;
04444 }
04445 
04446 static int count_proportional_objects(TransInfo *t)
04447 {
04448     int total = 0;
04449     Scene *scene = t->scene;
04450     View3D *v3d = t->view;
04451     Base *base;
04452 
04453     /* rotations around local centers are allowed to propagate, so we take all objects */
04454     if (!((t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)  && t->around == V3D_LOCAL))
04455     {
04456         /* mark all parents */
04457         for (base= scene->base.first; base; base= base->next) {
04458             if(TESTBASELIB_BGMODE(v3d, scene, base)) {
04459                 Object *parent = base->object->parent;
04460     
04461                 /* flag all parents */
04462                 while(parent) {
04463                     parent->flag |= BA_TRANSFORM_PARENT;
04464                     parent = parent->parent;
04465                 }
04466             }
04467         }
04468 
04469         /* mark all children */
04470         for (base= scene->base.first; base; base= base->next) {
04471             /* all base not already selected or marked that is editable */
04472             if ( (base->object->flag & (SELECT|BA_TRANSFORM_CHILD|BA_TRANSFORM_PARENT)) == 0 &&
04473                  (BASE_EDITABLE_BGMODE(v3d, scene, base)))
04474             {
04475                 mark_children(base->object);
04476             }
04477         }
04478     }
04479     
04480     for (base= scene->base.first; base; base= base->next) {
04481         Object *ob= base->object;
04482 
04483         /* if base is not selected, not a parent of selection or not a child of selection and it is editable */
04484         if ( (ob->flag & (SELECT|BA_TRANSFORM_CHILD|BA_TRANSFORM_PARENT)) == 0 &&
04485              (BASE_EDITABLE_BGMODE(v3d, scene, base)))
04486         {
04487 
04488             /* used for flush, depgraph will change recalcs if needed :) */
04489             ob->recalc |= OB_RECALC_OB;
04490 
04491             total += 1;
04492         }
04493     }
04494     
04495 
04496     /* all recalc flags get flushed to all layers, so a layer flip later on works fine */
04497     DAG_scene_flush_update(G.main, t->scene, -1, 0);
04498 
04499     /* and we store them temporal in base (only used for transform code) */
04500     /* this because after doing updates, the object->recalc is cleared */
04501     for (base= scene->base.first; base; base= base->next) {
04502         if(base->object->recalc & OB_RECALC_OB)
04503             base->flag |= BA_HAS_RECALC_OB;
04504         if(base->object->recalc & OB_RECALC_DATA)
04505             base->flag |= BA_HAS_RECALC_DATA;
04506     }
04507 
04508     return total;
04509 }
04510 
04511 static void clear_trans_object_base_flags(TransInfo *t)
04512 {
04513     Scene *sce = t->scene;
04514     Base *base;
04515 
04516     for (base= sce->base.first; base; base = base->next)
04517     {
04518         if(base->flag & BA_WAS_SEL)
04519             base->flag |= SELECT;
04520 
04521         base->flag &= ~(BA_WAS_SEL|BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA|BA_TEMP_TAG|BA_TRANSFORM_CHILD|BA_TRANSFORM_PARENT);
04522     }
04523 }
04524 
04525 /* auto-keyframing feature - for objects
04526  *  tmode: should be a transform mode
04527  */
04528 // NOTE: context may not always be available, so must check before using it as it's a luxury for a few cases
04529 void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, int tmode)
04530 {
04531     ID *id= &ob->id;
04532     FCurve *fcu;
04533     
04534     // TODO: this should probably be done per channel instead...
04535     if (autokeyframe_cfra_can_key(scene, id)) {
04536         ReportList *reports = CTX_wm_reports(C);
04537         KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
04538         ListBase dsources = {NULL, NULL};
04539         float cfra= (float)CFRA; // xxx this will do for now
04540         short flag = 0;
04541         
04542         /* get flags used for inserting keyframes */
04543         flag = ANIM_get_keyframing_flags(scene, 1);
04544         
04545         /* add datasource override for the camera object */
04546         ANIM_relative_keyingset_add_source(&dsources, id, NULL, NULL); 
04547         
04548         if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
04549             /* only insert into active keyingset 
04550              * NOTE: we assume here that the active Keying Set does not need to have its iterator overridden spe
04551              */
04552             ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
04553         }
04554         else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
04555             AnimData *adt= ob->adt;
04556             
04557             /* only key on available channels */
04558             if (adt && adt->action) {
04559                 for (fcu= adt->action->curves.first; fcu; fcu= fcu->next) {
04560                     fcu->flag &= ~FCURVE_SELECTED;
04561                     insert_keyframe(reports, id, adt->action,
04562                                     (fcu->grp ? fcu->grp->name : NULL),
04563                                     fcu->rna_path, fcu->array_index, cfra, flag);
04564                 }
04565             }
04566         }
04567         else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
04568             short doLoc=0, doRot=0, doScale=0;
04569             
04570             /* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */
04571             if (tmode == TFM_TRANSLATION) {
04572                 doLoc = 1;
04573             }
04574             else if (tmode == TFM_ROTATION) {
04575                 if (v3d->around == V3D_ACTIVE) {
04576                     if (ob != OBACT)
04577                         doLoc = 1;
04578                 }
04579                 else if (v3d->around == V3D_CURSOR)
04580                     doLoc = 1;
04581                 
04582                 if ((v3d->flag & V3D_ALIGN)==0)
04583                     doRot = 1;
04584             }
04585             else if (tmode == TFM_RESIZE) {
04586                 if (v3d->around == V3D_ACTIVE) {
04587                     if (ob != OBACT)
04588                         doLoc = 1;
04589                 }
04590                 else if (v3d->around == V3D_CURSOR)
04591                     doLoc = 1;
04592                 
04593                 if ((v3d->flag & V3D_ALIGN)==0)
04594                     doScale = 1;
04595             }
04596             
04597             /* insert keyframes for the affected sets of channels using the builtin KeyingSets found */
04598             if (doLoc) {
04599                 KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
04600                 ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
04601             }
04602             if (doRot) {
04603                 KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
04604                 ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
04605             }
04606             if (doScale) {
04607                 KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
04608                 ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
04609             }
04610         }
04611         /* insert keyframe in all (transform) channels */
04612         else {
04613             KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
04614             ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
04615         }
04616         
04617         /* free temp info */
04618         BLI_freelistN(&dsources);
04619     }
04620 }
04621 
04622 /* auto-keyframing feature - for poses/pose-channels
04623  *  tmode: should be a transform mode
04624  *  targetless_ik: has targetless ik been done on any channels?
04625  */
04626 // NOTE: context may not always be available, so must check before using it as it's a luxury for a few cases
04627 void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, int tmode, short targetless_ik)
04628 {
04629     ID *id= &ob->id;
04630     AnimData *adt= ob->adt;
04631     bAction *act= (adt) ? adt->action : NULL;
04632     bPose   *pose= ob->pose;
04633     bPoseChannel *pchan;
04634     FCurve *fcu;
04635     
04636     // TODO: this should probably be done per channel instead...
04637     if (autokeyframe_cfra_can_key(scene, id)) {
04638         ReportList *reports = CTX_wm_reports(C);
04639         KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
04640         float cfra= (float)CFRA;
04641         short flag= 0;
04642         
04643         /* flag is initialised from UserPref keyframing settings
04644          *  - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
04645          *    visual keyframes even if flag not set, as it's not that useful otherwise
04646          *    (for quick animation recording)
04647          */
04648         flag = ANIM_get_keyframing_flags(scene, 1);
04649         
04650         if (targetless_ik) 
04651             flag |= INSERTKEY_MATRIX;
04652         
04653         for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) {
04654             if (pchan->bone->flag & BONE_TRANSFORM) {
04655                 ListBase dsources = {NULL, NULL};
04656                 
04657                 /* clear any 'unkeyed' flag it may have */
04658                 pchan->bone->flag &= ~BONE_UNKEYED;
04659                 
04660                 /* add datasource override for the camera object */
04661                 ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan); 
04662                 
04663                 /* only insert into active keyingset? */
04664                 if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
04665                     /* run the active Keying Set on the current datasource */
04666                     ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
04667                 }
04668                 /* only insert into available channels? */
04669                 else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
04670                     if (act) {
04671                         for (fcu= act->curves.first; fcu; fcu= fcu->next) {
04672                             /* only insert keyframes for this F-Curve if it affects the current bone */
04673                             if (strstr(fcu->rna_path, "bones")) {
04674                                 char *pchanName= BLI_getQuotedStr(fcu->rna_path, "bones[");
04675                                 
04676                                 /* only if bone name matches too... 
04677                                  * NOTE: this will do constraints too, but those are ok to do here too?
04678                                  */
04679                                 if (pchanName && strcmp(pchanName, pchan->name) == 0) 
04680                                     insert_keyframe(reports, id, act, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
04681                                     
04682                                 if (pchanName) MEM_freeN(pchanName);
04683                             }
04684                         }
04685                     }
04686                 }
04687                 /* only insert keyframe if needed? */
04688                 else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
04689                     short doLoc=0, doRot=0, doScale=0;
04690                     
04691                     /* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */
04692                     if (tmode == TFM_TRANSLATION) {
04693                         if (targetless_ik)
04694                             doRot= 1;
04695                         else
04696                             doLoc = 1;
04697                     }
04698                     else if (tmode == TFM_ROTATION) {
04699                         if (ELEM(v3d->around, V3D_CURSOR, V3D_ACTIVE))
04700                             doLoc = 1;
04701                             
04702                         if ((v3d->flag & V3D_ALIGN)==0)
04703                             doRot = 1;
04704                     }
04705                     else if (tmode == TFM_RESIZE) {
04706                         if (ELEM(v3d->around, V3D_CURSOR, V3D_ACTIVE))
04707                             doLoc = 1;
04708                             
04709                         if ((v3d->flag & V3D_ALIGN)==0)
04710                             doScale = 1;
04711                     }
04712                     
04713                     if (doLoc) {
04714                         KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
04715                         ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
04716                     }
04717                     if (doRot) {
04718                         KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
04719                         ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
04720                     }
04721                     if (doScale) {
04722                         KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
04723                         ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
04724                     }
04725                 }
04726                 /* insert keyframe in all (transform) channels */
04727                 else {
04728                     KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
04729                     ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
04730                 }
04731                 
04732                 /* free temp info */
04733                 BLI_freelistN(&dsources);
04734             }
04735         }
04736         
04737         /* do the bone paths 
04738          *  - only do this when there is context info, since we need that to resolve
04739          *    how to do the updates and so on...
04740          *  - do not calculate unless there are paths already to update...
04741          */
04742         if (C && (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
04743             //ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
04744             ED_pose_recalculate_paths(scene, ob);
04745         }
04746     }
04747     else {
04748         /* tag channels that should have unkeyed data */
04749         for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) {
04750             if (pchan->bone->flag & BONE_TRANSFORM) {
04751                 /* tag this channel */
04752                 pchan->bone->flag |= BONE_UNKEYED;
04753             }
04754         }
04755     }
04756 }
04757 
04758 
04759 /* inserting keys, pointcache, redraw events... */
04760 /* 
04761  * note: sequencer freeing has its own function now because of a conflict with transform's order of freeing (campbell)
04762  *       Order changed, the sequencer stuff should go back in here
04763  * */
04764 void special_aftertrans_update(bContext *C, TransInfo *t)
04765 {
04766     Object *ob;
04767 //  short redrawipo=0, resetslowpar=1;
04768     int cancelled= (t->state == TRANS_CANCEL);
04769     short duplicate= (t->mode == TFM_TIME_DUPLICATE);
04770     
04771     /* early out when nothing happened */
04772     if (t->total == 0 || t->mode == TFM_DUMMY)
04773         return;
04774     
04775     if (t->spacetype==SPACE_VIEW3D) {
04776         if (t->obedit) {
04777             if (cancelled==0) {
04778                 EM_automerge(t->scene, t->obedit, 1);
04779             }
04780         }
04781     }
04782     
04783     if (t->spacetype == SPACE_SEQ) {
04784         /* freeSeqData in transform_conversions.c does this
04785          * keep here so the else at the end wont run... */
04786 
04787         SpaceSeq *sseq= (SpaceSeq *)t->sa->spacedata.first;
04788 
04789         /* marker transform, not especially nice but we may want to move markers
04790          * at the same time as keyframes in the dope sheet. */
04791         if ((sseq->flag & SEQ_MARKER_TRANS) && (cancelled == 0)) {
04792             /* cant use , TFM_TIME_EXTEND
04793              * for some reason EXTEND is changed into TRANSLATE, so use frame_side instead */
04794 
04795             if(t->mode == TFM_SEQ_SLIDE) {
04796                 if(t->frame_side == 'B')
04797                     ED_markers_post_apply_transform(&t->scene->markers, t->scene, TFM_TIME_TRANSLATE, t->values[0], t->frame_side);
04798             }
04799             else if (ELEM(t->frame_side, 'L', 'R')) {
04800                 ED_markers_post_apply_transform(&t->scene->markers, t->scene, TFM_TIME_EXTEND, t->values[0], t->frame_side);
04801             }
04802         }
04803 
04804     }
04805     else if (t->spacetype == SPACE_NODE) {
04806         SpaceNode *snode= (SpaceNode *)t->sa->spacedata.first;
04807         ED_node_update_hierarchy(C, snode->edittree);
04808         
04809         if(cancelled == 0)
04810             ED_node_link_insert(t->sa);
04811         
04812         /* clear link line */
04813         ED_node_link_intersect_test(t->sa, 0);
04814     }
04815     else if (t->spacetype == SPACE_CLIP) {
04816         SpaceClip *sc= t->sa->spacedata.first;
04817         MovieClip *clip= ED_space_clip(sc);
04818 
04819         if(t->scene->nodetree) {
04820             /* tracks can be used for stabilization nodes,
04821                flush update for such nodes */
04822             nodeUpdateID(t->scene->nodetree, &clip->id);
04823             WM_event_add_notifier(C, NC_SCENE|ND_NODES, NULL);
04824         }
04825     }
04826     else if (t->spacetype == SPACE_ACTION) {
04827         SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first;
04828         bAnimContext ac;
04829         
04830         /* initialise relevant anim-context 'context' data */
04831         if (ANIM_animdata_get_context(C, &ac) == 0)
04832             return;
04833             
04834         ob = ac.obact;
04835         
04836         if (ELEM(ac.datatype, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
04837             ListBase anim_data = {NULL, NULL};
04838             bAnimListElem *ale;
04839             short filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
04840             
04841             /* get channels to work on */
04842             ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
04843             
04844             /* these should all be F-Curves */
04845             for (ale= anim_data.first; ale; ale= ale->next) {
04846                 AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
04847                 FCurve *fcu= (FCurve *)ale->key_data;
04848                 
04849                 /* 3 cases here for curve cleanups:
04850                  * 1) NOTRANSKEYCULL on     -> cleanup of duplicates shouldn't be done
04851                  * 2) cancelled == 0        -> user confirmed the transform, so duplicates should be removed
04852                  * 3) cancelled + duplicate -> user cancelled the transform, but we made duplicates, so get rid of these
04853                  */
04854                 if ( (saction->flag & SACTION_NOTRANSKEYCULL)==0 &&
04855                      ((cancelled == 0) || (duplicate)) )
04856                 {
04857                     if (adt) {
04858                         ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 1);
04859                         posttrans_fcurve_clean(fcu, FALSE); /* only use handles in graph editor */
04860                         ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 1);
04861                     }
04862                     else
04863                         posttrans_fcurve_clean(fcu, FALSE); /* only use handles in graph editor */
04864                 }
04865             }
04866             
04867             /* free temp memory */
04868             BLI_freelistN(&anim_data);
04869         }
04870         else if (ac.datatype == ANIMCONT_ACTION) { // TODO: just integrate into the above...
04871             /* Depending on the lock status, draw necessary views */
04872             // fixme... some of this stuff is not good
04873             if (ob) {
04874                 if (ob->pose || ob_get_key(ob))
04875                     DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME);
04876                 else
04877                     DAG_id_tag_update(&ob->id, OB_RECALC_OB);
04878             }
04879             
04880             /* 3 cases here for curve cleanups:
04881              * 1) NOTRANSKEYCULL on     -> cleanup of duplicates shouldn't be done
04882              * 2) cancelled == 0        -> user confirmed the transform, so duplicates should be removed
04883              * 3) cancelled + duplicate -> user cancelled the transform, but we made duplicates, so get rid of these
04884              */
04885             if ( (saction->flag & SACTION_NOTRANSKEYCULL)==0 &&
04886                  ((cancelled == 0) || (duplicate)) )
04887             {
04888                 posttrans_action_clean(&ac, (bAction *)ac.data);
04889             }
04890         }
04891         else if (ac.datatype == ANIMCONT_GPENCIL) {
04892             /* remove duplicate frames and also make sure points are in order! */
04893                 /* 3 cases here for curve cleanups:
04894                  * 1) NOTRANSKEYCULL on     -> cleanup of duplicates shouldn't be done
04895                  * 2) cancelled == 0        -> user confirmed the transform, so duplicates should be removed
04896                  * 3) cancelled + duplicate -> user cancelled the transform, but we made duplicates, so get rid of these
04897                  */
04898             if ( (saction->flag & SACTION_NOTRANSKEYCULL)==0 &&
04899                  ((cancelled == 0) || (duplicate)) )
04900             {
04901                 bGPdata *gpd;
04902                 
04903                 // XXX: BAD! this get gpencil datablocks directly from main db...
04904                 // but that's how this currently works :/
04905                 for (gpd = G.main->gpencil.first; gpd; gpd = gpd->id.next) {
04906                     if (ID_REAL_USERS(gpd))
04907                         posttrans_gpd_clean(gpd);
04908                 }
04909             }
04910         }
04911         
04912         /* marker transform, not especially nice but we may want to move markers
04913          * at the same time as keyframes in the dope sheet. 
04914          */
04915         if ((saction->flag & SACTION_MARKERS_MOVE) && (cancelled == 0)) {
04916             if (t->mode == TFM_TIME_TRANSLATE) {
04917 #if 0
04918                 if (ELEM(t->frame_side, 'L', 'R')) { /* TFM_TIME_EXTEND */
04919                     /* same as below */
04920                     ED_markers_post_apply_transform(ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
04921                 }
04922                 else /* TFM_TIME_TRANSLATE */
04923 #endif
04924                 {
04925                     ED_markers_post_apply_transform(ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
04926                 }
04927             }
04928             else if (t->mode == TFM_TIME_SCALE) {
04929                 ED_markers_post_apply_transform(ED_context_get_markers(C), t->scene, t->mode, t->values[0], t->frame_side);
04930             }
04931         }
04932         
04933         /* make sure all F-Curves are set correctly */
04934         if (ac.datatype != ANIMCONT_GPENCIL)
04935             ANIM_editkeyframes_refresh(&ac);
04936         
04937         /* clear flag that was set for time-slide drawing */
04938         saction->flag &= ~SACTION_MOVING;
04939     }
04940     else if (t->spacetype == SPACE_IPO) {
04941         SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first;
04942         bAnimContext ac;
04943         const short use_handle = !(sipo->flag & SIPO_NOHANDLES);
04944         
04945         /* initialise relevant anim-context 'context' data */
04946         if (ANIM_animdata_get_context(C, &ac) == 0)
04947             return;
04948         
04949         if (ac.datatype)
04950         {
04951             ListBase anim_data = {NULL, NULL};
04952             bAnimListElem *ale;
04953             short filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
04954             
04955             /* get channels to work on */
04956             ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
04957             
04958             for (ale= anim_data.first; ale; ale= ale->next) {
04959                 AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
04960                 FCurve *fcu= (FCurve *)ale->key_data;
04961                 
04962                 /* 3 cases here for curve cleanups:
04963                  * 1) NOTRANSKEYCULL on     -> cleanup of duplicates shouldn't be done
04964                  * 2) cancelled == 0        -> user confirmed the transform, so duplicates should be removed
04965                  * 3) cancelled + duplicate -> user cancelled the transform, but we made duplicates, so get rid of these
04966                  */
04967                 if ( (sipo->flag & SIPO_NOTRANSKEYCULL)==0 &&
04968                      ((cancelled == 0) || (duplicate)) )
04969                 {
04970                     if (adt) {
04971                         ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
04972                         posttrans_fcurve_clean(fcu, use_handle);
04973                         ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
04974                     }
04975                     else
04976                         posttrans_fcurve_clean(fcu, use_handle);
04977                 }
04978             }
04979             
04980             /* free temp memory */
04981             BLI_freelistN(&anim_data);
04982         }
04983         
04984         /* Make sure all F-Curves are set correctly, but not if transform was
04985          * canceled, since then curves were already restored to initial state.
04986          * Note: if the refresh is really needed after cancel then some way
04987          *       has to be added to not update handle types (see bug 22289).
04988          */
04989         if(!cancelled)
04990             ANIM_editkeyframes_refresh(&ac);
04991     }
04992     else if (t->spacetype == SPACE_NLA) {
04993         bAnimContext ac;
04994         
04995         /* initialise relevant anim-context 'context' data */
04996         if (ANIM_animdata_get_context(C, &ac) == 0)
04997             return;
04998             
04999         if (ac.datatype)
05000         {
05001             ListBase anim_data = {NULL, NULL};
05002             bAnimListElem *ale;
05003             short filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
05004             
05005             /* get channels to work on */
05006             ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
05007             
05008             for (ale= anim_data.first; ale; ale= ale->next) {
05009                 NlaTrack *nlt= (NlaTrack *)ale->data;
05010                 
05011                 /* make sure strips are in order again */
05012                 BKE_nlatrack_sort_strips(nlt);
05013                 
05014                 /* remove the temp metas */
05015                 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
05016             }
05017             
05018             /* free temp memory */
05019             BLI_freelistN(&anim_data);
05020             
05021             /* perform after-transfrom validation */
05022             ED_nla_postop_refresh(&ac);
05023         }
05024     }
05025     else if (t->obedit) {
05026         if (t->obedit->type == OB_MESH)
05027         {
05028             EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh;
05029             /* table needs to be created for each edit command, since vertices can move etc */
05030             mesh_octree_table(t->obedit, em, NULL, 'e');
05031         }
05032     }
05033     else if ((t->flag & T_POSE) && (t->poseobj)) {
05034         bArmature *arm;
05035         bPoseChannel *pchan;
05036         short targetless_ik= 0;
05037 
05038         ob= t->poseobj;
05039         arm= ob->data;
05040 
05041         if((t->flag & T_AUTOIK) && (t->options & CTX_AUTOCONFIRM)) {
05042             /* when running transform non-interactively (operator exec),
05043              * we need to update the pose otherwise no updates get called during
05044              * transform and the auto-ik is not applied. see [#26164] */
05045             struct Object *pose_ob=t->poseobj;
05046             where_is_pose(t->scene, pose_ob);
05047         }
05048 
05049         /* set BONE_TRANSFORM flags for autokey, manipulator draw might have changed them */
05050         if (!cancelled && (t->mode != TFM_DUMMY))
05051             count_set_pose_transflags(&t->mode, t->around, ob);
05052 
05053         /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
05054         if (!cancelled && t->mode==TFM_TRANSLATION)
05055             targetless_ik= apply_targetless_ik(ob);
05056         else {
05057             /* not forget to clear the auto flag */
05058             for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
05059                 bKinematicConstraint *data= has_targetless_ik(pchan);
05060                 if(data) data->flag &= ~CONSTRAINT_IK_AUTO;
05061             }
05062         }
05063 
05064         if (t->mode==TFM_TRANSLATION)
05065             pose_grab_with_ik_clear(ob);
05066 
05067         /* automatic inserting of keys and unkeyed tagging - only if transform wasn't cancelled (or TFM_DUMMY) */
05068         if (!cancelled && (t->mode != TFM_DUMMY)) {
05069             autokeyframe_pose_cb_func(C, t->scene, (View3D *)t->view, ob, t->mode, targetless_ik);
05070             DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
05071         }
05072         else if (arm->flag & ARM_DELAYDEFORM) {
05073             /* old optimize trick... this enforces to bypass the depgraph */
05074             DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
05075             ob->recalc= 0;  // is set on OK position already by recalcData()
05076         }
05077         else
05078             DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
05079 
05080     }
05081     else if ( (t->scene->basact) &&
05082               (ob = t->scene->basact->object) &&
05083               (ob->mode & OB_MODE_PARTICLE_EDIT) &&
05084               PE_get_current(t->scene, ob))
05085     {
05086         /* do nothing */ ;
05087     }
05088     else { /* Objects */
05089         int i, recalcObPaths=0;
05090 
05091         for (i = 0; i < t->total; i++) {
05092             TransData *td = t->data + i;
05093             ListBase pidlist;
05094             PTCacheID *pid;
05095             ob = td->ob;
05096 
05097             if (td->flag & TD_NOACTION)
05098                 break;
05099             
05100             if (td->flag & TD_SKIP)
05101                 continue;
05102 
05103             /* flag object caches as outdated */
05104             BKE_ptcache_ids_from_object(&pidlist, ob, t->scene, MAX_DUPLI_RECUR);
05105             for(pid=pidlist.first; pid; pid=pid->next) {
05106                 if(pid->type != PTCACHE_TYPE_PARTICLES) /* particles don't need reset on geometry change */
05107                     pid->cache->flag |= PTCACHE_OUTDATED;
05108             }
05109             BLI_freelistN(&pidlist);
05110 
05111             /* pointcache refresh */
05112             if (BKE_ptcache_object_reset(t->scene, ob, PTCACHE_RESET_OUTDATED))
05113                 ob->recalc |= OB_RECALC_DATA;
05114 
05115             /* Needed for proper updating of "quick cached" dynamics. */
05116             /* Creates troubles for moving animated objects without */
05117             /* autokey though, probably needed is an anim sys override? */
05118             /* Please remove if some other solution is found. -jahka */
05119             DAG_id_tag_update(&ob->id, OB_RECALC_OB);
05120 
05121             /* Set autokey if necessary */
05122             if (!cancelled) {
05123                 autokeyframe_ob_cb_func(C, t->scene, (View3D *)t->view, ob, t->mode);
05124                 
05125                 /* only calculate paths if there are paths to be recalculated */
05126                 if (ob->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)
05127                     recalcObPaths= 1;
05128             }
05129         }
05130         
05131         /* recalculate motion paths for objects (if necessary) 
05132          * NOTE: only do this when there is context info
05133          */
05134         if (C && recalcObPaths) {
05135             //ED_objects_clear_paths(C); // XXX for now, don't need to clear
05136             ED_objects_recalculate_paths(C, t->scene);
05137 
05138             /* recalculating the frame positions means we loose our original transform if its not auto-keyed [#24451]
05139              * this hack re-applies it, which is annoying, only alternatives are...
05140              * - dont recalc paths.
05141              * - have an object_handle_update() which gives is the new transform without touching the objects.
05142              * - only recalc paths on auto-keying.
05143              * - ED_objects_recalculate_paths could backup/restore transforms.
05144              * - re-apply the transform which is simplest in this case. (2 lines below)
05145              */
05146             t->redraw |= TREDRAW_HARD;
05147             transformApply(C, t);
05148         }
05149     }
05150 
05151     clear_trans_object_base_flags(t);
05152 
05153 
05154 #if 0 // TRANSFORM_FIX_ME
05155     if(resetslowpar)
05156         reset_slowparents();
05157 #endif
05158 }
05159 
05160 static void createTransObject(bContext *C, TransInfo *t)
05161 {
05162     TransData *td = NULL;
05163     TransDataExtension *tx;
05164     int propmode = t->flag & T_PROP_EDIT;
05165 
05166     set_trans_object_base_flags(t);
05167 
05168     /* count */
05169     t->total= CTX_DATA_COUNT(C, selected_objects);
05170     
05171     if(!t->total) {
05172         /* clear here, main transform function escapes too */
05173         clear_trans_object_base_flags(t);
05174         return;
05175     }
05176     
05177     if (propmode)
05178     {
05179         t->total += count_proportional_objects(t);
05180     }
05181 
05182     td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransOb");
05183     tx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "TransObExtension");
05184 
05185     CTX_DATA_BEGIN(C, Base*, base, selected_bases)
05186     {
05187         Object *ob= base->object;
05188         
05189         td->flag = TD_SELECTED;
05190         td->protectflag= ob->protectflag;
05191         td->ext = tx;
05192         td->ext->rotOrder= ob->rotmode;
05193         
05194         if (base->flag & BA_TRANSFORM_CHILD)
05195         {
05196             td->flag |= TD_NOCENTER;
05197             td->flag |= TD_NO_LOC;
05198         }
05199         
05200         /* select linked objects, but skip them later */
05201         if (ob->id.lib != NULL) {
05202             td->flag |= TD_SKIP;
05203         }
05204         
05205         ObjectToTransData(t, td, ob);
05206         td->val = NULL;
05207         td++;
05208         tx++;
05209     }
05210     CTX_DATA_END;
05211     
05212     if (propmode)
05213     {
05214         Scene *scene = t->scene;
05215         View3D *v3d = t->view;
05216         Base *base;
05217 
05218         for (base= scene->base.first; base; base= base->next) {
05219             Object *ob= base->object;
05220 
05221             /* if base is not selected, not a parent of selection or not a child of selection and it is editable */
05222             if ((ob->flag & (SELECT|BA_TRANSFORM_CHILD|BA_TRANSFORM_PARENT)) == 0 && BASE_EDITABLE_BGMODE(v3d, scene, base))
05223             {
05224                 td->protectflag= ob->protectflag;
05225                 td->ext = tx;
05226                 td->ext->rotOrder= ob->rotmode;
05227                 
05228                 ObjectToTransData(t, td, ob);
05229                 td->val = NULL;
05230                 td++;
05231                 tx++;
05232             }
05233         }
05234     }
05235 }
05236 
05237 /* transcribe given node into TransData2D for Transforming */
05238 static void NodeToTransData(TransData *td, TransData2D *td2d, bNode *node)
05239 // static void NodeToTransData(bContext *C, TransInfo *t, TransData2D *td, bNode *node)
05240 {
05241     td2d->loc[0] = node->locx; /* hold original location */
05242     td2d->loc[1] = node->locy;
05243     td2d->loc[2] = 0.0f;
05244     td2d->loc2d = &node->locx; /* current location */
05245 
05246     td->flag = 0;
05247     /* exclude nodes whose parent is also transformed */
05248     if (node->parent && (node->parent->flag & NODE_TRANSFORM)) {
05249         td->flag |= TD_SKIP;
05250     }
05251 
05252     td->loc = td2d->loc;
05253     copy_v3_v3(td->center, td->loc);
05254     copy_v3_v3(td->iloc, td->loc);
05255 
05256     memset(td->axismtx, 0, sizeof(td->axismtx));
05257     td->axismtx[2][2] = 1.0f;
05258 
05259     td->ext= NULL; td->val= NULL;
05260 
05261     td->flag |= TD_SELECTED;
05262     td->dist= 0.0;
05263 
05264     unit_m3(td->mtx);
05265     unit_m3(td->smtx);
05266 }
05267 
05268 static void createTransNodeData(bContext *C, TransInfo *t)
05269 {
05270     TransData *td;
05271     TransData2D *td2d;
05272     SpaceNode *snode= t->sa->spacedata.first;
05273     bNode *node;
05274 
05275     if(!snode->edittree) {
05276         t->total= 0;
05277         return;
05278     }
05279 
05280     /* set transform flags on nodes */
05281     for (node=snode->edittree->nodes.first; node; node=node->next) {
05282         if ((node->flag & NODE_SELECT) || (node->parent && (node->parent->flag & NODE_TRANSFORM)))
05283             node->flag |= NODE_TRANSFORM;
05284         else
05285             node->flag &= ~NODE_TRANSFORM;
05286     }
05287 
05288     t->total= CTX_DATA_COUNT(C, selected_nodes);
05289 
05290     td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransNode TransData");
05291     td2d = t->data2d = MEM_callocN(t->total*sizeof(TransData2D), "TransNode TransData2D");
05292 
05293     CTX_DATA_BEGIN(C, bNode *, selnode, selected_nodes)
05294         NodeToTransData(td++, td2d++, selnode);
05295     CTX_DATA_END
05296 }
05297 
05298 /* *** CLIP EDITOR *** */
05299 
05300 typedef struct TransDataTracking {
05301     int area;
05302     float *relative, *loc;
05303     float soffset[2], srelative[2];
05304     float offset[2];
05305 
05306     float (*smarkers)[2];
05307     int markersnr;
05308     MovieTrackingMarker *markers;
05309 } TransDataTracking;
05310 
05311 static void markerToTransDataInit(TransData *td, TransData2D *td2d,
05312             TransDataTracking *tdt, MovieTrackingTrack *track, int area, float *loc, float *rel, float *off)
05313 {
05314     int anchor = area==TRACK_AREA_POINT && off;
05315 
05316     if(anchor) {
05317         td2d->loc[0] = rel[0]; /* hold original location */
05318         td2d->loc[1] = rel[1];
05319 
05320         tdt->loc= loc;
05321         td2d->loc2d = loc; /* current location */
05322     } else {
05323         td2d->loc[0] = loc[0]; /* hold original location */
05324         td2d->loc[1] = loc[1];
05325 
05326         td2d->loc2d = loc; /* current location */
05327     }
05328     td2d->loc[2] = 0.0f;
05329 
05330     tdt->relative= rel;
05331     tdt->area= area;
05332 
05333     tdt->markersnr= track->markersnr;
05334     tdt->markers= track->markers;
05335 
05336     if(rel) {
05337         if(!anchor) {
05338             td2d->loc[0]+= rel[0];
05339             td2d->loc[1]+= rel[1];
05340         }
05341 
05342         copy_v2_v2(tdt->srelative, rel);
05343     }
05344 
05345     if(off)
05346         copy_v2_v2(tdt->soffset, off);
05347 
05348     td->flag = 0;
05349     td->loc = td2d->loc;
05350     VECCOPY(td->center, td->loc);
05351     VECCOPY(td->iloc, td->loc);
05352 
05353     memset(td->axismtx, 0, sizeof(td->axismtx));
05354     td->axismtx[2][2] = 1.0f;
05355 
05356     td->ext= NULL; td->val= NULL;
05357 
05358     td->flag |= TD_SELECTED;
05359     td->dist= 0.0;
05360 
05361     unit_m3(td->mtx);
05362     unit_m3(td->smtx);
05363 }
05364 
05365 static void trackToTransData(SpaceClip *sc, TransData *td, TransData2D *td2d,
05366             TransDataTracking *tdt, MovieTrackingTrack *track)
05367 {
05368     MovieTrackingMarker *marker= BKE_tracking_ensure_marker(track, sc->user.framenr);
05369 
05370     track->transflag= marker->flag;
05371 
05372     marker->flag&= ~(MARKER_DISABLED|MARKER_TRACKED);
05373 
05374     markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_POINT, track->offset, marker->pos, track->offset);
05375 
05376     if(track->flag&SELECT)
05377         markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_POINT, marker->pos, NULL, NULL);
05378 
05379     if(track->pat_flag&SELECT) {
05380         markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_PAT, track->pat_min, marker->pos, NULL);
05381         markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_PAT, track->pat_max, marker->pos, NULL);
05382     }
05383 
05384     if(track->search_flag&SELECT) {
05385         markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_SEARCH, track->search_min, marker->pos, NULL);
05386         markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_SEARCH, track->search_max, marker->pos, NULL);
05387     }
05388 }
05389 
05390 static void transDataTrackingFree(TransInfo *t)
05391 {
05392     TransDataTracking *tdt= t->customData;
05393 
05394     if(tdt) {
05395         if(tdt->smarkers) MEM_freeN(tdt->smarkers);
05396         MEM_freeN(tdt);
05397     }
05398 }
05399 
05400 static void createTransTrackingData(bContext *C, TransInfo *t)
05401 {
05402     TransData *td;
05403     TransData2D *td2d;
05404     SpaceClip *sc = CTX_wm_space_clip(C);
05405     MovieClip *clip = ED_space_clip(sc);
05406     ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
05407     MovieTrackingTrack *track;
05408     MovieTrackingMarker *marker;
05409     TransDataTracking *tdt;
05410     int framenr = sc->user.framenr;
05411 
05412     if(!clip || !BKE_movieclip_has_frame(clip, &sc->user)) {
05413         t->total = 0;
05414         return;
05415     }
05416 
05417     /* count */
05418     t->total = 0;
05419 
05420     track = tracksbase->first;
05421     while(track) {
05422         if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
05423             marker= BKE_tracking_get_marker(track, framenr);
05424 
05425             if(marker) {
05426                 t->total++; /* offset */
05427 
05428                 if(track->flag&SELECT) t->total++;
05429                 if(track->pat_flag&SELECT) t->total+= 2;
05430                 if(track->search_flag&SELECT) t->total+= 2;
05431             }
05432         }
05433 
05434         track = track->next;
05435     }
05436 
05437     if(t->total==0)
05438         return;
05439 
05440     td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransTracking TransData");
05441     td2d = t->data2d = MEM_callocN(t->total*sizeof(TransData2D), "TransTracking TransData2D");
05442     tdt = t->customData = MEM_callocN(t->total*sizeof(TransDataTracking), "TransTracking TransDataTracking");
05443 
05444     t->customFree= transDataTrackingFree;
05445 
05446     /* create actual data */
05447     track = tracksbase->first;
05448     while(track) {
05449         if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
05450             marker= BKE_tracking_get_marker(track, framenr);
05451 
05452             trackToTransData(sc, td, td2d, tdt, track);
05453 
05454             /* offset */
05455             td++;
05456             td2d++;
05457             tdt++;
05458 
05459             if((marker->flag&MARKER_DISABLED)==0) {
05460                 if(track->flag&SELECT) {td++; td2d++; tdt++;}
05461                 if(track->pat_flag&SELECT) {td+= 2; td2d+= 2;tdt+=2;}
05462             }
05463 
05464             if(track->search_flag&SELECT) {
05465                 td+= 2;
05466                 td2d+= 2;
05467                 tdt+= 2;
05468 
05469                 if(marker->flag&MARKER_DISABLED) {
05470                     td+= 3;
05471                     td2d+= 3;
05472                     tdt+= 3;
05473                 };
05474             }
05475         }
05476 
05477         track = track->next;
05478     }
05479 }
05480 
05481 void flushTransTracking(TransInfo *t)
05482 {
05483     TransData *td;
05484     TransData2D *td2d;
05485     TransDataTracking *tdt;
05486     int a;
05487 
05488     /* flush to 2d vector from internally used 3d vector */
05489     for(a=0, td= t->data, td2d= t->data2d, tdt= t->customData; a<t->total; a++, td2d++, td++, tdt++) {
05490         if(t->flag&T_ALT_TRANSFORM) {
05491             if(tdt->area==TRACK_AREA_POINT && tdt->relative) {
05492                 float d[2], d2[2];
05493 
05494                 if(!tdt->smarkers) {
05495                     tdt->smarkers= MEM_callocN(sizeof(*tdt->smarkers)*tdt->markersnr, "flushTransTracking markers");
05496                     for(a= 0; a<tdt->markersnr; a++)
05497                         copy_v2_v2(tdt->smarkers[a], tdt->markers[a].pos);
05498                 }
05499 
05500                 sub_v2_v2v2(d, td2d->loc, tdt->soffset);
05501                 sub_v2_v2(d, tdt->srelative);
05502 
05503                 sub_v2_v2v2(d2, td2d->loc, tdt->srelative);
05504 
05505                 for(a= 0; a<tdt->markersnr; a++)
05506                     add_v2_v2v2(tdt->markers[a].pos, tdt->smarkers[a], d2);
05507 
05508                 negate_v2_v2(td2d->loc2d, d);
05509             }
05510         }
05511 
05512         if(tdt->area!=TRACK_AREA_POINT || tdt->relative==0) {
05513             td2d->loc2d[0] = td2d->loc[0];
05514             td2d->loc2d[1] = td2d->loc[1];
05515 
05516             if(tdt->relative)
05517                 sub_v2_v2(td2d->loc2d, tdt->relative);
05518         }
05519     }
05520 }
05521 
05522 void createTransData(bContext *C, TransInfo *t)
05523 {
05524     Scene *scene = t->scene;
05525     Object *ob = OBACT;
05526 
05527     if (t->options & CTX_TEXTURE) {
05528         t->flag |= T_TEXTURE;
05529         createTransTexspace(t);
05530     }
05531     else if (t->options & CTX_EDGE) {
05532         t->ext = NULL;
05533         t->flag |= T_EDIT;
05534         createTransEdge(t);
05535         if(t->data && t->flag & T_PROP_EDIT) {
05536             sort_trans_data(t); // makes selected become first in array
05537             set_prop_dist(t, 1);
05538             sort_trans_data_dist(t);
05539         }
05540     }
05541     else if (t->options == CTX_BMESH) {
05542         // TRANSFORM_FIX_ME
05543         //createTransBMeshVerts(t, G.editBMesh->bm, G.editBMesh->td);
05544     }
05545     else if (t->spacetype == SPACE_IMAGE) {
05546         t->flag |= T_POINTS|T_2D_EDIT;
05547         createTransUVs(C, t);
05548         if(t->data && (t->flag & T_PROP_EDIT)) {
05549             sort_trans_data(t); // makes selected become first in array
05550             set_prop_dist(t, 1);
05551             sort_trans_data_dist(t);
05552         }
05553     }
05554     else if (t->spacetype == SPACE_ACTION) {
05555         t->flag |= T_POINTS|T_2D_EDIT;
05556         createTransActionData(C, t);
05557     }
05558     else if (t->spacetype == SPACE_NLA) {
05559         t->flag |= T_POINTS|T_2D_EDIT;
05560         createTransNlaData(C, t);
05561     }
05562     else if (t->spacetype == SPACE_SEQ) {
05563         t->flag |= T_POINTS|T_2D_EDIT;
05564         t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point transformations */
05565         createTransSeqData(C, t);
05566     }
05567     else if (t->spacetype == SPACE_IPO) {
05568         t->flag |= T_POINTS|T_2D_EDIT;
05569         createTransGraphEditData(C, t);
05570 #if 0
05571         if (t->data && (t->flag & T_PROP_EDIT)) {
05572             sort_trans_data(t); // makes selected become first in array
05573             set_prop_dist(t, 1);
05574             sort_trans_data_dist(t);
05575         }
05576 #endif
05577     }
05578     else if(t->spacetype == SPACE_NODE) {
05579         t->flag |= T_2D_EDIT|T_POINTS;
05580         createTransNodeData(C, t);
05581         if (t->data && (t->flag & T_PROP_EDIT)) {
05582             sort_trans_data(t); // makes selected become first in array
05583             set_prop_dist(t, 1);
05584             sort_trans_data_dist(t);
05585         }
05586     }
05587     else if (t->spacetype == SPACE_CLIP) {
05588         t->flag |= T_POINTS|T_2D_EDIT;
05589         createTransTrackingData(C, t);
05590     }
05591     else if (t->obedit) {
05592         t->ext = NULL;
05593         if (t->obedit->type == OB_MESH) {
05594             createTransEditVerts(C, t);
05595         }
05596         else if ELEM(t->obedit->type, OB_CURVE, OB_SURF) {
05597             createTransCurveVerts(C, t);
05598         }
05599         else if (t->obedit->type==OB_LATTICE) {
05600             createTransLatticeVerts(t);
05601         }
05602         else if (t->obedit->type==OB_MBALL) {
05603             createTransMBallVerts(t);
05604         }
05605         else if (t->obedit->type==OB_ARMATURE) {
05606             t->flag &= ~T_PROP_EDIT;
05607             createTransArmatureVerts(t);
05608         }
05609         else {
05610             printf("edit type not implemented!\n");
05611         }
05612 
05613         t->flag |= T_EDIT|T_POINTS;
05614 
05615         if(t->data && t->flag & T_PROP_EDIT) {
05616             if (ELEM(t->obedit->type, OB_CURVE, OB_MESH)) {
05617                 sort_trans_data(t); // makes selected become first in array
05618                 set_prop_dist(t, 0);
05619                 sort_trans_data_dist(t);
05620             }
05621             else {
05622                 sort_trans_data(t); // makes selected become first in array
05623                 set_prop_dist(t, 1);
05624                 sort_trans_data_dist(t);
05625             }
05626         }
05627 
05628         /* exception... hackish, we want bonesize to use bone orientation matrix (ton) */
05629         if(t->mode==TFM_BONESIZE) {
05630             t->flag &= ~(T_EDIT|T_POINTS);
05631             t->flag |= T_POSE;
05632             t->poseobj = ob;    /* <- tsk tsk, this is going to give issues one day */
05633         }
05634     }
05635     else if (ob && (ob->mode & OB_MODE_POSE)) {
05636         // XXX this is currently limited to active armature only...
05637         // XXX active-layer checking isn't done as that should probably be checked through context instead
05638         createTransPose(t, ob);
05639     }
05640     else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT)) {
05641         /* important that ob_armature can be set even when its not selected [#23412]
05642          * lines below just check is also visible */
05643         Object *ob_armature= modifiers_isDeformedByArmature(ob);
05644         if(ob_armature && ob_armature->mode & OB_MODE_POSE) {
05645             Base *base_arm= object_in_scene(ob_armature, t->scene);
05646             if(base_arm) {
05647                 View3D *v3d = t->view;
05648                 if(BASE_VISIBLE(v3d, base_arm)) {
05649                     createTransPose(t, ob_armature);
05650                 }
05651             }
05652             
05653         }
05654     }
05655     else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) 
05656         && PE_start_edit(PE_get_current(scene, ob))) {
05657         createTransParticleVerts(C, t);
05658         t->flag |= T_POINTS;
05659 
05660         if(t->data && t->flag & T_PROP_EDIT) {
05661             sort_trans_data(t); // makes selected become first in array
05662             set_prop_dist(t, 1);
05663             sort_trans_data_dist(t);
05664         }
05665     }
05666     else if (ob && (ob->mode & (OB_MODE_SCULPT|OB_MODE_TEXTURE_PAINT))) {
05667         /* sculpt mode and project paint have own undo stack
05668          * transform ops redo clears sculpt/project undo stack.
05669          *
05670          * Could use 'OB_MODE_ALL_PAINT' since there are key conflicts,
05671          * transform + paint isnt well supported. */
05672     }
05673     else {
05674         createTransObject(C, t);
05675         t->flag |= T_OBJECT;
05676 
05677         if(t->data && t->flag & T_PROP_EDIT) {
05678             // selected objects are already first, no need to presort
05679             set_prop_dist(t, 1);
05680             sort_trans_data_dist(t);
05681         }
05682 
05683         if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW))
05684         {
05685             View3D *v3d = t->view;
05686             RegionView3D *rv3d = CTX_wm_region_view3d(C);
05687             if(rv3d && (t->flag & T_OBJECT) && v3d->camera == OBACT && rv3d->persp==RV3D_CAMOB)
05688             {
05689                 t->flag |= T_CAMERA;
05690             }
05691         }
05692     }
05693 
05694 // TRANSFORM_FIX_ME
05695 //  /* temporal...? */
05696 //  t->scene->recalc |= SCE_PRV_CHANGED;    /* test for 3d preview */
05697 }
05698 
05699 
05700 
05701