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) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): Joshua Leung 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <math.h> 00034 #include <stdlib.h> 00035 #include <string.h> 00036 #include <float.h> 00037 00038 #ifdef WITH_AUDASPACE 00039 # include "AUD_C-API.h" 00040 #endif 00041 00042 #include "MEM_guardedalloc.h" 00043 00044 #include "BLI_blenlib.h" 00045 #include "BLI_math.h" 00046 #include "BLI_utildefines.h" 00047 00048 #include "DNA_anim_types.h" 00049 #include "DNA_object_types.h" 00050 #include "DNA_scene_types.h" 00051 00052 #include "RNA_access.h" 00053 #include "RNA_define.h" 00054 #include "RNA_enum_types.h" 00055 00056 #include "BKE_fcurve.h" 00057 #include "BKE_nla.h" 00058 #include "BKE_context.h" 00059 #include "BKE_report.h" 00060 00061 #include "UI_interface.h" 00062 #include "UI_resources.h" 00063 #include "UI_view2d.h" 00064 00065 #include "ED_anim_api.h" 00066 #include "ED_keyframing.h" 00067 #include "ED_keyframes_edit.h" 00068 #include "ED_screen.h" 00069 #include "ED_transform.h" 00070 #include "ED_markers.h" 00071 00072 #include "WM_api.h" 00073 #include "WM_types.h" 00074 00075 #include "graph_intern.h" 00076 00077 /* ************************************************************************** */ 00078 /* KEYFRAME-RANGE STUFF */ 00079 00080 /* *************************** Calculate Range ************************** */ 00081 00082 /* Get the min/max keyframes*/ 00083 /* note: it should return total boundbox, filter for selection only can be argument... */ 00084 void get_graph_keyframe_extents (bAnimContext *ac, float *xmin, float *xmax, float *ymin, float *ymax, const short selOnly) 00085 { 00086 ListBase anim_data = {NULL, NULL}; 00087 bAnimListElem *ale; 00088 int filter; 00089 00090 /* get data to filter, from Dopesheet */ 00091 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); 00092 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00093 00094 /* set large values to try to override */ 00095 if (xmin) *xmin= 999999999.0f; 00096 if (xmax) *xmax= -999999999.0f; 00097 if (ymin) *ymin= 999999999.0f; 00098 if (ymax) *ymax= -999999999.0f; 00099 00100 /* check if any channels to set range with */ 00101 if (anim_data.first) { 00102 /* go through channels, finding max extents */ 00103 for (ale= anim_data.first; ale; ale= ale->next) { 00104 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00105 FCurve *fcu= (FCurve *)ale->key_data; 00106 float txmin, txmax, tymin, tymax; 00107 float unitFac; 00108 00109 /* get range */ 00110 calc_fcurve_bounds(fcu, &txmin, &txmax, &tymin, &tymax, selOnly); 00111 00112 /* apply NLA scaling */ 00113 if (adt) { 00114 txmin= BKE_nla_tweakedit_remap(adt, txmin, NLATIME_CONVERT_MAP); 00115 txmax= BKE_nla_tweakedit_remap(adt, txmax, NLATIME_CONVERT_MAP); 00116 } 00117 00118 /* apply unit corrections */ 00119 unitFac= ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, 0); 00120 tymin *= unitFac; 00121 tymax *= unitFac; 00122 00123 /* try to set cur using these values, if they're more extreme than previously set values */ 00124 if ((xmin) && (txmin < *xmin)) *xmin= txmin; 00125 if ((xmax) && (txmax > *xmax)) *xmax= txmax; 00126 if ((ymin) && (tymin < *ymin)) *ymin= tymin; 00127 if ((ymax) && (tymax > *ymax)) *ymax= tymax; 00128 } 00129 00130 /* ensure that the extents are not too extreme that view implodes...*/ 00131 if ((xmin && xmax) && (fabsf(*xmax - *xmin) < 0.1f)) *xmax += 0.1f; 00132 if ((ymin && ymax) && (fabsf(*ymax - *ymin) < 0.1f)) *ymax += 0.1f; 00133 00134 /* free memory */ 00135 BLI_freelistN(&anim_data); 00136 } 00137 else { 00138 /* set default range */ 00139 if (ac->scene) { 00140 if (xmin) *xmin= (float)ac->scene->r.sfra; 00141 if (xmax) *xmax= (float)ac->scene->r.efra; 00142 } 00143 else { 00144 if (xmin) *xmin= -5; 00145 if (xmax) *xmax= 100; 00146 } 00147 00148 if (ymin) *ymin= -5; 00149 if (ymax) *ymax= 5; 00150 } 00151 } 00152 00153 /* ****************** Automatic Preview-Range Operator ****************** */ 00154 00155 static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) 00156 { 00157 bAnimContext ac; 00158 Scene *scene; 00159 float min, max; 00160 00161 /* get editor data */ 00162 if (ANIM_animdata_get_context(C, &ac) == 0) 00163 return OPERATOR_CANCELLED; 00164 if (ac.scene == NULL) 00165 return OPERATOR_CANCELLED; 00166 else 00167 scene= ac.scene; 00168 00169 /* set the range directly */ 00170 get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL, FALSE); 00171 scene->r.flag |= SCER_PRV_RANGE; 00172 scene->r.psfra= (int)floor(min + 0.5f); 00173 scene->r.pefra= (int)floor(max + 0.5f); 00174 00175 /* set notifier that things have changed */ 00176 // XXX err... there's nothing for frame ranges yet, but this should do fine too 00177 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene); 00178 00179 return OPERATOR_FINISHED; 00180 } 00181 00182 void GRAPH_OT_previewrange_set (wmOperatorType *ot) 00183 { 00184 /* identifiers */ 00185 ot->name= "Auto-Set Preview Range"; 00186 ot->idname= "GRAPH_OT_previewrange_set"; 00187 ot->description= "Automatically set Preview Range based on range of keyframes"; 00188 00189 /* api callbacks */ 00190 ot->exec= graphkeys_previewrange_exec; 00191 ot->poll= ED_operator_graphedit_active; // XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... 00192 00193 /* flags */ 00194 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00195 } 00196 00197 /* ****************** View-All Operator ****************** */ 00198 00199 static int graphkeys_viewall(bContext *C, const short selOnly) 00200 { 00201 bAnimContext ac; 00202 View2D *v2d; 00203 float extra; 00204 00205 /* get editor data */ 00206 if (ANIM_animdata_get_context(C, &ac) == 0) 00207 return OPERATOR_CANCELLED; 00208 v2d= &ac.ar->v2d; 00209 00210 /* set the horizontal range, with an extra offset so that the extreme keys will be in view */ 00211 get_graph_keyframe_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, &v2d->cur.ymin, &v2d->cur.ymax, selOnly); 00212 00213 extra= 0.1f * (v2d->cur.xmax - v2d->cur.xmin); 00214 v2d->cur.xmin -= extra; 00215 v2d->cur.xmax += extra; 00216 00217 extra= 0.1f * (v2d->cur.ymax - v2d->cur.ymin); 00218 v2d->cur.ymin -= extra; 00219 v2d->cur.ymax += extra; 00220 00221 /* do View2D syncing */ 00222 UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY); 00223 00224 /* set notifier that things have changed */ 00225 ED_area_tag_redraw(CTX_wm_area(C)); 00226 00227 return OPERATOR_FINISHED; 00228 } 00229 00230 /* ......... */ 00231 00232 static int graphkeys_viewall_exec(bContext *C, wmOperator *UNUSED(op)) 00233 { 00234 /* whole range */ 00235 return graphkeys_viewall(C, FALSE); 00236 } 00237 00238 static int graphkeys_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) 00239 { 00240 /* only selected */ 00241 return graphkeys_viewall(C, TRUE); 00242 } 00243 00244 void GRAPH_OT_view_all (wmOperatorType *ot) 00245 { 00246 /* identifiers */ 00247 ot->name= "View All"; 00248 ot->idname= "GRAPH_OT_view_all"; 00249 ot->description= "Reset viewable area to show full keyframe range"; 00250 00251 /* api callbacks */ 00252 ot->exec= graphkeys_viewall_exec; 00253 ot->poll= ED_operator_graphedit_active; // XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... 00254 00255 /* flags */ 00256 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00257 } 00258 00259 void GRAPH_OT_view_selected (wmOperatorType *ot) 00260 { 00261 /* identifiers */ 00262 ot->name= "View Selected"; 00263 ot->idname= "GRAPH_OT_view_selected"; 00264 ot->description= "Reset viewable area to show selected keyframe range"; 00265 00266 /* api callbacks */ 00267 ot->exec= graphkeys_view_selected_exec; 00268 ot->poll= ED_operator_graphedit_active; // XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... 00269 00270 /* flags */ 00271 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00272 } 00273 00274 /* ******************** Create Ghost-Curves Operator *********************** */ 00275 /* This operator samples the data of the selected F-Curves to F-Points, storing them 00276 * as 'ghost curves' in the active Graph Editor 00277 */ 00278 00279 /* Bake each F-Curve into a set of samples, and store as a ghost curve */ 00280 static void create_ghost_curves (bAnimContext *ac, int start, int end) 00281 { 00282 SpaceIpo *sipo= (SpaceIpo *)ac->sl; 00283 ListBase anim_data = {NULL, NULL}; 00284 bAnimListElem *ale; 00285 int filter; 00286 00287 /* free existing ghost curves */ 00288 free_fcurves(&sipo->ghostCurves); 00289 00290 /* sanity check */ 00291 if (start >= end) { 00292 printf("Error: Frame range for Ghost F-Curve creation is inappropriate \n"); 00293 return; 00294 } 00295 00296 /* filter data */ 00297 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); 00298 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00299 00300 /* loop through filtered data and add keys between selected keyframes on every frame */ 00301 for (ale= anim_data.first; ale; ale= ale->next) { 00302 FCurve *fcu= (FCurve *)ale->key_data; 00303 FCurve *gcu= MEM_callocN(sizeof(FCurve), "Ghost FCurve"); 00304 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00305 ChannelDriver *driver= fcu->driver; 00306 FPoint *fpt; 00307 float unitFac; 00308 int cfra; 00309 00310 /* disable driver so that it don't muck up the sampling process */ 00311 fcu->driver= NULL; 00312 00313 /* calculate unit-mapping factor */ 00314 unitFac= ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, 0); 00315 00316 /* create samples, but store them in a new curve 00317 * - we cannot use fcurve_store_samples() as that will only overwrite the original curve 00318 */ 00319 gcu->fpt= fpt= MEM_callocN(sizeof(FPoint)*(end-start+1), "Ghost FPoint Samples"); 00320 gcu->totvert= end - start + 1; 00321 00322 /* use the sampling callback at 1-frame intervals from start to end frames */ 00323 for (cfra= start; cfra <= end; cfra++, fpt++) { 00324 float cfrae= BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP); 00325 00326 fpt->vec[0]= cfrae; 00327 fpt->vec[1]= fcurve_samplingcb_evalcurve(fcu, NULL, cfrae) * unitFac; 00328 } 00329 00330 /* set color of ghost curve 00331 * - make the color slightly darker 00332 */ 00333 gcu->color[0]= fcu->color[0] - 0.07f; 00334 gcu->color[1]= fcu->color[1] - 0.07f; 00335 gcu->color[2]= fcu->color[2] - 0.07f; 00336 00337 /* store new ghost curve */ 00338 BLI_addtail(&sipo->ghostCurves, gcu); 00339 00340 /* restore driver */ 00341 fcu->driver= driver; 00342 } 00343 00344 /* admin and redraws */ 00345 BLI_freelistN(&anim_data); 00346 } 00347 00348 /* ------------------- */ 00349 00350 static int graphkeys_create_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op)) 00351 { 00352 bAnimContext ac; 00353 View2D *v2d; 00354 int start, end; 00355 00356 /* get editor data */ 00357 if (ANIM_animdata_get_context(C, &ac) == 0) 00358 return OPERATOR_CANCELLED; 00359 00360 /* ghost curves are snapshots of the visible portions of the curves, so set range to be the visible range */ 00361 v2d= &ac.ar->v2d; 00362 start= (int)v2d->cur.xmin; 00363 end= (int)v2d->cur.xmax; 00364 00365 /* bake selected curves into a ghost curve */ 00366 create_ghost_curves(&ac, start, end); 00367 00368 /* update this editor only */ 00369 ED_area_tag_redraw(CTX_wm_area(C)); 00370 00371 return OPERATOR_FINISHED; 00372 } 00373 00374 void GRAPH_OT_ghost_curves_create (wmOperatorType *ot) 00375 { 00376 /* identifiers */ 00377 ot->name= "Create Ghost Curves"; 00378 ot->idname= "GRAPH_OT_ghost_curves_create"; 00379 ot->description= "Create snapshot (Ghosts) of selected F-Curves as background aid for active Graph Editor"; 00380 00381 /* api callbacks */ 00382 ot->exec= graphkeys_create_ghostcurves_exec; 00383 ot->poll= graphop_visible_keyframes_poll; 00384 00385 /* flags */ 00386 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00387 00388 // todo: add props for start/end frames 00389 } 00390 00391 /* ******************** Clear Ghost-Curves Operator *********************** */ 00392 /* This operator clears the 'ghost curves' for the active Graph Editor */ 00393 00394 static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op)) 00395 { 00396 bAnimContext ac; 00397 SpaceIpo *sipo; 00398 00399 /* get editor data */ 00400 if (ANIM_animdata_get_context(C, &ac) == 0) 00401 return OPERATOR_CANCELLED; 00402 sipo= (SpaceIpo *)ac.sl; 00403 00404 /* if no ghost curves, don't do anything */ 00405 if (sipo->ghostCurves.first == NULL) 00406 return OPERATOR_CANCELLED; 00407 00408 /* free ghost curves */ 00409 free_fcurves(&sipo->ghostCurves); 00410 00411 /* update this editor only */ 00412 ED_area_tag_redraw(CTX_wm_area(C)); 00413 00414 return OPERATOR_FINISHED; 00415 } 00416 00417 void GRAPH_OT_ghost_curves_clear (wmOperatorType *ot) 00418 { 00419 /* identifiers */ 00420 ot->name= "Clear Ghost Curves"; 00421 ot->idname= "GRAPH_OT_ghost_curves_clear"; 00422 ot->description= "Clear F-Curve snapshots (Ghosts) for active Graph Editor"; 00423 00424 /* api callbacks */ 00425 ot->exec= graphkeys_clear_ghostcurves_exec; 00426 ot->poll= ED_operator_graphedit_active; 00427 00428 /* flags */ 00429 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00430 } 00431 00432 /* ************************************************************************** */ 00433 /* GENERAL STUFF */ 00434 00435 /* ******************** Insert Keyframes Operator ************************* */ 00436 00437 /* defines for insert keyframes tool */ 00438 static EnumPropertyItem prop_graphkeys_insertkey_types[] = { 00439 {1, "ALL", 0, "All Channels", ""}, 00440 {2, "SEL", 0, "Only Selected Channels", ""}, 00441 {0, NULL, 0, NULL, NULL} 00442 }; 00443 00444 /* this function is responsible for snapping keyframes to frame-times */ 00445 static void insert_graph_keys(bAnimContext *ac, short mode) 00446 { 00447 ListBase anim_data = {NULL, NULL}; 00448 bAnimListElem *ale; 00449 int filter; 00450 00451 ReportList *reports = ac->reports; 00452 Scene *scene= ac->scene; 00453 short flag = 0; 00454 00455 /* filter data */ 00456 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 00457 if (mode == 2) filter |= ANIMFILTER_SEL; 00458 00459 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00460 00461 /* init keyframing flag */ 00462 flag = ANIM_get_keyframing_flags(scene, 1); 00463 00464 /* insert keyframes */ 00465 for (ale= anim_data.first; ale; ale= ale->next) { 00466 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00467 FCurve *fcu= (FCurve *)ale->key_data; 00468 float cfra; 00469 00470 /* adjust current frame for NLA-mapping */ 00471 if (adt) 00472 cfra= BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP); 00473 else 00474 cfra= (float)CFRA; 00475 00476 /* if there's an id */ 00477 if (ale->id) 00478 insert_keyframe(reports, ale->id, NULL, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag); 00479 else 00480 insert_vert_fcurve(fcu, cfra, fcu->curval, 0); 00481 } 00482 00483 BLI_freelistN(&anim_data); 00484 } 00485 00486 /* ------------------- */ 00487 00488 static int graphkeys_insertkey_exec(bContext *C, wmOperator *op) 00489 { 00490 bAnimContext ac; 00491 short mode; 00492 00493 /* get editor data */ 00494 if (ANIM_animdata_get_context(C, &ac) == 0) 00495 return OPERATOR_CANCELLED; 00496 00497 /* which channels to affect? */ 00498 mode= RNA_enum_get(op->ptr, "type"); 00499 00500 /* insert keyframes */ 00501 insert_graph_keys(&ac, mode); 00502 00503 /* validate keyframes after editing */ 00504 ANIM_editkeyframes_refresh(&ac); 00505 00506 /* set notifier that keyframes have changed */ 00507 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00508 00509 return OPERATOR_FINISHED; 00510 } 00511 00512 void GRAPH_OT_keyframe_insert (wmOperatorType *ot) 00513 { 00514 /* identifiers */ 00515 ot->name= "Insert Keyframes"; 00516 ot->idname= "GRAPH_OT_keyframe_insert"; 00517 ot->description= "Insert keyframes for the specified channels"; 00518 00519 /* api callbacks */ 00520 ot->invoke= WM_menu_invoke; 00521 ot->exec= graphkeys_insertkey_exec; 00522 ot->poll= graphop_editable_keyframes_poll; 00523 00524 /* flags */ 00525 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00526 00527 /* id-props */ 00528 ot->prop= RNA_def_enum(ot->srna, "type", prop_graphkeys_insertkey_types, 0, "Type", ""); 00529 } 00530 00531 /* ******************** Click-Insert Keyframes Operator ************************* */ 00532 00533 static int graphkeys_click_insert_exec (bContext *C, wmOperator *op) 00534 { 00535 bAnimContext ac; 00536 bAnimListElem *ale; 00537 AnimData *adt; 00538 FCurve *fcu; 00539 float frame, val; 00540 00541 /* get animation context */ 00542 if (ANIM_animdata_get_context(C, &ac) == 0) 00543 return OPERATOR_CANCELLED; 00544 00545 /* get active F-Curve 'anim-list-element' */ 00546 ale= get_active_fcurve_channel(&ac); 00547 if (ELEM(NULL, ale, ale->data)) { 00548 if (ale) MEM_freeN(ale); 00549 return OPERATOR_CANCELLED; 00550 } 00551 fcu = ale->data; 00552 00553 /* when there are F-Modifiers on the curve, only allow adding 00554 * keyframes if these will be visible after doing so... 00555 */ 00556 if (fcurve_is_keyframable(fcu)) { 00557 /* get frame and value from props */ 00558 frame= RNA_float_get(op->ptr, "frame"); 00559 val= RNA_float_get(op->ptr, "value"); 00560 00561 /* apply inverse NLA-mapping to frame to get correct time in un-scaled action */ 00562 adt= ANIM_nla_mapping_get(&ac, ale); 00563 frame= BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP); 00564 00565 /* apply inverse unit-mapping to value to get correct value for F-Curves */ 00566 val *= ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, 1); 00567 00568 /* insert keyframe on the specified frame + value */ 00569 insert_vert_fcurve(fcu, frame, val, 0); 00570 } 00571 else { 00572 /* warn about why this can't happen */ 00573 if (fcu->fpt) 00574 BKE_report(op->reports, RPT_ERROR, "Keyframes cannot be added to sampled F-Curves"); 00575 else if (fcu->flag & FCURVE_PROTECTED) 00576 BKE_report(op->reports, RPT_ERROR, "Active F-Curve is not editable"); 00577 else 00578 BKE_report(op->reports, RPT_ERROR, "Remove F-Modifiers from F-Curve to add keyframes"); 00579 } 00580 00581 /* free temp data */ 00582 MEM_freeN(ale); 00583 00584 /* set notifier that keyframes have changed */ 00585 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00586 00587 /* done */ 00588 return OPERATOR_FINISHED; 00589 } 00590 00591 static int graphkeys_click_insert_invoke (bContext *C, wmOperator *op, wmEvent *evt) 00592 { 00593 bAnimContext ac; 00594 ARegion *ar; 00595 View2D *v2d; 00596 int mval[2]; 00597 float x, y; 00598 00599 /* get animation context */ 00600 if (ANIM_animdata_get_context(C, &ac) == 0) 00601 return OPERATOR_CANCELLED; 00602 00603 /* store mouse coordinates in View2D space, into the operator's properties */ 00604 ar= ac.ar; 00605 v2d= &ar->v2d; 00606 00607 mval[0]= (evt->x - ar->winrct.xmin); 00608 mval[1]= (evt->y - ar->winrct.ymin); 00609 00610 UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); 00611 00612 RNA_float_set(op->ptr, "frame", x); 00613 RNA_float_set(op->ptr, "value", y); 00614 00615 /* run exec now */ 00616 return graphkeys_click_insert_exec(C, op); 00617 } 00618 00619 void GRAPH_OT_click_insert (wmOperatorType *ot) 00620 { 00621 /* identifiers */ 00622 ot->name= "Click-Insert Keyframes"; 00623 ot->idname= "GRAPH_OT_click_insert"; 00624 ot->description= "Insert new keyframe at the cursor position for the active F-Curve"; 00625 00626 /* api callbacks */ 00627 ot->invoke= graphkeys_click_insert_invoke; 00628 ot->exec= graphkeys_click_insert_exec; 00629 ot->poll= graphop_active_fcurve_poll; 00630 00631 /* flags */ 00632 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00633 00634 /* properties */ 00635 RNA_def_float(ot->srna, "frame", 1.0f, -FLT_MAX, FLT_MAX, "Frame Number", "Frame to insert keyframe on", 0, 100); 00636 RNA_def_float(ot->srna, "value", 1.0f, -FLT_MAX, FLT_MAX, "Value", "Value for keyframe on", 0, 100); 00637 } 00638 00639 /* ******************** Copy/Paste Keyframes Operator ************************* */ 00640 /* NOTE: the backend code for this is shared with the dopesheet editor */ 00641 00642 static short copy_graph_keys (bAnimContext *ac) 00643 { 00644 ListBase anim_data = {NULL, NULL}; 00645 int filter, ok=0; 00646 00647 /* clear buffer first */ 00648 free_anim_copybuf(); 00649 00650 /* filter data */ 00651 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); 00652 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00653 00654 /* copy keyframes */ 00655 ok= copy_animedit_keys(ac, &anim_data); 00656 00657 /* clean up */ 00658 BLI_freelistN(&anim_data); 00659 00660 return ok; 00661 } 00662 00663 static short paste_graph_keys (bAnimContext *ac, 00664 const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode) 00665 { 00666 ListBase anim_data = {NULL, NULL}; 00667 int filter, ok=0; 00668 00669 /* filter data */ 00670 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 00671 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00672 00673 /* paste keyframes */ 00674 ok= paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode); 00675 00676 /* clean up */ 00677 BLI_freelistN(&anim_data); 00678 00679 return ok; 00680 } 00681 00682 /* ------------------- */ 00683 00684 static int graphkeys_copy_exec(bContext *C, wmOperator *op) 00685 { 00686 bAnimContext ac; 00687 00688 /* get editor data */ 00689 if (ANIM_animdata_get_context(C, &ac) == 0) 00690 return OPERATOR_CANCELLED; 00691 00692 /* copy keyframes */ 00693 if (copy_graph_keys(&ac)) { 00694 BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer"); 00695 return OPERATOR_CANCELLED; 00696 } 00697 00698 /* just return - no operator needed here (no changes) */ 00699 return OPERATOR_FINISHED; 00700 } 00701 00702 void GRAPH_OT_copy (wmOperatorType *ot) 00703 { 00704 /* identifiers */ 00705 ot->name= "Copy Keyframes"; 00706 ot->idname= "GRAPH_OT_copy"; 00707 ot->description= "Copy selected keyframes to the copy/paste buffer"; 00708 00709 /* api callbacks */ 00710 ot->exec= graphkeys_copy_exec; 00711 ot->poll= graphop_editable_keyframes_poll; 00712 00713 /* flags */ 00714 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00715 } 00716 00717 00718 00719 static int graphkeys_paste_exec(bContext *C, wmOperator *op) 00720 { 00721 bAnimContext ac; 00722 00723 const eKeyPasteOffset offset_mode= RNA_enum_get(op->ptr, "offset"); 00724 const eKeyMergeMode merge_mode= RNA_enum_get(op->ptr, "merge"); 00725 00726 /* get editor data */ 00727 if (ANIM_animdata_get_context(C, &ac) == 0) 00728 return OPERATOR_CANCELLED; 00729 00730 /* ac.reports by default will be the global reports list, which won't show warnings */ 00731 ac.reports= op->reports; 00732 00733 /* paste keyframes - non-zero return means an error occurred while trying to paste */ 00734 if (paste_graph_keys(&ac, offset_mode, merge_mode)) { 00735 return OPERATOR_CANCELLED; 00736 } 00737 00738 /* validate keyframes after editing */ 00739 ANIM_editkeyframes_refresh(&ac); 00740 00741 /* set notifier that keyframes have changed */ 00742 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00743 00744 return OPERATOR_FINISHED; 00745 } 00746 00747 void GRAPH_OT_paste (wmOperatorType *ot) 00748 { 00749 /* identifiers */ 00750 ot->name= "Paste Keyframes"; 00751 ot->idname= "GRAPH_OT_paste"; 00752 ot->description= "Paste keyframes from copy/paste buffer for the selected channels, starting on the current frame"; 00753 00754 /* api callbacks */ 00755 // ot->invoke= WM_operator_props_popup; // better wait for graph redo panel 00756 ot->exec= graphkeys_paste_exec; 00757 ot->poll= graphop_editable_keyframes_poll; 00758 00759 /* flags */ 00760 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00761 00762 RNA_def_enum(ot->srna, "offset", keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys"); 00763 RNA_def_enum(ot->srna, "merge", keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing"); 00764 } 00765 00766 /* ******************** Duplicate Keyframes Operator ************************* */ 00767 00768 static void duplicate_graph_keys (bAnimContext *ac) 00769 { 00770 ListBase anim_data = {NULL, NULL}; 00771 bAnimListElem *ale; 00772 int filter; 00773 00774 /* filter data */ 00775 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 00776 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00777 00778 /* loop through filtered data and delete selected keys */ 00779 for (ale= anim_data.first; ale; ale= ale->next) { 00780 duplicate_fcurve_keys((FCurve *)ale->key_data); 00781 } 00782 00783 /* free filtered list */ 00784 BLI_freelistN(&anim_data); 00785 } 00786 00787 /* ------------------- */ 00788 00789 static int graphkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) 00790 { 00791 bAnimContext ac; 00792 00793 /* get editor data */ 00794 if (ANIM_animdata_get_context(C, &ac) == 0) 00795 return OPERATOR_CANCELLED; 00796 00797 /* duplicate keyframes */ 00798 duplicate_graph_keys(&ac); 00799 00800 /* validate keyframes after editing */ 00801 ANIM_editkeyframes_refresh(&ac); 00802 00803 /* set notifier that keyframes have changed */ 00804 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00805 00806 return OPERATOR_FINISHED; 00807 } 00808 00809 static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 00810 { 00811 graphkeys_duplicate_exec(C, op); 00812 00813 return OPERATOR_FINISHED; 00814 } 00815 00816 void GRAPH_OT_duplicate (wmOperatorType *ot) 00817 { 00818 /* identifiers */ 00819 ot->name= "Duplicate Keyframes"; 00820 ot->idname= "GRAPH_OT_duplicate"; 00821 ot->description= "Make a copy of all selected keyframes"; 00822 00823 /* api callbacks */ 00824 ot->invoke= graphkeys_duplicate_invoke; 00825 ot->exec= graphkeys_duplicate_exec; 00826 ot->poll= graphop_editable_keyframes_poll; 00827 00828 /* flags */ 00829 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00830 00831 /* to give to transform */ 00832 RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", ""); 00833 } 00834 00835 /* ******************** Delete Keyframes Operator ************************* */ 00836 00837 static void delete_graph_keys (bAnimContext *ac) 00838 { 00839 ListBase anim_data = {NULL, NULL}; 00840 bAnimListElem *ale; 00841 int filter; 00842 00843 /* filter data */ 00844 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 00845 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00846 00847 /* loop through filtered data and delete selected keys */ 00848 for (ale= anim_data.first; ale; ale= ale->next) { 00849 FCurve *fcu= (FCurve *)ale->key_data; 00850 AnimData *adt= ale->adt; 00851 00852 /* delete selected keyframes only */ 00853 delete_fcurve_keys(fcu); 00854 00855 /* Only delete curve too if it won't be doing anything anymore */ 00856 if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) 00857 ANIM_fcurve_delete_from_animdata(ac, adt, fcu); 00858 } 00859 00860 /* free filtered list */ 00861 BLI_freelistN(&anim_data); 00862 } 00863 00864 /* ------------------- */ 00865 00866 static int graphkeys_delete_exec(bContext *C, wmOperator *UNUSED(op)) 00867 { 00868 bAnimContext ac; 00869 00870 /* get editor data */ 00871 if (ANIM_animdata_get_context(C, &ac) == 0) 00872 return OPERATOR_CANCELLED; 00873 00874 /* delete keyframes */ 00875 delete_graph_keys(&ac); 00876 00877 /* validate keyframes after editing */ 00878 ANIM_editkeyframes_refresh(&ac); 00879 00880 /* set notifier that keyframes have changed */ 00881 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00882 00883 return OPERATOR_FINISHED; 00884 } 00885 00886 void GRAPH_OT_delete (wmOperatorType *ot) 00887 { 00888 /* identifiers */ 00889 ot->name= "Delete Keyframes"; 00890 ot->idname= "GRAPH_OT_delete"; 00891 ot->description= "Remove all selected keyframes"; 00892 00893 /* api callbacks */ 00894 ot->invoke= WM_operator_confirm; 00895 ot->exec= graphkeys_delete_exec; 00896 ot->poll= graphop_editable_keyframes_poll; 00897 00898 /* flags */ 00899 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00900 } 00901 00902 /* ******************** Clean Keyframes Operator ************************* */ 00903 00904 static void clean_graph_keys (bAnimContext *ac, float thresh) 00905 { 00906 ListBase anim_data = {NULL, NULL}; 00907 bAnimListElem *ale; 00908 int filter; 00909 00910 /* filter data */ 00911 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); 00912 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00913 00914 /* loop through filtered data and clean curves */ 00915 for (ale= anim_data.first; ale; ale= ale->next) 00916 clean_fcurve((FCurve *)ale->key_data, thresh); 00917 00918 /* free temp data */ 00919 BLI_freelistN(&anim_data); 00920 } 00921 00922 /* ------------------- */ 00923 00924 static int graphkeys_clean_exec(bContext *C, wmOperator *op) 00925 { 00926 bAnimContext ac; 00927 float thresh; 00928 00929 /* get editor data */ 00930 if (ANIM_animdata_get_context(C, &ac) == 0) 00931 return OPERATOR_CANCELLED; 00932 00933 /* get cleaning threshold */ 00934 thresh= RNA_float_get(op->ptr, "threshold"); 00935 00936 /* clean keyframes */ 00937 clean_graph_keys(&ac, thresh); 00938 00939 /* validate keyframes after editing */ 00940 ANIM_editkeyframes_refresh(&ac); 00941 00942 /* set notifier that keyframes have changed */ 00943 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00944 00945 return OPERATOR_FINISHED; 00946 } 00947 00948 void GRAPH_OT_clean (wmOperatorType *ot) 00949 { 00950 /* identifiers */ 00951 ot->name= "Clean Keyframes"; 00952 ot->idname= "GRAPH_OT_clean"; 00953 ot->description= "Simplify F-Curves by removing closely spaced keyframes"; 00954 00955 /* api callbacks */ 00956 //ot->invoke= // XXX we need that number popup for this! 00957 ot->exec= graphkeys_clean_exec; 00958 ot->poll= graphop_editable_keyframes_poll; 00959 00960 /* flags */ 00961 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00962 00963 /* properties */ 00964 ot->prop= RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f); 00965 } 00966 00967 /* ******************** Bake F-Curve Operator *********************** */ 00968 /* This operator bakes the data of the selected F-Curves to F-Points */ 00969 00970 /* Bake each F-Curve into a set of samples */ 00971 static void bake_graph_curves (bAnimContext *ac, int start, int end) 00972 { 00973 ListBase anim_data = {NULL, NULL}; 00974 bAnimListElem *ale; 00975 int filter; 00976 00977 /* filter data */ 00978 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 00979 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00980 00981 /* loop through filtered data and add keys between selected keyframes on every frame */ 00982 for (ale= anim_data.first; ale; ale= ale->next) { 00983 FCurve *fcu= (FCurve *)ale->key_data; 00984 ChannelDriver *driver= fcu->driver; 00985 00986 /* disable driver so that it don't muck up the sampling process */ 00987 fcu->driver= NULL; 00988 00989 /* create samples */ 00990 fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve); 00991 00992 /* restore driver */ 00993 fcu->driver= driver; 00994 } 00995 00996 /* admin and redraws */ 00997 BLI_freelistN(&anim_data); 00998 } 00999 01000 /* ------------------- */ 01001 01002 static int graphkeys_bake_exec(bContext *C, wmOperator *UNUSED(op)) 01003 { 01004 bAnimContext ac; 01005 Scene *scene= NULL; 01006 int start, end; 01007 01008 /* get editor data */ 01009 if (ANIM_animdata_get_context(C, &ac) == 0) 01010 return OPERATOR_CANCELLED; 01011 01012 /* for now, init start/end from preview-range extents */ 01013 // TODO: add properties for this 01014 scene= ac.scene; 01015 start= PSFRA; 01016 end= PEFRA; 01017 01018 /* bake keyframes */ 01019 bake_graph_curves(&ac, start, end); 01020 01021 /* validate keyframes after editing */ 01022 ANIM_editkeyframes_refresh(&ac); 01023 01024 /* set notifier that keyframes have changed */ 01025 // NOTE: some distinction between order/number of keyframes and type should be made? 01026 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 01027 01028 return OPERATOR_FINISHED; 01029 } 01030 01031 void GRAPH_OT_bake (wmOperatorType *ot) 01032 { 01033 /* identifiers */ 01034 ot->name= "Bake Curve"; 01035 ot->idname= "GRAPH_OT_bake"; 01036 ot->description= "Bake selected F-Curves to a set of sampled points defining a similar curve"; 01037 01038 /* api callbacks */ 01039 ot->invoke= WM_operator_confirm; // FIXME... 01040 ot->exec= graphkeys_bake_exec; 01041 ot->poll= graphop_selected_fcurve_poll; 01042 01043 /* flags */ 01044 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01045 01046 // todo: add props for start/end frames 01047 } 01048 01049 #ifdef WITH_AUDASPACE 01050 01051 /* ******************** Sound Bake F-Curve Operator *********************** */ 01052 /* This operator bakes the given sound to the selected F-Curves */ 01053 01054 /* ------------------- */ 01055 01056 /* Custom data storage passed to the F-Sample-ing function, 01057 * which provides the necessary info for baking the sound 01058 */ 01059 typedef struct tSoundBakeInfo { 01060 float *samples; 01061 int length; 01062 int cfra; 01063 } tSoundBakeInfo; 01064 01065 /* ------------------- */ 01066 01067 /* Sampling callback used to determine the value from the sound to 01068 * save in the F-Curve at the specified frame 01069 */ 01070 static float fcurve_samplingcb_sound (FCurve *UNUSED(fcu), void *data, float evaltime) 01071 { 01072 tSoundBakeInfo *sbi= (tSoundBakeInfo *)data; 01073 01074 int position = evaltime - sbi->cfra; 01075 if((position < 0) || (position >= sbi->length)) 01076 return 0.0f; 01077 01078 return sbi->samples[position]; 01079 } 01080 01081 /* ------------------- */ 01082 01083 static int graphkeys_sound_bake_exec(bContext *C, wmOperator *op) 01084 { 01085 bAnimContext ac; 01086 ListBase anim_data = {NULL, NULL}; 01087 bAnimListElem *ale; 01088 int filter; 01089 01090 tSoundBakeInfo sbi; 01091 Scene *scene= NULL; 01092 int start, end; 01093 01094 char path[FILE_MAX]; 01095 01096 /* get editor data */ 01097 if (ANIM_animdata_get_context(C, &ac) == 0) 01098 return OPERATOR_CANCELLED; 01099 01100 RNA_string_get(op->ptr, "filepath", path); 01101 01102 scene= ac.scene; /* current scene */ 01103 01104 /* store necessary data for the baking steps */ 01105 sbi.samples = AUD_readSoundBuffer(path, 01106 RNA_float_get(op->ptr, "low"), 01107 RNA_float_get(op->ptr, "high"), 01108 RNA_float_get(op->ptr, "attack"), 01109 RNA_float_get(op->ptr, "release"), 01110 RNA_float_get(op->ptr, "threshold"), 01111 RNA_boolean_get(op->ptr, "accumulate"), 01112 RNA_boolean_get(op->ptr, "use_additive"), 01113 RNA_boolean_get(op->ptr, "square"), 01114 RNA_float_get(op->ptr, "sthreshold"), 01115 FPS, &sbi.length); 01116 01117 if (sbi.samples == NULL) { 01118 BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); 01119 return OPERATOR_CANCELLED; 01120 } 01121 01122 /* determine extents of the baking */ 01123 sbi.cfra = start = CFRA; 01124 end = CFRA + sbi.length - 1; 01125 01126 /* filter anim channels */ 01127 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 01128 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 01129 01130 /* loop through all selected F-Curves, replacing its data with the sound samples */ 01131 for (ale= anim_data.first; ale; ale= ale->next) { 01132 FCurve *fcu= (FCurve *)ale->key_data; 01133 01134 /* sample the sound */ 01135 fcurve_store_samples(fcu, &sbi, start, end, fcurve_samplingcb_sound); 01136 } 01137 01138 /* free sample data */ 01139 free(sbi.samples); 01140 01141 /* admin and redraws */ 01142 BLI_freelistN(&anim_data); 01143 01144 /* validate keyframes after editing */ 01145 ANIM_editkeyframes_refresh(&ac); 01146 01147 /* set notifier that 'keyframes' have changed */ 01148 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 01149 01150 return OPERATOR_FINISHED; 01151 } 01152 01153 #else //WITH_AUDASPACE 01154 01155 static int graphkeys_sound_bake_exec(bContext *UNUSED(C), wmOperator *op) 01156 { 01157 BKE_report(op->reports, RPT_ERROR, "Compiled without sound support"); 01158 01159 return OPERATOR_CANCELLED; 01160 } 01161 01162 #endif //WITH_AUDASPACE 01163 01164 static int graphkeys_sound_bake_invoke (bContext *C, wmOperator *op, wmEvent *event) 01165 { 01166 bAnimContext ac; 01167 01168 /* verify editor data */ 01169 if (ANIM_animdata_get_context(C, &ac) == 0) 01170 return OPERATOR_CANCELLED; 01171 01172 return WM_operator_filesel(C, op, event); 01173 } 01174 01175 void GRAPH_OT_sound_bake (wmOperatorType *ot) 01176 { 01177 /* identifiers */ 01178 ot->name= "Bake Sound to F-Curves"; 01179 ot->idname= "GRAPH_OT_sound_bake"; 01180 ot->description= "Bakes a sound wave to selected F-Curves"; 01181 01182 /* api callbacks */ 01183 ot->invoke= graphkeys_sound_bake_invoke; 01184 ot->exec= graphkeys_sound_bake_exec; 01185 ot->poll= graphop_selected_fcurve_poll; 01186 01187 /* flags */ 01188 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01189 01190 /* properties */ 01191 WM_operator_properties_filesel(ot, FOLDERFILE|SOUNDFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH); 01192 RNA_def_float(ot->srna, "low", 0.0f, 0.0, 100000.0, "Lowest frequency", "", 0.1, 1000.00); 01193 RNA_def_float(ot->srna, "high", 100000.0, 0.0, 100000.0, "Highest frequency", "", 0.1, 1000.00); 01194 RNA_def_float(ot->srna, "attack", 0.005, 0.0, 2.0, "Attack time", "", 0.01, 0.1); 01195 RNA_def_float(ot->srna, "release", 0.2, 0.0, 5.0, "Release time", "", 0.01, 0.2); 01196 RNA_def_float(ot->srna, "threshold", 0.0, 0.0, 1.0, "Threshold", "", 0.01, 0.1); 01197 RNA_def_boolean(ot->srna, "accumulate", 0, "Accumulate", ""); 01198 RNA_def_boolean(ot->srna, "use_additive", 0, "Additive", ""); 01199 RNA_def_boolean(ot->srna, "square", 0, "Square", ""); 01200 RNA_def_float(ot->srna, "sthreshold", 0.1, 0.0, 1.0, "Square Threshold", "", 0.01, 0.1); 01201 } 01202 01203 /* ******************** Sample Keyframes Operator *********************** */ 01204 /* This operator 'bakes' the values of the curve into new keyframes between pairs 01205 * of selected keyframes. It is useful for creating keyframes for tweaking overlap. 01206 */ 01207 01208 /* Evaluates the curves between each selected keyframe on each frame, and keys the value */ 01209 static void sample_graph_keys (bAnimContext *ac) 01210 { 01211 ListBase anim_data = {NULL, NULL}; 01212 bAnimListElem *ale; 01213 int filter; 01214 01215 /* filter data */ 01216 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 01217 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 01218 01219 /* loop through filtered data and add keys between selected keyframes on every frame */ 01220 for (ale= anim_data.first; ale; ale= ale->next) 01221 sample_fcurve((FCurve *)ale->key_data); 01222 01223 /* admin and redraws */ 01224 BLI_freelistN(&anim_data); 01225 } 01226 01227 /* ------------------- */ 01228 01229 static int graphkeys_sample_exec(bContext *C, wmOperator *UNUSED(op)) 01230 { 01231 bAnimContext ac; 01232 01233 /* get editor data */ 01234 if (ANIM_animdata_get_context(C, &ac) == 0) 01235 return OPERATOR_CANCELLED; 01236 01237 /* sample keyframes */ 01238 sample_graph_keys(&ac); 01239 01240 /* validate keyframes after editing */ 01241 ANIM_editkeyframes_refresh(&ac); 01242 01243 /* set notifier that keyframes have changed */ 01244 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 01245 01246 return OPERATOR_FINISHED; 01247 } 01248 01249 void GRAPH_OT_sample (wmOperatorType *ot) 01250 { 01251 /* identifiers */ 01252 ot->name= "Sample Keyframes"; 01253 ot->idname= "GRAPH_OT_sample"; 01254 ot->description= "Add keyframes on every frame between the selected keyframes"; 01255 01256 /* api callbacks */ 01257 ot->exec= graphkeys_sample_exec; 01258 ot->poll= graphop_editable_keyframes_poll; 01259 01260 /* flags */ 01261 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01262 } 01263 01264 01265 /* ************************************************************************** */ 01266 /* SETTINGS STUFF */ 01267 01268 /* ******************** Set Extrapolation-Type Operator *********************** */ 01269 01270 /* defines for make/clear cyclic extrapolation tools */ 01271 #define MAKE_CYCLIC_EXPO -1 01272 #define CLEAR_CYCLIC_EXPO -2 01273 01274 /* defines for set extrapolation-type for selected keyframes tool */ 01275 static EnumPropertyItem prop_graphkeys_expo_types[] = { 01276 {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", 0, "Constant Extrapolation", ""}, 01277 {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", 0, "Linear Extrapolation", ""}, 01278 01279 {MAKE_CYCLIC_EXPO, "MAKE_CYCLIC", 0, "Make Cyclic (F-Modifier)", "Add Cycles F-Modifier if one doesn't exist already"}, 01280 {CLEAR_CYCLIC_EXPO, "CLEAR_CYCLIC", 0, "Clear Cyclic (F-Modifier)", "Remove Cycles F-Modifier if not needed anymore"}, 01281 {0, NULL, 0, NULL, NULL} 01282 }; 01283 01284 /* this function is responsible for setting extrapolation mode for keyframes */ 01285 static void setexpo_graph_keys(bAnimContext *ac, short mode) 01286 { 01287 ListBase anim_data = {NULL, NULL}; 01288 bAnimListElem *ale; 01289 int filter; 01290 01291 /* filter data */ 01292 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 01293 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 01294 01295 /* loop through setting mode per F-Curve */ 01296 for (ale= anim_data.first; ale; ale= ale->next) { 01297 FCurve *fcu= (FCurve *)ale->data; 01298 01299 if (mode >= 0) { 01300 /* just set mode setting */ 01301 fcu->extend= mode; 01302 } 01303 else { 01304 /* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation 01305 * without having to go through FModifier UI in Graph Editor to do so 01306 */ 01307 if (mode == MAKE_CYCLIC_EXPO) { 01308 /* only add if one doesn't exist */ 01309 if (list_has_suitable_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, -1) == 0) { 01310 // TODO: add some more preset versions which set different extrapolation options? 01311 add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES); 01312 } 01313 } 01314 else if (mode == CLEAR_CYCLIC_EXPO) { 01315 /* remove all the modifiers fitting this description */ 01316 FModifier *fcm, *fcn=NULL; 01317 01318 for (fcm = fcu->modifiers.first; fcm; fcm = fcn) { 01319 fcn = fcm->next; 01320 01321 if (fcm->type == FMODIFIER_TYPE_CYCLES) 01322 remove_fmodifier(&fcu->modifiers, fcm); 01323 } 01324 } 01325 } 01326 } 01327 01328 /* cleanup */ 01329 BLI_freelistN(&anim_data); 01330 } 01331 01332 /* ------------------- */ 01333 01334 static int graphkeys_expo_exec(bContext *C, wmOperator *op) 01335 { 01336 bAnimContext ac; 01337 short mode; 01338 01339 /* get editor data */ 01340 if (ANIM_animdata_get_context(C, &ac) == 0) 01341 return OPERATOR_CANCELLED; 01342 01343 /* get handle setting mode */ 01344 mode= RNA_enum_get(op->ptr, "type"); 01345 01346 /* set handle type */ 01347 setexpo_graph_keys(&ac, mode); 01348 01349 /* validate keyframes after editing */ 01350 ANIM_editkeyframes_refresh(&ac); 01351 01352 /* set notifier that keyframe properties have changed */ 01353 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL); 01354 01355 return OPERATOR_FINISHED; 01356 } 01357 01358 void GRAPH_OT_extrapolation_type (wmOperatorType *ot) 01359 { 01360 /* identifiers */ 01361 ot->name= "Set Keyframe Extrapolation"; 01362 ot->idname= "GRAPH_OT_extrapolation_type"; 01363 ot->description= "Set extrapolation mode for selected F-Curves"; 01364 01365 /* api callbacks */ 01366 ot->invoke= WM_menu_invoke; 01367 ot->exec= graphkeys_expo_exec; 01368 ot->poll= graphop_editable_keyframes_poll; 01369 01370 /* flags */ 01371 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01372 01373 /* id-props */ 01374 ot->prop= RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", ""); 01375 } 01376 01377 /* ******************** Set Interpolation-Type Operator *********************** */ 01378 01379 /* this function is responsible for setting interpolation mode for keyframes */ 01380 static void setipo_graph_keys(bAnimContext *ac, short mode) 01381 { 01382 ListBase anim_data = {NULL, NULL}; 01383 bAnimListElem *ale; 01384 int filter; 01385 KeyframeEditFunc set_cb= ANIM_editkeyframes_ipo(mode); 01386 01387 /* filter data */ 01388 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 01389 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 01390 01391 /* loop through setting BezTriple interpolation 01392 * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here... 01393 */ 01394 for (ale= anim_data.first; ale; ale= ale->next) 01395 ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve); 01396 01397 /* cleanup */ 01398 BLI_freelistN(&anim_data); 01399 } 01400 01401 /* ------------------- */ 01402 01403 static int graphkeys_ipo_exec(bContext *C, wmOperator *op) 01404 { 01405 bAnimContext ac; 01406 short mode; 01407 01408 /* get editor data */ 01409 if (ANIM_animdata_get_context(C, &ac) == 0) 01410 return OPERATOR_CANCELLED; 01411 01412 /* get handle setting mode */ 01413 mode= RNA_enum_get(op->ptr, "type"); 01414 01415 /* set handle type */ 01416 setipo_graph_keys(&ac, mode); 01417 01418 /* validate keyframes after editing */ 01419 ANIM_editkeyframes_refresh(&ac); 01420 01421 /* set notifier that keyframe properties have changed */ 01422 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL); 01423 01424 return OPERATOR_FINISHED; 01425 } 01426 01427 void GRAPH_OT_interpolation_type (wmOperatorType *ot) 01428 { 01429 /* identifiers */ 01430 ot->name= "Set Keyframe Interpolation"; 01431 ot->idname= "GRAPH_OT_interpolation_type"; 01432 ot->description= "Set interpolation mode for the F-Curve segments starting from the selected keyframes"; 01433 01434 /* api callbacks */ 01435 ot->invoke= WM_menu_invoke; 01436 ot->exec= graphkeys_ipo_exec; 01437 ot->poll= graphop_editable_keyframes_poll; 01438 01439 /* flags */ 01440 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01441 01442 /* id-props */ 01443 ot->prop= RNA_def_enum(ot->srna, "type", beztriple_interpolation_mode_items, 0, "Type", ""); 01444 } 01445 01446 /* ******************** Set Handle-Type Operator *********************** */ 01447 01448 /* this function is responsible for setting handle-type of selected keyframes */ 01449 static void sethandles_graph_keys(bAnimContext *ac, short mode) 01450 { 01451 ListBase anim_data = {NULL, NULL}; 01452 bAnimListElem *ale; 01453 int filter; 01454 01455 KeyframeEditFunc edit_cb= ANIM_editkeyframes_handles(mode); 01456 KeyframeEditFunc sel_cb= ANIM_editkeyframes_ok(BEZT_OK_SELECTED); 01457 01458 /* filter data */ 01459 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 01460 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 01461 01462 /* loop through setting flags for handles 01463 * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here... 01464 */ 01465 for (ale= anim_data.first; ale; ale= ale->next) { 01466 FCurve *fcu= (FCurve *)ale->key_data; 01467 01468 /* any selected keyframes for editing? */ 01469 if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) { 01470 /* change type of selected handles */ 01471 ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve); 01472 } 01473 } 01474 01475 /* cleanup */ 01476 BLI_freelistN(&anim_data); 01477 } 01478 /* ------------------- */ 01479 01480 static int graphkeys_handletype_exec(bContext *C, wmOperator *op) 01481 { 01482 bAnimContext ac; 01483 short mode; 01484 01485 /* get editor data */ 01486 if (ANIM_animdata_get_context(C, &ac) == 0) 01487 return OPERATOR_CANCELLED; 01488 01489 /* get handle setting mode */ 01490 mode= RNA_enum_get(op->ptr, "type"); 01491 01492 /* set handle type */ 01493 sethandles_graph_keys(&ac, mode); 01494 01495 /* validate keyframes after editing */ 01496 ANIM_editkeyframes_refresh(&ac); 01497 01498 /* set notifier that keyframe properties have changed */ 01499 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL); 01500 01501 return OPERATOR_FINISHED; 01502 } 01503 01504 void GRAPH_OT_handle_type (wmOperatorType *ot) 01505 { 01506 /* identifiers */ 01507 ot->name= "Set Keyframe Handle Type"; 01508 ot->idname= "GRAPH_OT_handle_type"; 01509 ot->description= "Set type of handle for selected keyframes"; 01510 01511 /* api callbacks */ 01512 ot->invoke= WM_menu_invoke; 01513 ot->exec= graphkeys_handletype_exec; 01514 ot->poll= graphop_editable_keyframes_poll; 01515 01516 /* flags */ 01517 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01518 01519 /* id-props */ 01520 ot->prop= RNA_def_enum(ot->srna, "type", keyframe_handle_type_items, 0, "Type", ""); 01521 } 01522 01523 /* ************************************************************************** */ 01524 /* TRANSFORM STUFF */ 01525 01526 /* ***************** 'Euler Filter' Operator **************************** */ 01527 /* Euler filter tools (as seen in Maya), are necessary for working with 'baked' 01528 * rotation curves (with Euler rotations). The main purpose of such tools is to 01529 * resolve any discontinuities that may arise in the curves due to the clamping 01530 * of values to -180 degrees to 180 degrees. 01531 */ 01532 01533 /* set of three euler-rotation F-Curves */ 01534 typedef struct tEulerFilter { 01535 struct tEulerFilter *next, *prev; 01536 01537 ID *id; /* ID-block which owns the channels */ 01538 FCurve *(fcurves[3]); /* 3 Pointers to F-Curves */ 01539 char *rna_path; /* Pointer to one of the RNA Path's used by one of the F-Curves */ 01540 } tEulerFilter; 01541 01542 static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op) 01543 { 01544 bAnimContext ac; 01545 01546 ListBase anim_data= {NULL, NULL}; 01547 bAnimListElem *ale; 01548 int filter; 01549 01550 ListBase eulers = {NULL, NULL}; 01551 tEulerFilter *euf= NULL; 01552 int groups=0, failed=0; 01553 01554 /* get editor data */ 01555 if (ANIM_animdata_get_context(C, &ac) == 0) 01556 return OPERATOR_CANCELLED; 01557 01558 /* The process is done in two passes: 01559 * 1) Sets of three related rotation curves are identified from the selected channels, 01560 * and are stored as a single 'operation unit' for the next step 01561 * 2) Each set of three F-Curves is processed for each keyframe, with the values being 01562 * processed as necessary 01563 */ 01564 01565 /* step 1: extract only the rotation f-curves */ 01566 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 01567 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 01568 01569 for (ale= anim_data.first; ale; ale= ale->next) { 01570 FCurve *fcu = (FCurve *)ale->data; 01571 01572 /* check if this is an appropriate F-Curve 01573 * - only rotation curves 01574 * - for pchan curves, make sure we're only using the euler curves 01575 */ 01576 if (strstr(fcu->rna_path, "rotation_euler") == NULL) 01577 continue; 01578 else if (ELEM3(fcu->array_index, 0, 1, 2) == 0) { 01579 BKE_reportf(op->reports, RPT_WARNING, 01580 "Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)", 01581 (ale->id)? ale->id->name:"<No ID>", fcu->rna_path, fcu->array_index); 01582 continue; 01583 } 01584 01585 /* optimisation: assume that xyz curves will always be stored consecutively, 01586 * so if the paths or the ID's don't match up, then a curve needs to be added 01587 * to a new group 01588 */ 01589 if ((euf) && (euf->id == ale->id) && (strcmp(euf->rna_path, fcu->rna_path)==0)) { 01590 /* this should be fine to add to the existing group then */ 01591 euf->fcurves[fcu->array_index]= fcu; 01592 } 01593 else { 01594 /* just add to a new block */ 01595 euf= MEM_callocN(sizeof(tEulerFilter), "tEulerFilter"); 01596 BLI_addtail(&eulers, euf); 01597 groups++; 01598 01599 euf->id= ale->id; 01600 euf->rna_path = fcu->rna_path; /* this should be safe, since we're only using it for a short time */ 01601 euf->fcurves[fcu->array_index]= fcu; 01602 } 01603 } 01604 BLI_freelistN(&anim_data); 01605 01606 if (groups == 0) { 01607 BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up"); 01608 return OPERATOR_CANCELLED; 01609 } 01610 01611 /* step 2: go through each set of curves, processing the values at each keyframe 01612 * - it is assumed that there must be a full set of keyframes at each keyframe position 01613 */ 01614 for (euf= eulers.first; euf; euf= euf->next) { 01615 int f; 01616 01617 /* sanity check: ensure that there are enough F-Curves to work on in this group */ 01618 // TODO: also enforce assumption that there be a full set of keyframes at each position by ensuring that totvert counts are same? 01619 if (ELEM3(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) { 01620 /* report which components are missing */ 01621 BKE_reportf(op->reports, RPT_WARNING, 01622 "Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'", 01623 (euf->fcurves[0]==NULL)? "X":"", 01624 (euf->fcurves[1]==NULL)? "Y":"", 01625 (euf->fcurves[2]==NULL)? "Z":"", 01626 euf->id->name, euf->rna_path); 01627 01628 /* keep track of number of failed sets, and carry on to next group */ 01629 failed++; 01630 continue; 01631 } 01632 01633 /* simple method: just treat any difference between keys of greater than 180 degrees as being a flip */ 01634 // FIXME: there are more complicated methods that will be needed to fix more cases than just some 01635 for (f = 0; f < 3; f++) { 01636 FCurve *fcu = euf->fcurves[f]; 01637 BezTriple *bezt, *prev=NULL; 01638 unsigned int i; 01639 01640 /* skip if not enough vets to do a decent analysis of... */ 01641 if (fcu->totvert <= 2) 01642 continue; 01643 01644 /* prev follows bezt, bezt = "current" point to be fixed */ 01645 for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, prev=bezt, bezt++) { 01646 /* our method depends on determining a "difference" from the previous vert */ 01647 if (prev == NULL) 01648 continue; 01649 01650 /* > 180 degree flip? */ 01651 if (fabs(prev->vec[1][1] - bezt->vec[1][1]) >= M_PI) { 01652 /* 360 degrees to add/subtract frame value until difference is acceptably small that there's no more flip */ 01653 const float fac = 2.0f * (float)M_PI; 01654 01655 if (prev->vec[1][1] > bezt->vec[1][1]) { 01656 while (fabsf(bezt->vec[1][1] - prev->vec[1][1]) >= (float)M_PI) { 01657 bezt->vec[0][1] += fac; 01658 bezt->vec[1][1] += fac; 01659 bezt->vec[2][1] += fac; 01660 } 01661 } 01662 else /* if (prev->vec[1][1] < bezt->vec[1][1]) */ { 01663 while (fabsf(bezt->vec[1][1] - prev->vec[1][1]) >= (float)M_PI) { 01664 bezt->vec[0][1] -= fac; 01665 bezt->vec[1][1] -= fac; 01666 bezt->vec[2][1] -= fac; 01667 } 01668 } 01669 } 01670 } 01671 } 01672 } 01673 BLI_freelistN(&eulers); 01674 01675 /* updates + finishing warnings */ 01676 if (failed == groups) { 01677 BKE_report(op->reports, RPT_ERROR, 01678 "No Euler Rotations could be corrected, ensure each rotation has keys for all components, and that F-Curves for these are in consecutive XYZ order and selected"); 01679 return OPERATOR_CANCELLED; 01680 } 01681 else { 01682 if (failed) { 01683 BKE_report(op->reports, RPT_ERROR, 01684 "Some Euler Rotations couldn't be corrected due to missing/unselected/out-of-order F-Curves, ensure each rotation has keys for all components, and that F-Curves for these are in consecutive XYZ order and selected"); 01685 } 01686 01687 /* validate keyframes after editing */ 01688 ANIM_editkeyframes_refresh(&ac); 01689 01690 /* set notifier that keyframes have changed */ 01691 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 01692 01693 /* done at last */ 01694 return OPERATOR_FINISHED; 01695 } 01696 } 01697 01698 void GRAPH_OT_euler_filter (wmOperatorType *ot) 01699 { 01700 /* identifiers */ 01701 ot->name= "Euler Discontinuity Filter"; 01702 ot->idname= "GRAPH_OT_euler_filter"; 01703 ot->description= "Fixes the most common causes of gimbal lock in the selected Euler Rotation F-Curves"; 01704 01705 /* api callbacks */ 01706 ot->exec= graphkeys_euler_filter_exec; 01707 ot->poll= graphop_editable_keyframes_poll; 01708 01709 /* flags */ 01710 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01711 } 01712 01713 /* ***************** Jump to Selected Frames Operator *********************** */ 01714 01715 /* snap current-frame indicator to 'average time' of selected keyframe */ 01716 static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op)) 01717 { 01718 bAnimContext ac; 01719 ListBase anim_data= {NULL, NULL}; 01720 bAnimListElem *ale; 01721 int filter; 01722 KeyframeEditData ked; 01723 01724 /* get editor data */ 01725 if (ANIM_animdata_get_context(C, &ac) == 0) 01726 return OPERATOR_CANCELLED; 01727 01728 /* init edit data */ 01729 memset(&ked, 0, sizeof(KeyframeEditData)); 01730 01731 /* loop over action data, averaging values */ 01732 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); 01733 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 01734 01735 for (ale= anim_data.first; ale; ale= ale->next) { 01736 AnimData *adt= ANIM_nla_mapping_get(&ac, ale); 01737 01738 /* apply unit corrections */ 01739 ANIM_unit_mapping_apply_fcurve(ac.scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYKEYS); 01740 01741 if (adt) { 01742 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 01743 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL); 01744 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); 01745 } 01746 else 01747 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL); 01748 01749 /* unapply unit corrections */ 01750 ANIM_unit_mapping_apply_fcurve(ac.scene, ale->id, ale->key_data, ANIM_UNITCONV_RESTORE|ANIM_UNITCONV_ONLYKEYS); 01751 } 01752 01753 BLI_freelistN(&anim_data); 01754 01755 /* set the new current frame and cursor values, based on the average time and value */ 01756 if (ked.i1) { 01757 SpaceIpo *sipo= (SpaceIpo *)ac.sl; 01758 Scene *scene= ac.scene; 01759 01760 /* take the average values, rounding to the nearest int for the current frame */ 01761 CFRA= (int)floor((ked.f1 / ked.i1) + 0.5f); 01762 SUBFRA= 0.f; 01763 sipo->cursorVal= ked.f2 / (float)ked.i1; 01764 } 01765 01766 /* set notifier that things have changed */ 01767 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, ac.scene); 01768 01769 return OPERATOR_FINISHED; 01770 } 01771 01772 void GRAPH_OT_frame_jump (wmOperatorType *ot) 01773 { 01774 /* identifiers */ 01775 ot->name= "Jump to Frame"; 01776 ot->idname= "GRAPH_OT_frame_jump"; 01777 ot->description= "Set the current frame to the average frame of the selected keyframes"; 01778 01779 /* api callbacks */ 01780 ot->exec= graphkeys_framejump_exec; 01781 ot->poll= graphop_visible_keyframes_poll; 01782 01783 /* flags */ 01784 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01785 } 01786 01787 /* ******************** Snap Keyframes Operator *********************** */ 01788 01789 /* defines for snap keyframes tool */ 01790 static EnumPropertyItem prop_graphkeys_snap_types[] = { 01791 {GRAPHKEYS_SNAP_CFRA, "CFRA", 0, "Current Frame", ""}, 01792 {GRAPHKEYS_SNAP_VALUE, "VALUE", 0, "Cursor Value", ""}, 01793 {GRAPHKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry? 01794 {GRAPHKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry? 01795 {GRAPHKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""}, 01796 {GRAPHKEYS_SNAP_HORIZONTAL, "HORIZONTAL", 0, "Flatten Handles", ""}, 01797 {0, NULL, 0, NULL, NULL} 01798 }; 01799 01800 /* this function is responsible for snapping keyframes to frame-times */ 01801 static void snap_graph_keys(bAnimContext *ac, short mode) 01802 { 01803 ListBase anim_data = {NULL, NULL}; 01804 bAnimListElem *ale; 01805 int filter; 01806 01807 KeyframeEditData ked; 01808 KeyframeEditFunc edit_cb; 01809 01810 /* filter data */ 01811 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 01812 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 01813 01814 /* get beztriple editing callbacks */ 01815 edit_cb= ANIM_editkeyframes_snap(mode); 01816 01817 memset(&ked, 0, sizeof(KeyframeEditData)); 01818 ked.scene= ac->scene; 01819 if (mode == GRAPHKEYS_SNAP_NEAREST_MARKER) { 01820 ked.list.first= (ac->markers) ? ac->markers->first : NULL; 01821 ked.list.last= (ac->markers) ? ac->markers->last : NULL; 01822 } 01823 else if (mode == GRAPHKEYS_SNAP_VALUE) { 01824 SpaceIpo *sipo= (SpaceIpo *)ac->sl; 01825 ked.f1= (sipo) ? sipo->cursorVal : 0.0f; 01826 } 01827 01828 /* snap keyframes */ 01829 for (ale= anim_data.first; ale; ale= ale->next) { 01830 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 01831 01832 /* apply unit corrections */ 01833 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, 0); 01834 01835 if (adt) { 01836 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 01837 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); 01838 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); 01839 } 01840 else 01841 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); 01842 01843 /* apply unit corrections */ 01844 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_RESTORE); 01845 } 01846 01847 BLI_freelistN(&anim_data); 01848 } 01849 01850 /* ------------------- */ 01851 01852 static int graphkeys_snap_exec(bContext *C, wmOperator *op) 01853 { 01854 bAnimContext ac; 01855 short mode; 01856 01857 /* get editor data */ 01858 if (ANIM_animdata_get_context(C, &ac) == 0) 01859 return OPERATOR_CANCELLED; 01860 01861 /* get snapping mode */ 01862 mode= RNA_enum_get(op->ptr, "type"); 01863 01864 /* snap keyframes */ 01865 snap_graph_keys(&ac, mode); 01866 01867 /* validate keyframes after editing */ 01868 ANIM_editkeyframes_refresh(&ac); 01869 01870 /* set notifier that keyframes have changed */ 01871 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 01872 01873 return OPERATOR_FINISHED; 01874 } 01875 01876 void GRAPH_OT_snap (wmOperatorType *ot) 01877 { 01878 /* identifiers */ 01879 ot->name= "Snap Keys"; 01880 ot->idname= "GRAPH_OT_snap"; 01881 ot->description= "Snap selected keyframes to the chosen times/values"; 01882 01883 /* api callbacks */ 01884 ot->invoke= WM_menu_invoke; 01885 ot->exec= graphkeys_snap_exec; 01886 ot->poll= graphop_editable_keyframes_poll; 01887 01888 /* flags */ 01889 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01890 01891 /* id-props */ 01892 ot->prop= RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", ""); 01893 } 01894 01895 /* ******************** Mirror Keyframes Operator *********************** */ 01896 01897 /* defines for mirror keyframes tool */ 01898 static EnumPropertyItem prop_graphkeys_mirror_types[] = { 01899 {GRAPHKEYS_MIRROR_CFRA, "CFRA", 0, "By Times over Current Frame", ""}, 01900 {GRAPHKEYS_MIRROR_VALUE, "VALUE", 0, "By Values over Cursor Value", ""}, 01901 {GRAPHKEYS_MIRROR_YAXIS, "YAXIS", 0, "By Times over Time=0", ""}, 01902 {GRAPHKEYS_MIRROR_XAXIS, "XAXIS", 0, "By Values over Value=0", ""}, 01903 {GRAPHKEYS_MIRROR_MARKER, "MARKER", 0, "By Times over First Selected Marker", ""}, 01904 {0, NULL, 0, NULL, NULL} 01905 }; 01906 01907 /* this function is responsible for mirroring keyframes */ 01908 static void mirror_graph_keys(bAnimContext *ac, short mode) 01909 { 01910 ListBase anim_data = {NULL, NULL}; 01911 bAnimListElem *ale; 01912 int filter; 01913 01914 KeyframeEditData ked; 01915 KeyframeEditFunc edit_cb; 01916 01917 /* get beztriple editing callbacks */ 01918 edit_cb= ANIM_editkeyframes_mirror(mode); 01919 01920 memset(&ked, 0, sizeof(KeyframeEditData)); 01921 ked.scene= ac->scene; 01922 01923 /* for 'first selected marker' mode, need to find first selected marker first! */ 01924 // XXX should this be made into a helper func in the API? 01925 if (mode == GRAPHKEYS_MIRROR_MARKER) { 01926 TimeMarker *marker= NULL; 01927 01928 /* find first selected marker */ 01929 marker= ED_markers_get_first_selected(ac->markers); 01930 01931 /* store marker's time (if available) */ 01932 if (marker) 01933 ked.f1= (float)marker->frame; 01934 else 01935 return; 01936 } 01937 else if (mode == GRAPHKEYS_MIRROR_VALUE) { 01938 SpaceIpo *sipo= (SpaceIpo *)ac->sl; 01939 ked.f1= (sipo) ? sipo->cursorVal : 0.0f; 01940 } 01941 01942 /* filter data */ 01943 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 01944 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 01945 01946 /* mirror keyframes */ 01947 for (ale= anim_data.first; ale; ale= ale->next) { 01948 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 01949 01950 /* apply unit corrections */ 01951 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYKEYS); 01952 01953 if (adt) { 01954 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 01955 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); 01956 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); 01957 } 01958 else 01959 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve); 01960 01961 /* unapply unit corrections */ 01962 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYKEYS|ANIM_UNITCONV_RESTORE); 01963 } 01964 01965 BLI_freelistN(&anim_data); 01966 } 01967 01968 /* ------------------- */ 01969 01970 static int graphkeys_mirror_exec(bContext *C, wmOperator *op) 01971 { 01972 bAnimContext ac; 01973 short mode; 01974 01975 /* get editor data */ 01976 if (ANIM_animdata_get_context(C, &ac) == 0) 01977 return OPERATOR_CANCELLED; 01978 01979 /* get mirroring mode */ 01980 mode= RNA_enum_get(op->ptr, "type"); 01981 01982 /* mirror keyframes */ 01983 mirror_graph_keys(&ac, mode); 01984 01985 /* validate keyframes after editing */ 01986 ANIM_editkeyframes_refresh(&ac); 01987 01988 /* set notifier that keyframes have changed */ 01989 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 01990 01991 return OPERATOR_FINISHED; 01992 } 01993 01994 void GRAPH_OT_mirror (wmOperatorType *ot) 01995 { 01996 /* identifiers */ 01997 ot->name= "Mirror Keys"; 01998 ot->idname= "GRAPH_OT_mirror"; 01999 ot->description= "Flip selected keyframes over the selected mirror line"; 02000 02001 /* api callbacks */ 02002 ot->invoke= WM_menu_invoke; 02003 ot->exec= graphkeys_mirror_exec; 02004 ot->poll= graphop_editable_keyframes_poll; 02005 02006 /* flags */ 02007 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02008 02009 /* id-props */ 02010 ot->prop= RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", ""); 02011 } 02012 02013 /* ******************** Smooth Keyframes Operator *********************** */ 02014 02015 static int graphkeys_smooth_exec(bContext *C, wmOperator *UNUSED(op)) 02016 { 02017 bAnimContext ac; 02018 ListBase anim_data = {NULL, NULL}; 02019 bAnimListElem *ale; 02020 int filter; 02021 02022 /* get editor data */ 02023 if (ANIM_animdata_get_context(C, &ac) == 0) 02024 return OPERATOR_CANCELLED; 02025 02026 /* filter data */ 02027 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 02028 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 02029 02030 /* smooth keyframes */ 02031 for (ale= anim_data.first; ale; ale= ale->next) { 02032 /* For now, we can only smooth by flattening handles AND smoothing curve values. 02033 * Perhaps the mode argument could be removed, as that functionality is offerred through 02034 * Snap->Flatten Handles anyway. 02035 */ 02036 smooth_fcurve(ale->key_data); 02037 } 02038 BLI_freelistN(&anim_data); 02039 02040 /* validate keyframes after editing */ 02041 ANIM_editkeyframes_refresh(&ac); 02042 02043 /* set notifier that keyframes have changed */ 02044 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 02045 02046 return OPERATOR_FINISHED; 02047 } 02048 02049 void GRAPH_OT_smooth (wmOperatorType *ot) 02050 { 02051 /* identifiers */ 02052 ot->name= "Smooth Keys"; 02053 ot->idname= "GRAPH_OT_smooth"; 02054 ot->description= "Apply weighted moving means to make selected F-Curves less bumpy"; 02055 02056 /* api callbacks */ 02057 ot->exec= graphkeys_smooth_exec; 02058 ot->poll= graphop_editable_keyframes_poll; 02059 02060 /* flags */ 02061 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02062 } 02063 02064 /* ************************************************************************** */ 02065 /* F-CURVE MODIFIERS */ 02066 02067 /* ******************** Add F-Modifier Operator *********************** */ 02068 02069 /* present a special customised popup menu for this, with some filtering */ 02070 static int graph_fmodifier_add_invoke (bContext *C, wmOperator *op, wmEvent *UNUSED(event)) 02071 { 02072 uiPopupMenu *pup; 02073 uiLayout *layout; 02074 int i; 02075 02076 pup= uiPupMenuBegin(C, "Add F-Curve Modifier", ICON_NONE); 02077 layout= uiPupMenuLayout(pup); 02078 02079 /* start from 1 to skip the 'Invalid' modifier type */ 02080 for (i = 1; i < FMODIFIER_NUM_TYPES; i++) { 02081 FModifierTypeInfo *fmi= get_fmodifier_typeinfo(i); 02082 PointerRNA props_ptr; 02083 02084 /* check if modifier is valid for this context */ 02085 if (fmi == NULL) 02086 continue; 02087 02088 /* create operator menu item with relevant properties filled in */ 02089 props_ptr= uiItemFullO(layout, "GRAPH_OT_fmodifier_add", fmi->name, ICON_NONE, NULL, WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS); 02090 /* the only thing that gets set from the menu is the type of F-Modifier to add */ 02091 RNA_enum_set(&props_ptr, "type", i); 02092 /* the following properties are just repeats of existing ones... */ 02093 RNA_boolean_set(&props_ptr, "only_active", RNA_boolean_get(op->ptr, "only_active")); 02094 } 02095 uiItemS(layout); 02096 02097 uiPupMenuEnd(C, pup); 02098 02099 return OPERATOR_CANCELLED; 02100 } 02101 02102 static int graph_fmodifier_add_exec(bContext *C, wmOperator *op) 02103 { 02104 bAnimContext ac; 02105 ListBase anim_data = {NULL, NULL}; 02106 bAnimListElem *ale; 02107 int filter; 02108 short type; 02109 02110 /* get editor data */ 02111 if (ANIM_animdata_get_context(C, &ac) == 0) 02112 return OPERATOR_CANCELLED; 02113 02114 /* get type of modifier to add */ 02115 type= RNA_enum_get(op->ptr, "type"); 02116 02117 /* filter data */ 02118 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 02119 if (RNA_boolean_get(op->ptr, "only_active")) 02120 filter |= ANIMFILTER_ACTIVE; // FIXME: enforce in this case only a single channel to get handled? 02121 else 02122 filter |= (ANIMFILTER_SEL|ANIMFILTER_CURVE_VISIBLE); 02123 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 02124 02125 /* add f-modifier to each curve */ 02126 for (ale= anim_data.first; ale; ale= ale->next) { 02127 FCurve *fcu= (FCurve *)ale->data; 02128 FModifier *fcm; 02129 02130 /* add F-Modifier of specified type to active F-Curve, and make it the active one */ 02131 fcm= add_fmodifier(&fcu->modifiers, type); 02132 if (fcm) 02133 set_active_fmodifier(&fcu->modifiers, fcm); 02134 else { 02135 BKE_report(op->reports, RPT_ERROR, "Modifier couldn't be added, see console for details"); 02136 break; 02137 } 02138 } 02139 BLI_freelistN(&anim_data); 02140 02141 /* validate keyframes after editing */ 02142 ANIM_editkeyframes_refresh(&ac); 02143 02144 /* set notifier that things have changed */ 02145 // FIXME: this really isn't the best description for it... 02146 WM_event_add_notifier(C, NC_ANIMATION, NULL); 02147 02148 return OPERATOR_FINISHED; 02149 } 02150 02151 void GRAPH_OT_fmodifier_add (wmOperatorType *ot) 02152 { 02153 /* identifiers */ 02154 ot->name= "Add F-Curve Modifier"; 02155 ot->idname= "GRAPH_OT_fmodifier_add"; 02156 ot->description= "Add F-Modifiers to the selected F-Curves"; 02157 02158 /* api callbacks */ 02159 ot->invoke= graph_fmodifier_add_invoke; 02160 ot->exec= graph_fmodifier_add_exec; 02161 ot->poll= graphop_selected_fcurve_poll; 02162 02163 /* flags */ 02164 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02165 02166 /* id-props */ 02167 ot->prop= RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", ""); 02168 RNA_def_boolean(ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve"); 02169 } 02170 02171 /* ******************** Copy F-Modifiers Operator *********************** */ 02172 02173 static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op) 02174 { 02175 bAnimContext ac; 02176 bAnimListElem *ale; 02177 short ok = 0; 02178 02179 /* get editor data */ 02180 if (ANIM_animdata_get_context(C, &ac) == 0) 02181 return OPERATOR_CANCELLED; 02182 02183 /* clear buffer first */ 02184 free_fmodifiers_copybuf(); 02185 02186 /* get the active F-Curve */ 02187 ale= get_active_fcurve_channel(&ac); 02188 02189 /* if this exists, call the copy F-Modifiers API function */ 02190 if (ale && ale->data) { 02191 FCurve *fcu= (FCurve *)ale->data; 02192 02193 // TODO: when 'active' vs 'all' boolean is added, change last param! 02194 ok= ANIM_fmodifiers_copy_to_buf(&fcu->modifiers, 0); 02195 02196 /* free temp data now */ 02197 MEM_freeN(ale); 02198 } 02199 02200 /* successful or not? */ 02201 if (ok == 0) { 02202 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied"); 02203 return OPERATOR_CANCELLED; 02204 } 02205 else 02206 return OPERATOR_FINISHED; 02207 } 02208 02209 void GRAPH_OT_fmodifier_copy (wmOperatorType *ot) 02210 { 02211 /* identifiers */ 02212 ot->name= "Copy F-Modifiers"; 02213 ot->idname= "GRAPH_OT_fmodifier_copy"; 02214 ot->description= "Copy the F-Modifier(s) of the active F-Curve"; 02215 02216 /* api callbacks */ 02217 ot->exec= graph_fmodifier_copy_exec; 02218 ot->poll= graphop_active_fcurve_poll; 02219 02220 /* flags */ 02221 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02222 02223 /* id-props */ 02224 //ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one"); 02225 } 02226 02227 /* ******************** Paste F-Modifiers Operator *********************** */ 02228 02229 static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op) 02230 { 02231 bAnimContext ac; 02232 ListBase anim_data = {NULL, NULL}; 02233 bAnimListElem *ale; 02234 int filter, ok=0; 02235 02236 /* get editor data */ 02237 if (ANIM_animdata_get_context(C, &ac) == 0) 02238 return OPERATOR_CANCELLED; 02239 02240 /* filter data */ 02241 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT); 02242 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 02243 02244 /* paste modifiers */ 02245 for (ale = anim_data.first; ale; ale = ale->next) { 02246 FCurve *fcu= (FCurve *)ale->data; 02247 02248 // TODO: do we want to replace existing modifiers? add user pref for that! 02249 ok += ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, 0); 02250 } 02251 02252 /* clean up */ 02253 BLI_freelistN(&anim_data); 02254 02255 /* successful or not? */ 02256 if (ok) { 02257 /* validate keyframes after editing */ 02258 ANIM_editkeyframes_refresh(&ac); 02259 02260 /* set notifier that keyframes have changed */ 02261 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 02262 02263 return OPERATOR_FINISHED; 02264 } 02265 else { 02266 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste"); 02267 return OPERATOR_CANCELLED; 02268 } 02269 } 02270 02271 void GRAPH_OT_fmodifier_paste (wmOperatorType *ot) 02272 { 02273 /* identifiers */ 02274 ot->name= "Paste F-Modifiers"; 02275 ot->idname= "GRAPH_OT_fmodifier_paste"; 02276 ot->description= "Add copied F-Modifiers to the selected F-Curves"; 02277 02278 /* api callbacks */ 02279 ot->exec= graph_fmodifier_paste_exec; 02280 ot->poll= graphop_active_fcurve_poll; 02281 02282 /* flags */ 02283 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02284 } 02285 02286 /* ************************************************************************** */