|
Blender
V2.59
|
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