Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2008 Blender Foundation 00019 * All rights reserved. 00020 * 00021 * Contributor(s): Joshua Leung 00022 * 00023 * ***** END GPL LICENSE BLOCK ***** 00024 */ 00025 00031 #include <stdlib.h> 00032 #include <string.h> 00033 #include <math.h> 00034 #include <float.h> 00035 00036 #include "MEM_guardedalloc.h" 00037 00038 #include "BLI_blenlib.h" 00039 #include "BLI_math.h" 00040 #include "BLI_utildefines.h" 00041 00042 #include "DNA_anim_types.h" 00043 #include "DNA_object_types.h" 00044 #include "DNA_scene_types.h" 00045 00046 00047 #include "BKE_fcurve.h" 00048 #include "BKE_utildefines.h" 00049 #include "BKE_report.h" 00050 #include "BKE_library.h" 00051 #include "BKE_global.h" 00052 00053 #include "RNA_access.h" 00054 #include "RNA_enum_types.h" 00055 00056 #include "ED_anim_api.h" 00057 #include "ED_keyframing.h" 00058 #include "ED_keyframes_edit.h" 00059 00060 /* This file contains code for various keyframe-editing tools which are 'destructive' 00061 * (i.e. they will modify the order of the keyframes, and change the size of the array). 00062 * While some of these tools may eventually be moved out into blenkernel, for now, it is 00063 * fine to have these calls here. 00064 * 00065 * There are also a few tools here which cannot be easily coded for in the other system (yet). 00066 * These may also be moved around at some point, but for now, they are best added here. 00067 * 00068 * - Joshua Leung, Dec 2008 00069 */ 00070 00071 /* **************************************************** */ 00072 00073 /* Only delete the nominated keyframe from provided F-Curve. 00074 * Not recommended to be used many times successively. For that 00075 * there is delete_fcurve_keys(). 00076 */ 00077 void delete_fcurve_key(FCurve *fcu, int index, short do_recalc) 00078 { 00079 /* sanity check */ 00080 if (fcu == NULL) 00081 return; 00082 00083 /* verify the index: 00084 * 1) cannot be greater than the number of available keyframes 00085 * 2) negative indices are for specifying a value from the end of the array 00086 */ 00087 if (abs(index) >= fcu->totvert) 00088 return; 00089 else if (index < 0) 00090 index += fcu->totvert; 00091 00092 /* Delete this keyframe */ 00093 memmove(&fcu->bezt[index], &fcu->bezt[index+1], sizeof(BezTriple)*(fcu->totvert-index-1)); 00094 fcu->totvert--; 00095 00096 if (fcu->totvert == 0) { 00097 if (fcu->bezt) 00098 MEM_freeN(fcu->bezt); 00099 fcu->bezt= NULL; 00100 } 00101 00102 /* recalc handles - only if it won't cause problems */ 00103 if (do_recalc) 00104 calchandles_fcurve(fcu); 00105 } 00106 00107 /* Delete selected keyframes in given F-Curve */ 00108 void delete_fcurve_keys(FCurve *fcu) 00109 { 00110 int i; 00111 00112 if (fcu->bezt==NULL) /* ignore baked curves */ 00113 return; 00114 00115 /* Delete selected BezTriples */ 00116 for (i=0; i < fcu->totvert; i++) { 00117 if (fcu->bezt[i].f2 & SELECT) { 00118 memmove(&fcu->bezt[i], &fcu->bezt[i+1], sizeof(BezTriple)*(fcu->totvert-i-1)); 00119 fcu->totvert--; 00120 i--; 00121 } 00122 } 00123 00124 /* Free the array of BezTriples if there are not keyframes */ 00125 if (fcu->totvert == 0) 00126 clear_fcurve_keys(fcu); 00127 } 00128 00129 00130 void clear_fcurve_keys(FCurve *fcu) 00131 { 00132 if (fcu->bezt) 00133 MEM_freeN(fcu->bezt); 00134 fcu->bezt= NULL; 00135 00136 fcu->totvert= 0; 00137 } 00138 00139 /* ---------------- */ 00140 00141 /* duplicate selected keyframes for the given F-Curve */ 00142 void duplicate_fcurve_keys(FCurve *fcu) 00143 { 00144 BezTriple *newbezt; 00145 int i; 00146 00147 /* this can only work when there is an F-Curve, and also when there are some BezTriples */ 00148 if ELEM(NULL, fcu, fcu->bezt) 00149 return; 00150 00151 for (i=0; i < fcu->totvert; i++) { 00152 /* If a key is selected */ 00153 if (fcu->bezt[i].f2 & SELECT) { 00154 /* Expand the list */ 00155 newbezt = MEM_callocN(sizeof(BezTriple) * (fcu->totvert+1), "beztriple"); 00156 00157 memcpy(newbezt, fcu->bezt, sizeof(BezTriple) * (i+1)); 00158 memcpy(newbezt+i+1, fcu->bezt+i, sizeof(BezTriple)); 00159 memcpy(newbezt+i+2, fcu->bezt+i+1, sizeof (BezTriple) *(fcu->totvert-(i+1))); 00160 fcu->totvert++; 00161 00162 /* reassign pointers... (free old, and add new) */ 00163 MEM_freeN(fcu->bezt); 00164 fcu->bezt=newbezt; 00165 00166 /* Unselect the current key */ 00167 BEZ_DESEL(&fcu->bezt[i]); 00168 i++; 00169 00170 /* Select the copied key */ 00171 BEZ_SEL(&fcu->bezt[i]); 00172 } 00173 } 00174 } 00175 00176 /* **************************************************** */ 00177 /* Various Tools */ 00178 00179 /* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only */ 00180 void clean_fcurve(FCurve *fcu, float thresh) 00181 { 00182 BezTriple *old_bezts, *bezt, *beztn; 00183 BezTriple *lastb; 00184 int totCount, i; 00185 00186 /* check if any points */ 00187 if ((fcu == NULL) || (fcu->totvert <= 1)) 00188 return; 00189 00190 /* make a copy of the old BezTriples, and clear IPO curve */ 00191 old_bezts = fcu->bezt; 00192 totCount = fcu->totvert; 00193 fcu->bezt = NULL; 00194 fcu->totvert = 0; 00195 00196 /* now insert first keyframe, as it should be ok */ 00197 bezt = old_bezts; 00198 insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], 0); 00199 00200 /* Loop through BezTriples, comparing them. Skip any that do 00201 * not fit the criteria for "ok" points. 00202 */ 00203 for (i=1; i<totCount; i++) { 00204 float prev[2], cur[2], next[2]; 00205 00206 /* get BezTriples and their values */ 00207 if (i < (totCount - 1)) { 00208 beztn = (old_bezts + (i+1)); 00209 next[0]= beztn->vec[1][0]; next[1]= beztn->vec[1][1]; 00210 } 00211 else { 00212 beztn = NULL; 00213 next[0] = next[1] = 0.0f; 00214 } 00215 lastb= (fcu->bezt + (fcu->totvert - 1)); 00216 bezt= (old_bezts + i); 00217 00218 /* get references for quicker access */ 00219 prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1]; 00220 cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1]; 00221 00222 /* check if current bezt occurs at same time as last ok */ 00223 if (IS_EQT(cur[0], prev[0], thresh)) { 00224 /* If there is a next beztriple, and if occurs at the same time, only insert 00225 * if there is a considerable distance between the points, and also if the 00226 * current is further away than the next one is to the previous. 00227 */ 00228 if (beztn && (IS_EQT(cur[0], next[0], thresh)) && 00229 (IS_EQT(next[1], prev[1], thresh)==0)) 00230 { 00231 /* only add if current is further away from previous */ 00232 if (cur[1] > next[1]) { 00233 if (IS_EQT(cur[1], prev[1], thresh) == 0) { 00234 /* add new keyframe */ 00235 insert_vert_fcurve(fcu, cur[0], cur[1], 0); 00236 } 00237 } 00238 } 00239 else { 00240 /* only add if values are a considerable distance apart */ 00241 if (IS_EQT(cur[1], prev[1], thresh) == 0) { 00242 /* add new keyframe */ 00243 insert_vert_fcurve(fcu, cur[0], cur[1], 0); 00244 } 00245 } 00246 } 00247 else { 00248 /* checks required are dependent on whether this is last keyframe or not */ 00249 if (beztn) { 00250 /* does current have same value as previous and next? */ 00251 if (IS_EQT(cur[1], prev[1], thresh) == 0) { 00252 /* add new keyframe*/ 00253 insert_vert_fcurve(fcu, cur[0], cur[1], 0); 00254 } 00255 else if (IS_EQT(cur[1], next[1], thresh) == 0) { 00256 /* add new keyframe */ 00257 insert_vert_fcurve(fcu, cur[0], cur[1], 0); 00258 } 00259 } 00260 else { 00261 /* add if value doesn't equal that of previous */ 00262 if (IS_EQT(cur[1], prev[1], thresh) == 0) { 00263 /* add new keyframe */ 00264 insert_vert_fcurve(fcu, cur[0], cur[1], 0); 00265 } 00266 } 00267 } 00268 } 00269 00270 /* now free the memory used by the old BezTriples */ 00271 if (old_bezts) 00272 MEM_freeN(old_bezts); 00273 } 00274 00275 /* ---------------- */ 00276 00277 /* temp struct used for smooth_fcurve */ 00278 typedef struct tSmooth_Bezt { 00279 float *h1, *h2, *h3; /* bezt->vec[0,1,2][1] */ 00280 float y1, y2, y3; /* averaged before/new/after y-values */ 00281 } tSmooth_Bezt; 00282 00283 /* Use a weighted moving-means method to reduce intensity of fluctuations */ 00284 // TODO: introduce scaling factor for weighting falloff 00285 void smooth_fcurve (FCurve *fcu) 00286 { 00287 BezTriple *bezt; 00288 int i, x, totSel = 0; 00289 00290 /* first loop through - count how many verts are selected */ 00291 bezt= fcu->bezt; 00292 for (i=0; i < fcu->totvert; i++, bezt++) { 00293 if (BEZSELECTED(bezt)) 00294 totSel++; 00295 } 00296 00297 /* if any points were selected, allocate tSmooth_Bezt points to work on */ 00298 if (totSel >= 3) { 00299 tSmooth_Bezt *tarray, *tsb; 00300 00301 /* allocate memory in one go */ 00302 tsb= tarray= MEM_callocN(totSel*sizeof(tSmooth_Bezt), "tSmooth_Bezt Array"); 00303 00304 /* populate tarray with data of selected points */ 00305 bezt= fcu->bezt; 00306 for (i=0, x=0; (i < fcu->totvert) && (x < totSel); i++, bezt++) { 00307 if (BEZSELECTED(bezt)) { 00308 /* tsb simply needs pointer to vec, and index */ 00309 tsb->h1 = &bezt->vec[0][1]; 00310 tsb->h2 = &bezt->vec[1][1]; 00311 tsb->h3 = &bezt->vec[2][1]; 00312 00313 /* advance to the next tsb to populate */ 00314 if (x < totSel-1) 00315 tsb++; 00316 else 00317 break; 00318 } 00319 } 00320 00321 /* calculate the new smoothed F-Curve's with weighted averages: 00322 * - this is done with two passes to avoid progressive corruption errors 00323 * - uses 5 points for each operation (which stores in the relevant handles) 00324 * - previous: w/a ratio = 3:5:2:1:1 00325 * - next: w/a ratio = 1:1:2:5:3 00326 */ 00327 00328 /* round 1: calculate smoothing deltas and new values */ 00329 tsb= tarray; 00330 for (i=0; i < totSel; i++, tsb++) { 00331 /* don't touch end points (otherwise, curves slowly explode, as we don't have enough data there) */ 00332 if (ELEM(i, 0, (totSel-1)) == 0) { 00333 const tSmooth_Bezt *tP1 = tsb - 1; 00334 const tSmooth_Bezt *tP2 = (i-2 > 0) ? (tsb - 2) : (NULL); 00335 const tSmooth_Bezt *tN1 = tsb + 1; 00336 const tSmooth_Bezt *tN2 = (i+2 < totSel) ? (tsb + 2) : (NULL); 00337 00338 const float p1 = *tP1->h2; 00339 const float p2 = (tP2) ? (*tP2->h2) : (*tP1->h2); 00340 const float c1 = *tsb->h2; 00341 const float n1 = *tN1->h2; 00342 const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2); 00343 00344 /* calculate previous and next, then new position by averaging these */ 00345 tsb->y1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12; 00346 tsb->y3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12; 00347 00348 tsb->y2 = (tsb->y1 + tsb->y3) / 2; 00349 } 00350 } 00351 00352 /* round 2: apply new values */ 00353 tsb= tarray; 00354 for (i=0; i < totSel; i++, tsb++) { 00355 /* don't touch end points, as their values were't touched above */ 00356 if (ELEM(i, 0, (totSel-1)) == 0) { 00357 /* y2 takes the average of the 2 points */ 00358 *tsb->h2 = tsb->y2; 00359 00360 /* handles are weighted between their original values and the averaged values */ 00361 *tsb->h1 = ((*tsb->h1) * 0.7f) + (tsb->y1 * 0.3f); 00362 *tsb->h3 = ((*tsb->h3) * 0.7f) + (tsb->y3 * 0.3f); 00363 } 00364 } 00365 00366 /* free memory required for tarray */ 00367 MEM_freeN(tarray); 00368 } 00369 00370 /* recalculate handles */ 00371 calchandles_fcurve(fcu); 00372 } 00373 00374 /* ---------------- */ 00375 00376 /* little cache for values... */ 00377 typedef struct tempFrameValCache { 00378 float frame, val; 00379 } tempFrameValCache; 00380 00381 00382 /* Evaluates the curves between each selected keyframe on each frame, and keys the value */ 00383 void sample_fcurve (FCurve *fcu) 00384 { 00385 BezTriple *bezt, *start=NULL, *end=NULL; 00386 tempFrameValCache *value_cache, *fp; 00387 int sfra, range; 00388 int i, n, nIndex; 00389 00390 if (fcu->bezt==NULL) /* ignore baked */ 00391 return; 00392 00393 /* find selected keyframes... once pair has been found, add keyframes */ 00394 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) { 00395 /* check if selected, and which end this is */ 00396 if (BEZSELECTED(bezt)) { 00397 if (start) { 00398 /* set end */ 00399 end= bezt; 00400 00401 /* cache values then add keyframes using these values, as adding 00402 * keyframes while sampling will affect the outcome... 00403 * - only start sampling+adding from index=1, so that we don't overwrite original keyframe 00404 */ 00405 range= (int)( ceil(end->vec[1][0] - start->vec[1][0]) ); 00406 sfra= (int)( floor(start->vec[1][0]) ); 00407 00408 if (range) { 00409 value_cache= MEM_callocN(sizeof(tempFrameValCache)*range, "IcuFrameValCache"); 00410 00411 /* sample values */ 00412 for (n=1, fp=value_cache; n<range && fp; n++, fp++) { 00413 fp->frame= (float)(sfra + n); 00414 fp->val= evaluate_fcurve(fcu, fp->frame); 00415 } 00416 00417 /* add keyframes with these, tagging as 'breakdowns' */ 00418 for (n=1, fp=value_cache; n<range && fp; n++, fp++) { 00419 nIndex= insert_vert_fcurve(fcu, fp->frame, fp->val, 1); 00420 BEZKEYTYPE(fcu->bezt + nIndex)= BEZT_KEYTYPE_BREAKDOWN; 00421 } 00422 00423 /* free temp cache */ 00424 MEM_freeN(value_cache); 00425 00426 /* as we added keyframes, we need to compensate so that bezt is at the right place */ 00427 bezt = fcu->bezt + i + range - 1; 00428 i += (range - 1); 00429 } 00430 00431 /* bezt was selected, so it now marks the start of a whole new chain to search */ 00432 start= bezt; 00433 end= NULL; 00434 } 00435 else { 00436 /* just set start keyframe */ 00437 start= bezt; 00438 end= NULL; 00439 } 00440 } 00441 } 00442 00443 /* recalculate channel's handles? */ 00444 calchandles_fcurve(fcu); 00445 } 00446 00447 /* **************************************************** */ 00448 /* Copy/Paste Tools */ 00449 /* - The copy/paste buffer currently stores a set of temporary F-Curves containing only the keyframes 00450 * that were selected in each of the original F-Curves 00451 * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of 00452 * the current frame and the 'first keyframe' (i.e. the earliest one in all channels). 00453 * - The earliest frame is calculated per copy operation. 00454 */ 00455 00456 /* globals for copy/paste data (like for other copy/paste buffers) */ 00457 static ListBase animcopybuf = {NULL, NULL}; 00458 static float animcopy_firstframe= 999999999.0f; 00459 static float animcopy_lastframe= -999999999.0f; 00460 static float animcopy_cfra= 0.0; 00461 00462 /* datatype for use in copy/paste buffer */ 00463 typedef struct tAnimCopybufItem { 00464 struct tAnimCopybufItem *next, *prev; 00465 00466 ID *id; /* ID which owns the curve */ 00467 bActionGroup *grp; /* Action Group */ 00468 char *rna_path; /* RNA-Path */ 00469 int array_index; /* array index */ 00470 00471 int totvert; /* number of keyframes stored for this channel */ 00472 BezTriple *bezt; /* keyframes in buffer */ 00473 00474 short id_type; /* Result of GS(id->name)*/ 00475 } tAnimCopybufItem; 00476 00477 00478 /* This function frees any MEM_calloc'ed copy/paste buffer data */ 00479 // XXX find some header to put this in! 00480 void free_anim_copybuf (void) 00481 { 00482 tAnimCopybufItem *aci, *acn; 00483 00484 /* free each buffer element */ 00485 for (aci= animcopybuf.first; aci; aci= acn) { 00486 acn= aci->next; 00487 00488 /* free keyframes */ 00489 if (aci->bezt) 00490 MEM_freeN(aci->bezt); 00491 00492 /* free RNA-path */ 00493 if (aci->rna_path) 00494 MEM_freeN(aci->rna_path); 00495 00496 /* free ourself */ 00497 BLI_freelinkN(&animcopybuf, aci); 00498 } 00499 00500 /* restore initial state */ 00501 animcopybuf.first= animcopybuf.last= NULL; 00502 animcopy_firstframe= 999999999.0f; 00503 animcopy_lastframe= -999999999.0f; 00504 } 00505 00506 /* ------------------- */ 00507 00508 /* This function adds data to the keyframes copy/paste buffer, freeing existing data first */ 00509 short copy_animedit_keys (bAnimContext *ac, ListBase *anim_data) 00510 { 00511 bAnimListElem *ale; 00512 Scene *scene= ac->scene; 00513 00514 /* clear buffer first */ 00515 free_anim_copybuf(); 00516 00517 /* assume that each of these is an F-Curve */ 00518 for (ale= anim_data->first; ale; ale= ale->next) { 00519 FCurve *fcu= (FCurve *)ale->key_data; 00520 tAnimCopybufItem *aci; 00521 BezTriple *bezt, *nbezt, *newbuf; 00522 int i; 00523 00524 /* firstly, check if F-Curve has any selected keyframes 00525 * - skip if no selected keyframes found (so no need to create unnecessary copy-buffer data) 00526 * - this check should also eliminate any problems associated with using sample-data 00527 */ 00528 if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ANIM_editkeyframes_ok(BEZT_OK_SELECTED), NULL) == 0) 00529 continue; 00530 00531 /* init copybuf item info */ 00532 aci= MEM_callocN(sizeof(tAnimCopybufItem), "AnimCopybufItem"); 00533 aci->id= ale->id; 00534 aci->id_type= GS(ale->id->name); 00535 aci->grp= fcu->grp; 00536 aci->rna_path= MEM_dupallocN(fcu->rna_path); 00537 aci->array_index= fcu->array_index; 00538 BLI_addtail(&animcopybuf, aci); 00539 00540 /* add selected keyframes to buffer */ 00541 // TODO: currently, we resize array everytime we add a new vert - this works ok as long as it is assumed only a few keys are copied 00542 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) { 00543 if (BEZSELECTED(bezt)) { 00544 /* add to buffer */ 00545 newbuf= MEM_callocN(sizeof(BezTriple)*(aci->totvert+1), "copybuf beztriple"); 00546 00547 /* assume that since we are just resizing the array, just copy all existing data across */ 00548 if (aci->bezt) 00549 memcpy(newbuf, aci->bezt, sizeof(BezTriple)*(aci->totvert)); 00550 00551 /* copy current beztriple across too */ 00552 nbezt= &newbuf[aci->totvert]; 00553 *nbezt= *bezt; 00554 00555 /* ensure copy buffer is selected so pasted keys are selected */ 00556 BEZ_SEL(nbezt); 00557 00558 /* free old array and set the new */ 00559 if (aci->bezt) MEM_freeN(aci->bezt); 00560 aci->bezt= newbuf; 00561 aci->totvert++; 00562 00563 /* check if this is the earliest frame encountered so far */ 00564 if (bezt->vec[1][0] < animcopy_firstframe) 00565 animcopy_firstframe= bezt->vec[1][0]; 00566 if (bezt->vec[1][0] > animcopy_lastframe) 00567 animcopy_lastframe= bezt->vec[1][0]; 00568 } 00569 } 00570 00571 } 00572 00573 /* check if anything ended up in the buffer */ 00574 if (ELEM(NULL, animcopybuf.first, animcopybuf.last)) 00575 return -1; 00576 00577 /* incase 'relative' paste method is used */ 00578 animcopy_cfra= CFRA; 00579 00580 /* everything went fine */ 00581 return 0; 00582 } 00583 00584 /* ------------------- */ 00585 00586 /* most strict method: exact matches only */ 00587 static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_single, const short to_simple) 00588 { 00589 tAnimCopybufItem *aci; 00590 00591 for (aci= animcopybuf.first; aci; aci= aci->next) { 00592 /* check that paths exist */ 00593 if (to_simple || (aci->rna_path && fcu->rna_path)) { 00594 if (to_simple || (strcmp(aci->rna_path, fcu->rna_path) == 0)) { 00595 if ((from_single) || (aci->array_index == fcu->array_index)) 00596 break; 00597 } 00598 } 00599 } 00600 00601 return aci; 00602 } 00603 00604 /* medium match strictness: path match only (i.e. ignore ID) */ 00605 static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short from_single, const short UNUSED(to_simple)) 00606 { 00607 tAnimCopybufItem *aci; 00608 00609 for (aci= animcopybuf.first; aci; aci= aci->next) { 00610 /* check that paths exist */ 00611 if (aci->rna_path && fcu->rna_path) { 00612 /* find the property of the fcurve and compare against the end of the tAnimCopybufItem 00613 * more involved since it needs to to path lookups. 00614 * This is not 100% reliable since the user could be editing the curves on a path that wont 00615 * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste 00616 * this should work out ok. 00617 */ 00618 if (BLI_findindex(which_libbase(G.main, aci->id_type), aci->id) == -1) { 00619 /* pedantic but the ID could have been removed, and beats crashing! */ 00620 printf("paste_animedit_keys: error ID has been removed!\n"); 00621 } 00622 else { 00623 PointerRNA id_ptr, rptr; 00624 PropertyRNA *prop; 00625 00626 RNA_id_pointer_create(aci->id, &id_ptr); 00627 RNA_path_resolve(&id_ptr, aci->rna_path, &rptr, &prop); 00628 00629 if (prop) { 00630 const char *identifier= RNA_property_identifier(prop); 00631 int len_id = strlen(identifier); 00632 int len_path = strlen(fcu->rna_path); 00633 if (len_id <= len_path) { 00634 /* note, paths which end with "] will fail with this test - Animated ID Props */ 00635 if (strcmp(identifier, fcu->rna_path + (len_path-len_id))==0) { 00636 if ((from_single) || (aci->array_index == fcu->array_index)) 00637 break; 00638 } 00639 } 00640 } 00641 else { 00642 printf("paste_animedit_keys: failed to resolve path id:%s, '%s'!\n", aci->id->name, aci->rna_path); 00643 } 00644 } 00645 } 00646 } 00647 00648 return aci; 00649 } 00650 00651 /* least strict matching heuristic: indices only */ 00652 static tAnimCopybufItem *pastebuf_match_index_only(FCurve *fcu, const short from_single, const short UNUSED(to_simple)) 00653 { 00654 tAnimCopybufItem *aci; 00655 00656 for (aci= animcopybuf.first; aci; aci= aci->next) { 00657 /* check that paths exist */ 00658 if ((from_single) || (aci->array_index == fcu->array_index)) { 00659 break; 00660 } 00661 } 00662 00663 return aci; 00664 } 00665 00666 /* ................ */ 00667 00668 /* helper for paste_animedit_keys() - performs the actual pasting */ 00669 static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float offset, const eKeyMergeMode merge_mode) 00670 { 00671 BezTriple *bezt; 00672 int i; 00673 00674 /* First de-select existing FCuvre */ 00675 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) { 00676 bezt->f2 &= ~SELECT; 00677 } 00678 00679 /* mix mode with existing data */ 00680 switch (merge_mode) { 00681 case KEYFRAME_PASTE_MERGE_MIX: 00682 /* do-nothing */ 00683 break; 00684 00685 case KEYFRAME_PASTE_MERGE_OVER: 00686 /* remove all keys */ 00687 clear_fcurve_keys(fcu); 00688 break; 00689 00690 case KEYFRAME_PASTE_MERGE_OVER_RANGE: 00691 case KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL: 00692 { 00693 float f_min; 00694 float f_max; 00695 00696 if (merge_mode==KEYFRAME_PASTE_MERGE_OVER_RANGE) { 00697 f_min= aci->bezt[0].vec[1][0] + offset; 00698 f_max= aci->bezt[aci->totvert-1].vec[1][0] + offset; 00699 } 00700 else { /* Entire Range */ 00701 f_min= animcopy_firstframe + offset; 00702 f_max= animcopy_lastframe + offset; 00703 } 00704 00705 /* remove keys in range */ 00706 if (f_min < f_max) { 00707 /* select verts in range for removal */ 00708 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) { 00709 if ((f_min < bezt[0].vec[1][0]) && (bezt[0].vec[1][0] < f_max)) { 00710 bezt->f2 |= SELECT; 00711 } 00712 } 00713 00714 /* remove frames in the range */ 00715 delete_fcurve_keys(fcu); 00716 } 00717 break; 00718 } 00719 } 00720 00721 /* just start pasting, with the the first keyframe on the current frame, and so on */ 00722 for (i=0, bezt=aci->bezt; i < aci->totvert; i++, bezt++) { 00723 /* temporarily apply offset to src beztriple while copying */ 00724 bezt->vec[0][0] += offset; 00725 bezt->vec[1][0] += offset; 00726 bezt->vec[2][0] += offset; 00727 00728 /* insert the keyframe 00729 * NOTE: no special flags here for now 00730 */ 00731 insert_bezt_fcurve(fcu, bezt, 0); 00732 00733 /* un-apply offset from src beztriple after copying */ 00734 bezt->vec[0][0] -= offset; 00735 bezt->vec[1][0] -= offset; 00736 bezt->vec[2][0] -= offset; 00737 } 00738 00739 /* recalculate F-Curve's handles? */ 00740 calchandles_fcurve(fcu); 00741 } 00742 00743 /* ------------------- */ 00744 00745 EnumPropertyItem keyframe_paste_offset_items[] = { 00746 {KEYFRAME_PASTE_OFFSET_CFRA_START, "START", 0, "Frame Start", "Paste keys starting at current frame"}, 00747 {KEYFRAME_PASTE_OFFSET_CFRA_END, "END", 0, "Frame End", "Paste keys ending at current frame"}, 00748 {KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE, "RELATIVE", 0, "Frame Relative", "Paste keys relative to the current frame when copying"}, 00749 {KEYFRAME_PASTE_OFFSET_NONE, "NONE", 0, "No Offset", "Paste keys from original time"}, 00750 {0, NULL, 0, NULL, NULL}}; 00751 00752 EnumPropertyItem keyframe_paste_merge_items[] = { 00753 {KEYFRAME_PASTE_MERGE_MIX, "MIX", 0, "Mix", "Overlay existing with new keys"}, 00754 {KEYFRAME_PASTE_MERGE_OVER, "OVER_ALL", 0, "Overwrite All", "Replace all keys"}, 00755 {KEYFRAME_PASTE_MERGE_OVER_RANGE, "OVER_RANGE", 0, "Overwrite Range", "Overwrite keys in pasted range"}, 00756 {KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL, "OVER_RANGE_ALL", 0, "Overwrite Entire Range", "Overwrite keys in pasted range, using the range of all copied keys"}, 00757 {0, NULL, 0, NULL, NULL}}; 00758 00759 00760 /* This function pastes data from the keyframes copy/paste buffer 00761 * > return status code is whether the method FAILED to do anything 00762 */ 00763 short paste_animedit_keys (bAnimContext *ac, ListBase *anim_data, 00764 const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode) 00765 { 00766 bAnimListElem *ale; 00767 00768 const Scene *scene= (ac->scene); 00769 00770 const short from_single= (animcopybuf.first == animcopybuf.last); 00771 const short to_simple= (anim_data->first == anim_data->last); 00772 00773 float offset = 0.0f; 00774 int pass; 00775 00776 /* check if buffer is empty */ 00777 if (animcopybuf.first == NULL) { 00778 BKE_report(ac->reports, RPT_ERROR, "No animation data in buffer to paste"); 00779 return -1; 00780 } 00781 00782 if (anim_data->first == NULL) { 00783 BKE_report(ac->reports, RPT_ERROR, "No selected F-Curves to paste into"); 00784 return -1; 00785 } 00786 00787 /* mathods of offset */ 00788 switch (offset_mode) { 00789 case KEYFRAME_PASTE_OFFSET_CFRA_START: 00790 offset= (float)(CFRA - animcopy_firstframe); 00791 break; 00792 case KEYFRAME_PASTE_OFFSET_CFRA_END: 00793 offset= (float)(CFRA - animcopy_lastframe); 00794 break; 00795 case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE: 00796 offset= (float)(CFRA - animcopy_cfra); 00797 break; 00798 case KEYFRAME_PASTE_OFFSET_NONE: 00799 offset= 0.0f; 00800 break; 00801 } 00802 00803 if (from_single && to_simple) { 00804 /* 1:1 match, no tricky checking, just paste */ 00805 FCurve *fcu; 00806 tAnimCopybufItem *aci; 00807 00808 ale= anim_data->first; 00809 fcu= (FCurve *)ale->data; /* destination F-Curve */ 00810 aci= animcopybuf.first; 00811 00812 paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode); 00813 } 00814 else { 00815 /* from selected channels 00816 * This "passes" system aims to try to find "matching" channels to paste keyframes 00817 * into with increasingly loose matching heuristics. The process finishes when at least 00818 * one F-Curve has been pasted into. 00819 */ 00820 for (pass= 0; pass < 3; pass++) { 00821 unsigned int totmatch= 0; 00822 00823 for (ale= anim_data->first; ale; ale= ale->next) { 00824 /* find buffer item to paste from 00825 * - if names don't matter (i.e. only 1 channel in buffer), don't check id/group 00826 * - if names do matter, only check if id-type is ok for now (group check is not that important) 00827 * - most importantly, rna-paths should match (array indices are unimportant for now) 00828 */ 00829 FCurve *fcu = (FCurve *)ale->data; /* destination F-Curve */ 00830 tAnimCopybufItem *aci= NULL; 00831 00832 switch (pass) { 00833 case 0: 00834 /* most strict, must be exact path match data_path & index */ 00835 aci= pastebuf_match_path_full(fcu, from_single, to_simple); 00836 break; 00837 00838 case 1: 00839 /* less strict, just compare property names */ 00840 aci= pastebuf_match_path_property(fcu, from_single, to_simple); 00841 break; 00842 00843 case 2: 00844 /* Comparing properties gave no results, so just do index comparisons */ 00845 aci= pastebuf_match_index_only(fcu, from_single, to_simple); 00846 break; 00847 } 00848 00849 /* copy the relevant data from the matching buffer curve */ 00850 if (aci) { 00851 totmatch++; 00852 paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode); 00853 } 00854 } 00855 00856 /* dont continue if some fcurves were pasted */ 00857 if (totmatch) 00858 break; 00859 } 00860 } 00861 00862 return 0; 00863 } 00864 00865 /* **************************************************** */