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