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