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