6042100a984de6c326500683c11d625f86b37bd9
[blender.git] / source / blender / editors / space_graph / graph_edit.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_graph/graph_edit.c
29  *  \ingroup spgraph
30  */
31
32
33 #include <math.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <float.h>
37
38 #ifdef WITH_AUDASPACE
39 #  include AUD_SPECIAL_H
40 #endif
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_math.h"
46 #include "BLI_utildefines.h"
47
48 #include "DNA_anim_types.h"
49 #include "DNA_scene_types.h"
50
51 #include "RNA_access.h"
52 #include "RNA_define.h"
53 #include "RNA_enum_types.h"
54
55 #include "BLT_translation.h"
56
57 #include "BKE_fcurve.h"
58 #include "BKE_global.h"
59 #include "BKE_nla.h"
60 #include "BKE_context.h"
61 #include "BKE_report.h"
62
63 #include "UI_view2d.h"
64
65 #include "ED_anim_api.h"
66 #include "ED_keyframing.h"
67 #include "ED_keyframes_edit.h"
68 #include "ED_screen.h"
69 #include "ED_transform.h"
70 #include "ED_markers.h"
71
72 #include "WM_api.h"
73 #include "WM_types.h"
74
75 #include "graph_intern.h"
76
77 /* ************************************************************************** */
78 /* KEYFRAME-RANGE STUFF */
79
80 /* *************************** Calculate Range ************************** */
81
82 /* Get the min/max keyframes*/
83 /* note: it should return total boundbox, filter for selection only can be argument... */
84 void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, float *ymin, float *ymax, 
85                                 const bool do_sel_only, const bool include_handles)
86 {
87         Scene *scene = ac->scene;
88         
89         ListBase anim_data = {NULL, NULL};
90         bAnimListElem *ale;
91         int filter;
92         
93         /* get data to filter, from Dopesheet */
94         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
95         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
96         
97         /* set large values initial values that will be easy to override */
98         if (xmin) *xmin = 999999999.0f;
99         if (xmax) *xmax = -999999999.0f;
100         if (ymin) *ymin = 999999999.0f;
101         if (ymax) *ymax = -999999999.0f;
102         
103         /* check if any channels to set range with */
104         if (anim_data.first) {
105                 bool foundBounds = false;
106                 
107                 /* go through channels, finding max extents */
108                 for (ale = anim_data.first; ale; ale = ale->next) {
109                         AnimData *adt = ANIM_nla_mapping_get(ac, ale);
110                         FCurve *fcu = (FCurve *)ale->key_data;
111                         float txmin, txmax, tymin, tymax;
112                         float unitFac, offset;
113                         
114                         /* get range */
115                         if (calc_fcurve_bounds(fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) {
116                                 short mapping_flag = ANIM_get_normalization_flags(ac);
117
118                                 /* apply NLA scaling */
119                                 if (adt) {
120                                         txmin = BKE_nla_tweakedit_remap(adt, txmin, NLATIME_CONVERT_MAP);
121                                         txmax = BKE_nla_tweakedit_remap(adt, txmax, NLATIME_CONVERT_MAP);
122                                 }
123                                 
124                                 /* apply unit corrections */
125                                 unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
126                                 tymin += offset;
127                                 tymax += offset;
128                                 tymin *= unitFac;
129                                 tymax *= unitFac;
130                                 
131                                 /* try to set cur using these values, if they're more extreme than previously set values */
132                                 if ((xmin) && (txmin < *xmin)) *xmin = txmin;
133                                 if ((xmax) && (txmax > *xmax)) *xmax = txmax;
134                                 if ((ymin) && (tymin < *ymin)) *ymin = tymin;
135                                 if ((ymax) && (tymax > *ymax)) *ymax = tymax;
136                                 
137                                 foundBounds = true;
138                         }
139                 }
140                 
141                 /* ensure that the extents are not too extreme that view implodes...*/
142                 if (foundBounds) {
143                         if ((xmin && xmax) && (fabsf(*xmax - *xmin) < 0.1f)) *xmax += 0.1f;
144                         if ((ymin && ymax) && (fabsf(*ymax - *ymin) < 0.1f)) *ymax += 0.1f;
145                 }
146                 else {
147                         if (xmin) *xmin = (float)PSFRA;
148                         if (xmax) *xmax = (float)PEFRA;
149                         if (ymin) *ymin = -5;
150                         if (ymax) *ymax = 5;
151                 }
152                 
153                 /* free memory */
154                 ANIM_animdata_freelist(&anim_data);
155         }
156         else {
157                 /* set default range */
158                 if (ac->scene) {
159                         if (xmin) *xmin = (float)PSFRA;
160                         if (xmax) *xmax = (float)PEFRA;
161                 }
162                 else {
163                         if (xmin) *xmin = -5;
164                         if (xmax) *xmax = 100;
165                 }
166                 
167                 if (ymin) *ymin = -5;
168                 if (ymax) *ymax = 5;
169         }
170 }
171
172 /* ****************** Automatic Preview-Range Operator ****************** */
173
174 static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
175 {
176         bAnimContext ac;
177         Scene *scene;
178         float min, max;
179         
180         /* get editor data */
181         if (ANIM_animdata_get_context(C, &ac) == 0)
182                 return OPERATOR_CANCELLED;
183         if (ac.scene == NULL)
184                 return OPERATOR_CANCELLED;
185         else
186                 scene = ac.scene;
187         
188         /* set the range directly */
189         get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL, false, false);
190         scene->r.flag |= SCER_PRV_RANGE;
191         scene->r.psfra = iroundf(min);
192         scene->r.pefra = iroundf(max);
193         
194         /* set notifier that things have changed */
195         // XXX err... there's nothing for frame ranges yet, but this should do fine too
196         WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene);
197         
198         return OPERATOR_FINISHED;
199 }
200  
201 void GRAPH_OT_previewrange_set(wmOperatorType *ot)
202 {
203         /* identifiers */
204         ot->name = "Auto-Set Preview Range";
205         ot->idname = "GRAPH_OT_previewrange_set";
206         ot->description = "Automatically set Preview Range based on range of keyframes";
207         
208         /* api callbacks */
209         ot->exec = graphkeys_previewrange_exec;
210         ot->poll = ED_operator_graphedit_active; // XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier...
211         
212         /* flags */
213         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
214 }
215
216 /* ****************** View-All Operator ****************** */
217
218 static int graphkeys_viewall(bContext *C, const bool do_sel_only, const bool include_handles,
219                              const int smooth_viewtx)
220 {
221         bAnimContext ac;
222         rctf cur_new;
223         
224         /* get editor data */
225         if (ANIM_animdata_get_context(C, &ac) == 0)
226                 return OPERATOR_CANCELLED;
227         
228         /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
229         get_graph_keyframe_extents(&ac,
230                                    &cur_new.xmin, &cur_new.xmax,
231                                    &cur_new.ymin, &cur_new.ymax,
232                                    do_sel_only, include_handles);
233
234         BLI_rctf_scale(&cur_new, 1.1f);
235         
236         UI_view2d_smooth_view(C, ac.ar, &cur_new, smooth_viewtx);
237         
238         return OPERATOR_FINISHED;
239 }
240
241 /* ......... */
242
243 static int graphkeys_viewall_exec(bContext *C, wmOperator *op)
244 {
245         const bool include_handles = RNA_boolean_get(op->ptr, "include_handles");
246         const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
247         
248         /* whole range */
249         return graphkeys_viewall(C, false, include_handles, smooth_viewtx);
250 }
251  
252 static int graphkeys_view_selected_exec(bContext *C, wmOperator *op)
253 {
254         const bool include_handles = RNA_boolean_get(op->ptr, "include_handles");
255         const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
256         
257         /* only selected */
258         return graphkeys_viewall(C, true, include_handles, smooth_viewtx);
259 }
260
261 static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
262 {
263         const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
264         ANIM_center_frame(C, smooth_viewtx);
265         return OPERATOR_FINISHED;
266 }
267
268
269 void GRAPH_OT_view_all(wmOperatorType *ot)
270 {
271         /* identifiers */
272         ot->name = "View All";
273         ot->idname = "GRAPH_OT_view_all";
274         ot->description = "Reset viewable area to show full keyframe range";
275         
276         /* api callbacks */
277         ot->exec = graphkeys_viewall_exec;
278         ot->poll = ED_operator_graphedit_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
279         
280         /* flags */
281         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
282         
283         /* props */
284         ot->prop = RNA_def_boolean(ot->srna, "include_handles", true, "Include Handles", 
285                                    "Include handles of keyframes when calculating extents");
286 }
287
288 void GRAPH_OT_view_selected(wmOperatorType *ot)
289 {
290         /* identifiers */
291         ot->name = "View Selected";
292         ot->idname = "GRAPH_OT_view_selected";
293         ot->description = "Reset viewable area to show selected keyframe range";
294
295         /* api callbacks */
296         ot->exec = graphkeys_view_selected_exec;
297         ot->poll = ED_operator_graphedit_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
298
299         /* flags */
300         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
301         
302         /* props */
303         ot->prop = RNA_def_boolean(ot->srna, "include_handles", true, "Include Handles", 
304                                    "Include handles of keyframes when calculating extents");
305 }
306
307 void GRAPH_OT_view_frame(wmOperatorType *ot)
308 {
309         /* identifiers */
310         ot->name = "View Frame";
311         ot->idname = "GRAPH_OT_view_frame";
312         ot->description = "Reset viewable area to show range around current frame";
313
314         /* api callbacks */
315         ot->exec = graphkeys_view_frame_exec;
316         ot->poll = ED_operator_graphedit_active; /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier... */
317
318         /* flags */
319         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
320 }
321
322 /* ******************** Create Ghost-Curves Operator *********************** */
323 /* This operator samples the data of the selected F-Curves to F-Points, storing them
324  * as 'ghost curves' in the active Graph Editor
325  */
326
327 /* Bake each F-Curve into a set of samples, and store as a ghost curve */
328 static void create_ghost_curves(bAnimContext *ac, int start, int end)
329 {       
330         SpaceIpo *sipo = (SpaceIpo *)ac->sl;
331         ListBase anim_data = {NULL, NULL};
332         bAnimListElem *ale;
333         int filter;
334         
335         /* free existing ghost curves */
336         free_fcurves(&sipo->ghostCurves);
337         
338         /* sanity check */
339         if (start >= end) {
340                 printf("Error: Frame range for Ghost F-Curve creation is inappropriate\n");
341                 return;
342         }
343         
344         /* filter data */
345         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
346         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
347         
348         /* loop through filtered data and add keys between selected keyframes on every frame  */
349         for (ale = anim_data.first; ale; ale = ale->next) {
350                 FCurve *fcu = (FCurve *)ale->key_data;
351                 FCurve *gcu = MEM_callocN(sizeof(FCurve), "Ghost FCurve");
352                 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
353                 ChannelDriver *driver = fcu->driver;
354                 FPoint *fpt;
355                 float unitFac, offset;
356                 int cfra;
357                 short mapping_flag = ANIM_get_normalization_flags(ac);
358                 
359                 /* disable driver so that it don't muck up the sampling process */
360                 fcu->driver = NULL;
361                 
362                 /* calculate unit-mapping factor */
363                 unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
364                 
365                 /* create samples, but store them in a new curve 
366                  *      - we cannot use fcurve_store_samples() as that will only overwrite the original curve 
367                  */
368                 gcu->fpt = fpt = MEM_callocN(sizeof(FPoint) * (end - start + 1), "Ghost FPoint Samples");
369                 gcu->totvert = end - start + 1;
370                 
371                 /* use the sampling callback at 1-frame intervals from start to end frames */
372                 for (cfra = start; cfra <= end; cfra++, fpt++) {
373                         float cfrae = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
374                         
375                         fpt->vec[0] = cfrae;
376                         fpt->vec[1] = (fcurve_samplingcb_evalcurve(fcu, NULL, cfrae) + offset) * unitFac;
377                 }
378                 
379                 /* set color of ghost curve 
380                  *      - make the color slightly darker
381                  */
382                 gcu->color[0] = fcu->color[0] - 0.07f;
383                 gcu->color[1] = fcu->color[1] - 0.07f;
384                 gcu->color[2] = fcu->color[2] - 0.07f;
385                 
386                 /* store new ghost curve */
387                 BLI_addtail(&sipo->ghostCurves, gcu);
388                 
389                 /* restore driver */
390                 fcu->driver = driver;
391         }
392         
393         /* admin and redraws */
394         ANIM_animdata_freelist(&anim_data);
395 }
396
397 /* ------------------- */
398
399 static int graphkeys_create_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op))
400 {
401         bAnimContext ac;
402         View2D *v2d;
403         int start, end;
404         
405         /* get editor data */
406         if (ANIM_animdata_get_context(C, &ac) == 0)
407                 return OPERATOR_CANCELLED;
408                 
409         /* ghost curves are snapshots of the visible portions of the curves, so set range to be the visible range */
410         v2d = &ac.ar->v2d;
411         start = (int)v2d->cur.xmin;
412         end = (int)v2d->cur.xmax;
413         
414         /* bake selected curves into a ghost curve */
415         create_ghost_curves(&ac, start, end);
416         
417         /* update this editor only */
418         ED_area_tag_redraw(CTX_wm_area(C));
419         
420         return OPERATOR_FINISHED;
421 }
422  
423 void GRAPH_OT_ghost_curves_create(wmOperatorType *ot)
424 {
425         /* identifiers */
426         ot->name = "Create Ghost Curves";
427         ot->idname = "GRAPH_OT_ghost_curves_create";
428         ot->description = "Create snapshot (Ghosts) of selected F-Curves as background aid for active Graph Editor";
429         
430         /* api callbacks */
431         ot->exec = graphkeys_create_ghostcurves_exec;
432         ot->poll = graphop_visible_keyframes_poll;
433         
434         /* flags */
435         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
436         
437         // todo: add props for start/end frames
438 }
439
440 /* ******************** Clear Ghost-Curves Operator *********************** */
441 /* This operator clears the 'ghost curves' for the active Graph Editor */
442
443 static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op))
444 {
445         bAnimContext ac;
446         SpaceIpo *sipo;
447         
448         /* get editor data */
449         if (ANIM_animdata_get_context(C, &ac) == 0)
450                 return OPERATOR_CANCELLED;
451         sipo = (SpaceIpo *)ac.sl;
452                 
453         /* if no ghost curves, don't do anything */
454         if (BLI_listbase_is_empty(&sipo->ghostCurves))
455                 return OPERATOR_CANCELLED;
456         
457         /* free ghost curves */
458         free_fcurves(&sipo->ghostCurves);
459         
460         /* update this editor only */
461         ED_area_tag_redraw(CTX_wm_area(C));
462         
463         return OPERATOR_FINISHED;
464 }
465  
466 void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot)
467 {
468         /* identifiers */
469         ot->name = "Clear Ghost Curves";
470         ot->idname = "GRAPH_OT_ghost_curves_clear";
471         ot->description = "Clear F-Curve snapshots (Ghosts) for active Graph Editor";
472         
473         /* api callbacks */
474         ot->exec = graphkeys_clear_ghostcurves_exec;
475         ot->poll = ED_operator_graphedit_active;
476         
477         /* flags */
478         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
479 }
480
481 /* ************************************************************************** */
482 /* GENERAL STUFF */
483
484 /* ******************** Insert Keyframes Operator ************************* */
485
486 /* Mode defines for insert keyframes tool */
487 typedef enum eGraphKeys_InsertKey_Types {
488         GRAPHKEYS_INSERTKEY_ALL    = (1 << 0),
489         GRAPHKEYS_INSERTKEY_SEL    = (1 << 1),
490         GRAPHKEYS_INSERTKEY_CURSOR = (1 << 2),
491         GRAPHKEYS_INSERTKEY_ACTIVE = (1 << 3),
492 } eGraphKeys_InsertKey_Types;
493
494 /* RNA mode types for insert keyframes tool */
495 static EnumPropertyItem prop_graphkeys_insertkey_types[] = {
496         {GRAPHKEYS_INSERTKEY_ALL,   "ALL", 0, "All Channels",
497          "Insert a keyframe on all visible and editable F-Curves using each curve's current value"},
498         {GRAPHKEYS_INSERTKEY_SEL,   "SEL", 0, "Only Selected Channels",
499          "Insert a keyframe on selected F-Curves using each curve's current value"},
500         {0, "", 0, "", ""},
501         {GRAPHKEYS_INSERTKEY_ACTIVE | GRAPHKEYS_INSERTKEY_CURSOR, "CURSOR_ACTIVE", 0,
502          "Active Channels At Cursor", "Insert a keyframe for the active F-Curve at the cursor point"},
503         {GRAPHKEYS_INSERTKEY_SEL | GRAPHKEYS_INSERTKEY_CURSOR, "CURSOR_SEL", 0,
504          "Selected Channels At Cursor", "Insert a keyframe for selected F-Curves at the cursor point"},
505         {0, NULL, 0, NULL, NULL}
506 };
507
508 /* this function is responsible for snapping keyframes to frame-times */
509 static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode) 
510 {
511         ListBase anim_data = {NULL, NULL};
512         bAnimListElem *ale;
513         int filter;
514         size_t num_items;
515         
516         ReportList *reports = ac->reports;
517         SpaceIpo *sipo = (SpaceIpo *)ac->sl;
518         Scene *scene = ac->scene;
519         short flag = 0;
520         
521         /* filter data */
522         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
523         if (mode & GRAPHKEYS_INSERTKEY_SEL)
524                 filter |= ANIMFILTER_SEL;
525         else if (mode & GRAPHKEYS_INSERTKEY_ACTIVE)
526                 filter |= ANIMFILTER_ACTIVE;
527         
528         num_items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
529         if (num_items == 0) {
530                 if (mode & GRAPHKEYS_INSERTKEY_ACTIVE)
531                         BKE_report(reports, RPT_ERROR, "No active F-Curve to add a keyframe to. Select an editable F-Curve first");
532                 else if (mode & GRAPHKEYS_INSERTKEY_SEL)
533                         BKE_report(reports, RPT_ERROR, "No selected F-Curves to add keyframes to");
534                 else
535                         BKE_report(reports, RPT_ERROR, "No channels to add keyframes to");
536                 
537                 return;
538         }
539         
540         /* init keyframing flag */
541         flag = ANIM_get_keyframing_flags(scene, 1);
542         
543         /* insert keyframes */
544         if (mode & GRAPHKEYS_INSERTKEY_CURSOR) {
545                 for (ale = anim_data.first; ale; ale = ale->next) {
546                         AnimData *adt = ANIM_nla_mapping_get(ac, ale);
547                         FCurve *fcu = (FCurve *)ale->key_data;
548                         
549                         short mapping_flag = ANIM_get_normalization_flags(ac);
550                         float offset;
551                         float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag, &offset);
552                         
553                         float x, y;
554                         
555                         
556                         /* perform time remapping for x-coordinate (if necessary) */
557                         if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS))
558                                 x = sipo->cursorTime;
559                         else if (adt)
560                                 x = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
561                         else
562                                 x = (float)CFRA;
563                         
564                         /* normalise units of cursor's value */
565                         if (sipo)
566                                 y = (sipo->cursorVal / unit_scale) - offset;
567                         else
568                                 y = 0.0f;
569                                 
570                         /* insert keyframe directly into the F-Curve */
571                         insert_vert_fcurve(fcu, x, y, 0);
572                         
573                         ale->update |= ANIM_UPDATE_DEFAULT;
574                 }
575         }
576         else {
577                 for (ale = anim_data.first; ale; ale = ale->next) {
578                         AnimData *adt = ANIM_nla_mapping_get(ac, ale);
579                         FCurve *fcu = (FCurve *)ale->key_data;
580                         float cfra;
581                         
582                         /* adjust current frame for NLA-mapping */
583                         if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS))
584                                 cfra = sipo->cursorTime;
585                         else if (adt)
586                                 cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
587                         else 
588                                 cfra = (float)CFRA;
589                                 
590                         /* read value from property the F-Curve represents, or from the curve only?
591                          * - ale->id != NULL:    Typically, this means that we have enough info to try resolving the path
592                          * - ale->owner != NULL: If this is set, then the path may not be resolvable from the ID alone,
593                          *                       so it's easier for now to just read the F-Curve directly.
594                          *                       (TODO: add the full-blown PointerRNA relative parsing case here...)
595                          * - fcu->driver != NULL: If this is set, then it's a driver. If we don't check for this, we'd end
596                          *                        up adding the keyframes on a new F-Curve in the action data instead.
597                          */
598                         if (ale->id && !ale->owner && !fcu->driver)
599                                 insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
600                         else
601                                 insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
602                         
603                         ale->update |= ANIM_UPDATE_DEFAULT;
604                 }
605         }
606         
607         ANIM_animdata_update(ac, &anim_data);
608         ANIM_animdata_freelist(&anim_data);
609 }
610
611 /* ------------------- */
612
613 static int graphkeys_insertkey_exec(bContext *C, wmOperator *op)
614 {
615         bAnimContext ac;
616         eGraphKeys_InsertKey_Types mode;
617         
618         /* get editor data */
619         if (ANIM_animdata_get_context(C, &ac) == 0)
620                 return OPERATOR_CANCELLED;
621                 
622         /* which channels to affect? */
623         mode = RNA_enum_get(op->ptr, "type");
624         
625         /* insert keyframes */
626         insert_graph_keys(&ac, mode);
627         
628         /* set notifier that keyframes have changed */
629         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
630         
631         return OPERATOR_FINISHED;
632 }
633
634 void GRAPH_OT_keyframe_insert(wmOperatorType *ot)
635 {
636         /* identifiers */
637         ot->name = "Insert Keyframes";
638         ot->idname = "GRAPH_OT_keyframe_insert";
639         ot->description = "Insert keyframes for the specified channels";
640         
641         /* api callbacks */
642         ot->invoke = WM_menu_invoke;
643         ot->exec = graphkeys_insertkey_exec;
644         ot->poll = graphop_editable_keyframes_poll;
645         
646         /* flags */
647         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
648         
649         /* id-props */
650         ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_insertkey_types, 0, "Type", "");
651 }
652
653 /* ******************** Click-Insert Keyframes Operator ************************* */
654
655 static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
656 {
657         bAnimContext ac;
658         bAnimListElem *ale;
659         AnimData *adt;
660         FCurve *fcu;
661         float frame, val;
662         
663         /* get animation context */
664         if (ANIM_animdata_get_context(C, &ac) == 0)
665                 return OPERATOR_CANCELLED;
666         
667         /* get active F-Curve 'anim-list-element' */
668         ale = get_active_fcurve_channel(&ac);
669         if (ELEM(NULL, ale, ale->data)) {
670                 if (ale) MEM_freeN(ale);
671                 return OPERATOR_CANCELLED;
672         }
673         fcu = ale->data;
674         
675         /* when there are F-Modifiers on the curve, only allow adding
676          * keyframes if these will be visible after doing so...
677          */
678         if (fcurve_is_keyframable(fcu)) {
679                 ListBase anim_data;
680
681                 short mapping_flag = ANIM_get_normalization_flags(&ac);
682                 float scale, offset;
683                 /* get frame and value from props */
684                 frame = RNA_float_get(op->ptr, "frame");
685                 val = RNA_float_get(op->ptr, "value");
686                 
687                 /* apply inverse NLA-mapping to frame to get correct time in un-scaled action */
688                 adt = ANIM_nla_mapping_get(&ac, ale);
689                 frame = BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP);
690                 
691                 /* apply inverse unit-mapping to value to get correct value for F-Curves */
692                 scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, fcu, mapping_flag | ANIM_UNITCONV_RESTORE, &offset);
693
694                 val = val * scale - offset;
695
696                 /* insert keyframe on the specified frame + value */
697                 insert_vert_fcurve(fcu, frame, val, 0);
698                 
699                 ale->update |= ANIM_UPDATE_DEPS;
700                 
701                 BLI_listbase_clear(&anim_data);
702                 BLI_addtail(&anim_data, ale);
703                 
704                 ANIM_animdata_update(&ac, &anim_data);
705         }
706         else {
707                 /* warn about why this can't happen */
708                 if (fcu->fpt)
709                         BKE_report(op->reports, RPT_ERROR, "Keyframes cannot be added to sampled F-Curves");
710                 else if (fcu->flag & FCURVE_PROTECTED)
711                         BKE_report(op->reports, RPT_ERROR, "Active F-Curve is not editable");
712                 else
713                         BKE_report(op->reports, RPT_ERROR, "Remove F-Modifiers from F-Curve to add keyframes");
714         }
715         
716         /* free temp data */
717         MEM_freeN(ale);
718         
719         /* set notifier that keyframes have changed */
720         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
721         
722         /* done */
723         return OPERATOR_FINISHED;
724 }
725
726 static int graphkeys_click_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
727 {
728         bAnimContext ac;
729         ARegion *ar;
730         View2D *v2d;
731         int mval[2];
732         float x, y;
733         
734         /* get animation context */
735         if (ANIM_animdata_get_context(C, &ac) == 0)
736                 return OPERATOR_CANCELLED;
737         
738         /* store mouse coordinates in View2D space, into the operator's properties */
739         ar = ac.ar;
740         v2d = &ar->v2d;
741         
742         mval[0] = (event->x - ar->winrct.xmin);
743         mval[1] = (event->y - ar->winrct.ymin);
744         
745         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
746         
747         RNA_float_set(op->ptr, "frame", x);
748         RNA_float_set(op->ptr, "value", y);
749         
750         /* run exec now */
751         return graphkeys_click_insert_exec(C, op);
752 }
753
754 void GRAPH_OT_click_insert(wmOperatorType *ot)
755 {
756         /* identifiers */
757         ot->name = "Click-Insert Keyframes";
758         ot->idname = "GRAPH_OT_click_insert";
759         ot->description = "Insert new keyframe at the cursor position for the active F-Curve";
760         
761         /* api callbacks */
762         ot->invoke = graphkeys_click_insert_invoke;
763         ot->exec = graphkeys_click_insert_exec;
764         ot->poll = graphop_active_fcurve_poll;
765         
766         /* flags */
767         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
768         
769         /* properties */
770         RNA_def_float(ot->srna, "frame", 1.0f, -FLT_MAX, FLT_MAX, "Frame Number", "Frame to insert keyframe on", 0, 100);
771         RNA_def_float(ot->srna, "value", 1.0f, -FLT_MAX, FLT_MAX, "Value", "Value for keyframe on", 0, 100);
772 }
773
774 /* ******************** Copy/Paste Keyframes Operator ************************* */
775 /* NOTE: the backend code for this is shared with the dopesheet editor */
776
777 static short copy_graph_keys(bAnimContext *ac)
778 {       
779         ListBase anim_data = {NULL, NULL};
780         int filter, ok = 0;
781         
782         /* clear buffer first */
783         free_anim_copybuf();
784         
785         /* filter data */
786         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
787         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
788         
789         /* copy keyframes */
790         ok = copy_animedit_keys(ac, &anim_data);
791         
792         /* clean up */
793         ANIM_animdata_freelist(&anim_data);
794
795         return ok;
796 }
797
798 static short paste_graph_keys(bAnimContext *ac,
799                               const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode, bool flip)
800 {       
801         ListBase anim_data = {NULL, NULL};
802         int filter, ok = 0;
803         
804         /* filter data 
805          * - First time we try to filter more strictly, allowing only selected channels 
806          *   to allow copying animation between channels
807          * - Second time, we loosen things up if nothing was found the first time, allowing
808          *   users to just paste keyframes back into the original curve again [#31670]
809          */
810         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
811         
812         if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0)
813                 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
814         
815         /* paste keyframes */
816         ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
817
818         /* clean up */
819         ANIM_animdata_freelist(&anim_data);
820
821         return ok;
822 }
823
824 /* ------------------- */
825
826 static int graphkeys_copy_exec(bContext *C, wmOperator *op)
827 {
828         bAnimContext ac;
829         
830         /* get editor data */
831         if (ANIM_animdata_get_context(C, &ac) == 0)
832                 return OPERATOR_CANCELLED;
833         
834         /* copy keyframes */
835         if (copy_graph_keys(&ac)) {
836                 BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
837                 return OPERATOR_CANCELLED;
838         }
839         
840         /* just return - no operator needed here (no changes) */
841         return OPERATOR_FINISHED;
842 }
843  
844 void GRAPH_OT_copy(wmOperatorType *ot)
845 {
846         /* identifiers */
847         ot->name = "Copy Keyframes";
848         ot->idname = "GRAPH_OT_copy";
849         ot->description = "Copy selected keyframes to the copy/paste buffer";
850         
851         /* api callbacks */
852         ot->exec = graphkeys_copy_exec;
853         ot->poll = graphop_editable_keyframes_poll;
854         
855         /* flags */
856         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
857 }
858
859
860
861 static int graphkeys_paste_exec(bContext *C, wmOperator *op)
862 {
863         bAnimContext ac;
864
865         const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset");
866         const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge");
867         const bool flipped = RNA_boolean_get(op->ptr, "flipped");
868         
869         /* get editor data */
870         if (ANIM_animdata_get_context(C, &ac) == 0)
871                 return OPERATOR_CANCELLED;
872         
873         /* ac.reports by default will be the global reports list, which won't show warnings */
874         ac.reports = op->reports;
875
876         /* paste keyframes - non-zero return means an error occurred while trying to paste */
877         if (paste_graph_keys(&ac, offset_mode, merge_mode, flipped)) {
878                 return OPERATOR_CANCELLED;
879         }
880         
881         /* set notifier that keyframes have changed */
882         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
883         
884         return OPERATOR_FINISHED;
885 }
886  
887 void GRAPH_OT_paste(wmOperatorType *ot)
888 {
889         PropertyRNA *prop;
890         
891         /* identifiers */
892         ot->name = "Paste Keyframes";
893         ot->idname = "GRAPH_OT_paste";
894         ot->description = "Paste keyframes from copy/paste buffer for the selected channels, starting on the current frame";
895         
896         /* api callbacks */
897 //      ot->invoke = WM_operator_props_popup; // better wait for graph redo panel
898         ot->exec = graphkeys_paste_exec;
899         ot->poll = graphop_editable_keyframes_poll;
900         
901         /* flags */
902         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
903         
904         /* props */
905         RNA_def_enum(ot->srna, "offset", rna_enum_keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys");
906         RNA_def_enum(ot->srna, "merge", rna_enum_keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing");
907         prop = RNA_def_boolean(ot->srna, "flipped", false, "Flipped", "Paste keyframes from mirrored bones if they exist");
908         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
909 }
910
911 /* ******************** Duplicate Keyframes Operator ************************* */
912
913 static void duplicate_graph_keys(bAnimContext *ac)
914 {
915         ListBase anim_data = {NULL, NULL};
916         bAnimListElem *ale;
917         int filter;
918         
919         /* filter data */
920         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
921         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
922         
923         /* loop through filtered data and delete selected keys */
924         for (ale = anim_data.first; ale; ale = ale->next) {
925                 duplicate_fcurve_keys((FCurve *)ale->key_data);
926
927                 ale->update |= ANIM_UPDATE_DEFAULT;
928         }
929
930         ANIM_animdata_update(ac, &anim_data);
931         ANIM_animdata_freelist(&anim_data);
932 }
933
934 /* ------------------- */
935
936 static int graphkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
937 {
938         bAnimContext ac;
939         
940         /* get editor data */
941         if (ANIM_animdata_get_context(C, &ac) == 0)
942                 return OPERATOR_CANCELLED;
943                 
944         /* duplicate keyframes */
945         duplicate_graph_keys(&ac);
946         
947         /* set notifier that keyframes have changed */
948         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
949         
950         return OPERATOR_FINISHED;
951 }
952
953 void GRAPH_OT_duplicate(wmOperatorType *ot)
954 {
955         /* identifiers */
956         ot->name = "Duplicate Keyframes";
957         ot->idname = "GRAPH_OT_duplicate";
958         ot->description = "Make a copy of all selected keyframes";
959         
960         /* api callbacks */
961         ot->exec = graphkeys_duplicate_exec;
962         ot->poll = graphop_editable_keyframes_poll;
963         
964         /* flags */
965         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
966         
967         /* to give to transform */
968         RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
969 }
970
971 /* ******************** Delete Keyframes Operator ************************* */
972
973 static bool delete_graph_keys(bAnimContext *ac)
974 {
975         ListBase anim_data = {NULL, NULL};
976         bAnimListElem *ale;
977         int filter;
978         bool changed_final = false;
979         
980         /* filter data */
981         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
982         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
983         
984         /* loop through filtered data and delete selected keys */
985         for (ale = anim_data.first; ale; ale = ale->next) {
986                 FCurve *fcu = (FCurve *)ale->key_data;
987                 AnimData *adt = ale->adt;
988                 bool changed;
989                 
990                 /* delete selected keyframes only */
991                 changed = delete_fcurve_keys(fcu);
992
993                 if (changed) {
994                         ale->update |= ANIM_UPDATE_DEFAULT;
995                         changed_final = true;
996                 }
997                 
998                 /* Only delete curve too if it won't be doing anything anymore */
999                 if ((fcu->totvert == 0) &&
1000                     (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0) &&
1001                     (fcu->driver == NULL))
1002                 {
1003                         ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
1004                         ale->key_data = NULL;
1005                 }
1006         }
1007
1008         ANIM_animdata_update(ac, &anim_data);
1009         ANIM_animdata_freelist(&anim_data);
1010
1011         return changed_final;
1012 }
1013
1014 /* ------------------- */
1015
1016 static int graphkeys_delete_exec(bContext *C, wmOperator *UNUSED(op))
1017 {
1018         bAnimContext ac;
1019         
1020         /* get editor data */
1021         if (ANIM_animdata_get_context(C, &ac) == 0)
1022                 return OPERATOR_CANCELLED;
1023                 
1024         /* delete keyframes */
1025         if (!delete_graph_keys(&ac))
1026                 return OPERATOR_CANCELLED;
1027         
1028         /* set notifier that keyframes have changed */
1029         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
1030         
1031         return OPERATOR_FINISHED;
1032 }
1033  
1034 void GRAPH_OT_delete(wmOperatorType *ot)
1035 {
1036         /* identifiers */
1037         ot->name = "Delete Keyframes";
1038         ot->idname = "GRAPH_OT_delete";
1039         ot->description = "Remove all selected keyframes";
1040         
1041         /* api callbacks */
1042         ot->invoke = WM_operator_confirm;
1043         ot->exec = graphkeys_delete_exec;
1044         ot->poll = graphop_editable_keyframes_poll;
1045         
1046         /* flags */
1047         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1048 }
1049
1050 /* ******************** Clean Keyframes Operator ************************* */
1051
1052 static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan)
1053 {       
1054         ListBase anim_data = {NULL, NULL};
1055         bAnimListElem *ale;
1056         int filter;
1057         
1058         /* filter data */
1059         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
1060         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1061         
1062         /* loop through filtered data and clean curves */
1063         for (ale = anim_data.first; ale; ale = ale->next) {
1064                 clean_fcurve(ac, ale, thresh, clean_chan);
1065
1066                 ale->update |= ANIM_UPDATE_DEFAULT;
1067         }
1068
1069         ANIM_animdata_update(ac, &anim_data);
1070         ANIM_animdata_freelist(&anim_data);
1071 }
1072
1073 /* ------------------- */
1074
1075 static int graphkeys_clean_exec(bContext *C, wmOperator *op)
1076 {
1077         bAnimContext ac;
1078         float thresh;
1079         bool clean_chan;
1080         
1081         /* get editor data */
1082         if (ANIM_animdata_get_context(C, &ac) == 0)
1083                 return OPERATOR_CANCELLED;
1084                 
1085         /* get cleaning threshold */
1086         thresh = RNA_float_get(op->ptr, "threshold");
1087         clean_chan = RNA_boolean_get(op->ptr, "channels");
1088         /* clean keyframes */
1089         clean_graph_keys(&ac, thresh, clean_chan);
1090         
1091         /* set notifier that keyframes have changed */
1092         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
1093         
1094         return OPERATOR_FINISHED;
1095 }
1096  
1097 void GRAPH_OT_clean(wmOperatorType *ot)
1098 {
1099         /* identifiers */
1100         ot->name = "Clean Keyframes";
1101         ot->idname = "GRAPH_OT_clean";
1102         ot->description = "Simplify F-Curves by removing closely spaced keyframes";
1103         
1104         /* api callbacks */
1105         //ot->invoke =  // XXX we need that number popup for this! 
1106         ot->exec = graphkeys_clean_exec;
1107         ot->poll = graphop_editable_keyframes_poll;
1108         
1109         /* flags */
1110         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1111         
1112         /* properties */
1113         ot->prop = RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
1114         RNA_def_boolean(ot->srna, "channels", false, "Channels", "");
1115 }
1116
1117 /* ******************** Bake F-Curve Operator *********************** */
1118 /* This operator bakes the data of the selected F-Curves to F-Points */
1119
1120 /* Bake each F-Curve into a set of samples */
1121 static void bake_graph_curves(bAnimContext *ac, int start, int end)
1122 {       
1123         ListBase anim_data = {NULL, NULL};
1124         bAnimListElem *ale;
1125         int filter;
1126         
1127         /* filter data */
1128         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1129         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1130         
1131         /* loop through filtered data and add keys between selected keyframes on every frame  */
1132         for (ale = anim_data.first; ale; ale = ale->next) {
1133                 FCurve *fcu = (FCurve *)ale->key_data;
1134                 ChannelDriver *driver = fcu->driver;
1135                 
1136                 /* disable driver so that it don't muck up the sampling process */
1137                 fcu->driver = NULL;
1138                 
1139                 /* create samples */
1140                 fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
1141                 
1142                 /* restore driver */
1143                 fcu->driver = driver;
1144
1145                 ale->update |= ANIM_UPDATE_DEPS;
1146         }
1147
1148         ANIM_animdata_update(ac, &anim_data);
1149         ANIM_animdata_freelist(&anim_data);
1150 }
1151
1152 /* ------------------- */
1153
1154 static int graphkeys_bake_exec(bContext *C, wmOperator *UNUSED(op))
1155 {
1156         bAnimContext ac;
1157         Scene *scene = NULL;
1158         int start, end;
1159         
1160         /* get editor data */
1161         if (ANIM_animdata_get_context(C, &ac) == 0)
1162                 return OPERATOR_CANCELLED;
1163                 
1164         /* for now, init start/end from preview-range extents */
1165         // TODO: add properties for this 
1166         scene = ac.scene;
1167         start = PSFRA;
1168         end = PEFRA;
1169         
1170         /* bake keyframes */
1171         bake_graph_curves(&ac, start, end);
1172         
1173         /* set notifier that keyframes have changed */
1174         // NOTE: some distinction between order/number of keyframes and type should be made?
1175         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
1176         
1177         return OPERATOR_FINISHED;
1178 }
1179  
1180 void GRAPH_OT_bake(wmOperatorType *ot)
1181 {
1182         /* identifiers */
1183         ot->name = "Bake Curve";
1184         ot->idname = "GRAPH_OT_bake";
1185         ot->description = "Bake selected F-Curves to a set of sampled points defining a similar curve";
1186         
1187         /* api callbacks */
1188         ot->invoke = WM_operator_confirm; // FIXME...
1189         ot->exec = graphkeys_bake_exec;
1190         ot->poll = graphop_selected_fcurve_poll; 
1191         
1192         /* flags */
1193         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1194         
1195         // todo: add props for start/end frames
1196 }
1197
1198 #ifdef WITH_AUDASPACE
1199
1200 /* ******************** Sound Bake F-Curve Operator *********************** */
1201 /* This operator bakes the given sound to the selected F-Curves */
1202
1203 /* ------------------- */
1204
1205 /* Custom data storage passed to the F-Sample-ing function,
1206  * which provides the necessary info for baking the sound
1207  */
1208 typedef struct tSoundBakeInfo {
1209         float *samples;
1210         int length;
1211         int cfra;
1212 } tSoundBakeInfo;
1213
1214 /* ------------------- */
1215
1216 /* Sampling callback used to determine the value from the sound to
1217  * save in the F-Curve at the specified frame
1218  */
1219 static float fcurve_samplingcb_sound(FCurve *UNUSED(fcu), void *data, float evaltime)
1220 {
1221         tSoundBakeInfo *sbi = (tSoundBakeInfo *)data;
1222
1223         int position = evaltime - sbi->cfra;
1224         if ((position < 0) || (position >= sbi->length))
1225                 return 0.0f;
1226
1227         return sbi->samples[position];
1228 }
1229
1230 /* ------------------- */
1231
1232 static int graphkeys_sound_bake_exec(bContext *C, wmOperator *op)
1233 {
1234         bAnimContext ac;
1235         ListBase anim_data = {NULL, NULL};
1236         bAnimListElem *ale;
1237         int filter;
1238
1239         tSoundBakeInfo sbi;
1240         Scene *scene = NULL;
1241         int start, end;
1242
1243         char path[FILE_MAX];
1244
1245         /* get editor data */
1246         if (ANIM_animdata_get_context(C, &ac) == 0)
1247                 return OPERATOR_CANCELLED;
1248
1249         RNA_string_get(op->ptr, "filepath", path);
1250
1251         if (!BLI_is_file(path)) {
1252                 BKE_reportf(op->reports, RPT_ERROR, "File not found '%s'", path);
1253                 return OPERATOR_CANCELLED;
1254         }
1255
1256         scene = ac.scene;    /* current scene */
1257
1258         /* store necessary data for the baking steps */
1259         sbi.samples = AUD_readSoundBuffer(path,
1260                                           RNA_float_get(op->ptr, "low"),
1261                                           RNA_float_get(op->ptr, "high"),
1262                                           RNA_float_get(op->ptr, "attack"),
1263                                           RNA_float_get(op->ptr, "release"),
1264                                           RNA_float_get(op->ptr, "threshold"),
1265                                           RNA_boolean_get(op->ptr, "use_accumulate"),
1266                                           RNA_boolean_get(op->ptr, "use_additive"),
1267                                           RNA_boolean_get(op->ptr, "use_square"),
1268                                           RNA_float_get(op->ptr, "sthreshold"),
1269                                           FPS, &sbi.length);
1270
1271         if (sbi.samples == NULL) {
1272                 BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
1273                 return OPERATOR_CANCELLED;
1274         }
1275
1276         /* determine extents of the baking */
1277         sbi.cfra = start = CFRA;
1278         end = CFRA + sbi.length - 1;
1279
1280         /* filter anim channels */
1281         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1282         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1283
1284         /* loop through all selected F-Curves, replacing its data with the sound samples */
1285         for (ale = anim_data.first; ale; ale = ale->next) {
1286                 FCurve *fcu = (FCurve *)ale->key_data;
1287                 
1288                 /* sample the sound */
1289                 fcurve_store_samples(fcu, &sbi, start, end, fcurve_samplingcb_sound);
1290
1291                 ale->update |= ANIM_UPDATE_DEFAULT;
1292         }
1293
1294         /* free sample data */
1295         free(sbi.samples);
1296
1297         /* validate keyframes after editing */
1298         ANIM_animdata_update(&ac, &anim_data);
1299         ANIM_animdata_freelist(&anim_data);
1300
1301         /* set notifier that 'keyframes' have changed */
1302         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
1303
1304         return OPERATOR_FINISHED;
1305 }
1306
1307 #else //WITH_AUDASPACE
1308
1309 static int graphkeys_sound_bake_exec(bContext *UNUSED(C), wmOperator *op)
1310 {
1311         BKE_report(op->reports, RPT_ERROR, "Compiled without sound support");
1312
1313         return OPERATOR_CANCELLED;
1314 }
1315
1316 #endif //WITH_AUDASPACE
1317
1318 static int graphkeys_sound_bake_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1319 {
1320         bAnimContext ac;
1321
1322         /* verify editor data */
1323         if (ANIM_animdata_get_context(C, &ac) == 0)
1324                 return OPERATOR_CANCELLED;
1325
1326         return WM_operator_filesel(C, op, event);
1327 }
1328
1329 void GRAPH_OT_sound_bake(wmOperatorType *ot)
1330 {
1331         /* identifiers */
1332         ot->name = "Bake Sound to F-Curves";
1333         ot->idname = "GRAPH_OT_sound_bake";
1334         ot->description = "Bakes a sound wave to selected F-Curves";
1335
1336         /* api callbacks */
1337         ot->invoke = graphkeys_sound_bake_invoke;
1338         ot->exec = graphkeys_sound_bake_exec;
1339         ot->poll = graphop_selected_fcurve_poll;
1340
1341         /* flags */
1342         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1343
1344         /* properties */
1345         WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
1346                                        WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
1347         RNA_def_float(ot->srna, "low", 0.0f, 0.0, 100000.0, "Lowest frequency",
1348                       "Cutoff frequency of a high-pass filter that is applied to the audio data", 0.1, 1000.00);
1349         RNA_def_float(ot->srna, "high", 100000.0, 0.0, 100000.0, "Highest frequency",
1350                       "Cutoff frequency of a low-pass filter that is applied to the audio data", 0.1, 1000.00);
1351         RNA_def_float(ot->srna, "attack", 0.005, 0.0, 2.0, "Attack time",
1352                       "Value for the hull curve calculation that tells how fast the hull curve can rise "
1353                       "(the lower the value the steeper it can rise)", 0.01, 0.1);
1354         RNA_def_float(ot->srna, "release", 0.2, 0.0, 5.0, "Release time",
1355                       "Value for the hull curve calculation that tells how fast the hull curve can fall "
1356                       "(the lower the value the steeper it can fall)", 0.01, 0.2);
1357         RNA_def_float(ot->srna, "threshold", 0.0, 0.0, 1.0, "Threshold",
1358                       "Minimum amplitude value needed to influence the hull curve", 0.01, 0.1);
1359         RNA_def_boolean(ot->srna, "use_accumulate", 0, "Accumulate",
1360                         "Only the positive differences of the hull curve amplitudes are summarized to produce the output");
1361         RNA_def_boolean(ot->srna, "use_additive", 0, "Additive",
1362                         "The amplitudes of the hull curve are summarized (or, when Accumulate is enabled, "
1363                         "both positive and negative differences are accumulated)");
1364         RNA_def_boolean(ot->srna, "use_square", 0, "Square",
1365                         "The output is a square curve (negative values always result in -1, and positive ones in 1)");
1366         RNA_def_float(ot->srna, "sthreshold", 0.1, 0.0, 1.0, "Square Threshold",
1367                       "Square only: all values with an absolute amplitude lower than that result in 0", 0.01, 0.1);
1368 }
1369
1370 /* ******************** Sample Keyframes Operator *********************** */
1371 /* This operator 'bakes' the values of the curve into new keyframes between pairs
1372  * of selected keyframes. It is useful for creating keyframes for tweaking overlap.
1373  */
1374
1375 /* Evaluates the curves between each selected keyframe on each frame, and keys the value  */
1376 static void sample_graph_keys(bAnimContext *ac)
1377 {       
1378         ListBase anim_data = {NULL, NULL};
1379         bAnimListElem *ale;
1380         int filter;
1381         
1382         /* filter data */
1383         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1384         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1385         
1386         /* loop through filtered data and add keys between selected keyframes on every frame  */
1387         for (ale = anim_data.first; ale; ale = ale->next) {
1388                 sample_fcurve((FCurve *)ale->key_data);
1389
1390                 ale->update |= ANIM_UPDATE_DEPS;
1391         }
1392
1393         ANIM_animdata_update(ac, &anim_data);
1394         ANIM_animdata_freelist(&anim_data);
1395 }
1396
1397 /* ------------------- */
1398
1399 static int graphkeys_sample_exec(bContext *C, wmOperator *UNUSED(op))
1400 {
1401         bAnimContext ac;
1402         
1403         /* get editor data */
1404         if (ANIM_animdata_get_context(C, &ac) == 0)
1405                 return OPERATOR_CANCELLED;
1406         
1407         /* sample keyframes */
1408         sample_graph_keys(&ac);
1409         
1410         /* set notifier that keyframes have changed */
1411         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
1412         
1413         return OPERATOR_FINISHED;
1414 }
1415  
1416 void GRAPH_OT_sample(wmOperatorType *ot)
1417 {
1418         /* identifiers */
1419         ot->name = "Sample Keyframes";
1420         ot->idname = "GRAPH_OT_sample";
1421         ot->description = "Add keyframes on every frame between the selected keyframes";
1422         
1423         /* api callbacks */
1424         ot->exec = graphkeys_sample_exec;
1425         ot->poll = graphop_editable_keyframes_poll;
1426         
1427         /* flags */
1428         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1429 }
1430
1431
1432 /* ************************************************************************** */
1433 /* SETTINGS STUFF */
1434
1435 /* ******************** Set Extrapolation-Type Operator *********************** */
1436
1437 /* defines for make/clear cyclic extrapolation tools */
1438 #define MAKE_CYCLIC_EXPO    -1
1439 #define CLEAR_CYCLIC_EXPO   -2
1440
1441 /* defines for set extrapolation-type for selected keyframes tool */
1442 static EnumPropertyItem prop_graphkeys_expo_types[] = {
1443         {FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", 0, "Constant Extrapolation", "Values on endpoint keyframes are held"},
1444         {FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", 0, "Linear Extrapolation", "Straight-line slope of end segments are extended past the endpoint keyframes"},
1445         
1446         {MAKE_CYCLIC_EXPO, "MAKE_CYCLIC", 0, "Make Cyclic (F-Modifier)", "Add Cycles F-Modifier if one doesn't exist already"},
1447         {CLEAR_CYCLIC_EXPO, "CLEAR_CYCLIC", 0, "Clear Cyclic (F-Modifier)", "Remove Cycles F-Modifier if not needed anymore"},
1448         {0, NULL, 0, NULL, NULL}
1449 };
1450
1451 /* this function is responsible for setting extrapolation mode for keyframes */
1452 static void setexpo_graph_keys(bAnimContext *ac, short mode) 
1453 {
1454         ListBase anim_data = {NULL, NULL};
1455         bAnimListElem *ale;
1456         int filter;
1457         
1458         /* filter data */
1459         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1460         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1461         
1462         /* loop through setting mode per F-Curve */
1463         for (ale = anim_data.first; ale; ale = ale->next) {
1464                 FCurve *fcu = (FCurve *)ale->data;
1465                 
1466                 if (mode >= 0) {
1467                         /* just set mode setting */
1468                         fcu->extend = mode;
1469
1470                         ale->update |= ANIM_UPDATE_HANDLES;
1471                 }
1472                 else {
1473                         /* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation 
1474                          * without having to go through FModifier UI in Graph Editor to do so
1475                          */
1476                         if (mode == MAKE_CYCLIC_EXPO) {
1477                                 /* only add if one doesn't exist */
1478                                 if (list_has_suitable_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, -1) == 0) {
1479                                         // TODO: add some more preset versions which set different extrapolation options?
1480                                         add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES);
1481                                 }
1482                         }
1483                         else if (mode == CLEAR_CYCLIC_EXPO) {
1484                                 /* remove all the modifiers fitting this description */
1485                                 FModifier *fcm, *fcn = NULL;
1486                                 
1487                                 for (fcm = fcu->modifiers.first; fcm; fcm = fcn) {
1488                                         fcn = fcm->next;
1489                                         
1490                                         if (fcm->type == FMODIFIER_TYPE_CYCLES)
1491                                                 remove_fmodifier(&fcu->modifiers, fcm);
1492                                 }
1493                         }
1494                 }
1495
1496                 ale->update |= ANIM_UPDATE_DEPS;
1497         }
1498
1499         ANIM_animdata_update(ac, &anim_data);
1500         ANIM_animdata_freelist(&anim_data);
1501 }
1502
1503 /* ------------------- */
1504
1505 static int graphkeys_expo_exec(bContext *C, wmOperator *op)
1506 {
1507         bAnimContext ac;
1508         short mode;
1509         
1510         /* get editor data */
1511         if (ANIM_animdata_get_context(C, &ac) == 0)
1512                 return OPERATOR_CANCELLED;
1513                 
1514         /* get handle setting mode */
1515         mode = RNA_enum_get(op->ptr, "type");
1516         
1517         /* set handle type */
1518         setexpo_graph_keys(&ac, mode);
1519         
1520         /* set notifier that keyframe properties have changed */
1521         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
1522         
1523         return OPERATOR_FINISHED;
1524 }
1525  
1526 void GRAPH_OT_extrapolation_type(wmOperatorType *ot)
1527 {
1528         /* identifiers */
1529         ot->name = "Set Keyframe Extrapolation";
1530         ot->idname = "GRAPH_OT_extrapolation_type";
1531         ot->description = "Set extrapolation mode for selected F-Curves";
1532         
1533         /* api callbacks */
1534         ot->invoke = WM_menu_invoke;
1535         ot->exec = graphkeys_expo_exec;
1536         ot->poll = graphop_editable_keyframes_poll;
1537         
1538         /* flags */
1539         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1540         
1541         /* id-props */
1542         ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_expo_types, 0, "Type", "");
1543 }
1544
1545 /* ******************** Set Interpolation-Type Operator *********************** */
1546
1547 /* this function is responsible for setting interpolation mode for keyframes */
1548 static void setipo_graph_keys(bAnimContext *ac, short mode) 
1549 {
1550         ListBase anim_data = {NULL, NULL};
1551         bAnimListElem *ale;
1552         int filter;
1553         KeyframeEditFunc set_cb = ANIM_editkeyframes_ipo(mode);
1554         
1555         /* filter data */
1556         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1557         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1558         
1559         /* loop through setting BezTriple interpolation
1560          * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
1561          */
1562         for (ale = anim_data.first; ale; ale = ale->next) {
1563                 ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
1564
1565                 ale->update |= ANIM_UPDATE_DEFAULT_NOHANDLES;
1566         }
1567
1568         ANIM_animdata_update(ac, &anim_data);
1569         ANIM_animdata_freelist(&anim_data);
1570 }
1571
1572 /* ------------------- */
1573
1574 static int graphkeys_ipo_exec(bContext *C, wmOperator *op)
1575 {
1576         bAnimContext ac;
1577         short mode;
1578         
1579         /* get editor data */
1580         if (ANIM_animdata_get_context(C, &ac) == 0)
1581                 return OPERATOR_CANCELLED;
1582                 
1583         /* get handle setting mode */
1584         mode = RNA_enum_get(op->ptr, "type");
1585         
1586         /* set handle type */
1587         setipo_graph_keys(&ac, mode);
1588         
1589         /* set notifier that keyframe properties have changed */
1590         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
1591         
1592         return OPERATOR_FINISHED;
1593 }
1594  
1595 void GRAPH_OT_interpolation_type(wmOperatorType *ot)
1596 {
1597         /* identifiers */
1598         ot->name = "Set Keyframe Interpolation";
1599         ot->idname = "GRAPH_OT_interpolation_type";
1600         ot->description = "Set interpolation mode for the F-Curve segments starting from the selected keyframes";
1601         
1602         /* api callbacks */
1603         ot->invoke = WM_menu_invoke;
1604         ot->exec = graphkeys_ipo_exec;
1605         ot->poll = graphop_editable_keyframes_poll;
1606         
1607         /* flags */
1608         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1609         
1610         /* id-props */
1611         ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_interpolation_mode_items, 0, "Type", "");
1612 }
1613
1614 /* ******************** Set Easing Operator *********************** */
1615
1616 static void seteasing_graph_keys(bAnimContext *ac, short mode)
1617 {
1618         ListBase anim_data = {NULL, NULL};
1619         bAnimListElem *ale;
1620         int filter;
1621         KeyframeEditFunc set_cb = ANIM_editkeyframes_easing(mode);
1622         
1623         /* filter data */
1624         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1625         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1626         
1627         /* loop through setting BezTriple easing
1628          * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
1629          */
1630         for (ale = anim_data.first; ale; ale = ale->next) {
1631                 ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
1632
1633                 ale->update |= ANIM_UPDATE_DEFAULT_NOHANDLES;
1634         }
1635
1636         ANIM_animdata_update(ac, &anim_data);
1637         ANIM_animdata_freelist(&anim_data);
1638 }
1639
1640 static int graphkeys_easing_exec(bContext *C, wmOperator *op)
1641 {
1642         bAnimContext ac;
1643         short mode;
1644         
1645         /* get editor data */
1646         if (ANIM_animdata_get_context(C, &ac) == 0)
1647                 return OPERATOR_CANCELLED;
1648         
1649         /* get handle setting mode */
1650         mode = RNA_enum_get(op->ptr, "type");
1651         
1652         /* set handle type */
1653         seteasing_graph_keys(&ac, mode);
1654         
1655         /* set notifier that keyframe properties have changed */
1656         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
1657         
1658         return OPERATOR_FINISHED;
1659 }
1660
1661 void GRAPH_OT_easing_type(wmOperatorType *ot)
1662 {
1663         /* identifiers */
1664         ot->name = "Set Keyframe Easing Type";
1665         ot->idname = "GRAPH_OT_easing_type";
1666         ot->description = "Set easing type for the F-Curve segments starting from the selected keyframes";
1667         
1668         /* api callbacks */
1669         ot->invoke = WM_menu_invoke;
1670         ot->exec = graphkeys_easing_exec;
1671         ot->poll = graphop_editable_keyframes_poll;
1672         
1673         /* flags */
1674         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1675         
1676         /* id-props */
1677         ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_interpolation_easing_items, 0, "Type", "");
1678 }
1679
1680 /* ******************** Set Handle-Type Operator *********************** */
1681
1682 /* this function is responsible for setting handle-type of selected keyframes */
1683 static void sethandles_graph_keys(bAnimContext *ac, short mode) 
1684 {
1685         ListBase anim_data = {NULL, NULL};
1686         bAnimListElem *ale;
1687         int filter;
1688         
1689         KeyframeEditFunc edit_cb = ANIM_editkeyframes_handles(mode);
1690         KeyframeEditFunc sel_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
1691         
1692         /* filter data */
1693         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1694         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1695         
1696         /* loop through setting flags for handles 
1697          * Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
1698          */
1699         for (ale = anim_data.first; ale; ale = ale->next) {
1700                 FCurve *fcu = (FCurve *)ale->key_data;
1701                 
1702                 /* any selected keyframes for editing? */
1703                 if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) {
1704                         /* change type of selected handles */
1705                         ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve);
1706
1707                         ale->update |= ANIM_UPDATE_DEFAULT;
1708                 }
1709         }
1710
1711         ANIM_animdata_update(ac, &anim_data);
1712         ANIM_animdata_freelist(&anim_data);
1713 }
1714 /* ------------------- */
1715
1716 static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
1717 {
1718         bAnimContext ac;
1719         short mode;
1720         
1721         /* get editor data */
1722         if (ANIM_animdata_get_context(C, &ac) == 0)
1723                 return OPERATOR_CANCELLED;
1724                 
1725         /* get handle setting mode */
1726         mode = RNA_enum_get(op->ptr, "type");
1727         
1728         /* set handle type */
1729         sethandles_graph_keys(&ac, mode);
1730         
1731         /* set notifier that keyframe properties have changed */
1732         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
1733         
1734         return OPERATOR_FINISHED;
1735 }
1736  
1737 void GRAPH_OT_handle_type(wmOperatorType *ot)
1738 {
1739         /* identifiers */
1740         ot->name = "Set Keyframe Handle Type";
1741         ot->idname = "GRAPH_OT_handle_type";
1742         ot->description = "Set type of handle for selected keyframes";
1743         
1744         /* api callbacks */
1745         ot->invoke = WM_menu_invoke;
1746         ot->exec = graphkeys_handletype_exec;
1747         ot->poll = graphop_editable_keyframes_poll;
1748         
1749         /* flags */
1750         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1751         
1752         /* id-props */
1753         ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", "");
1754 }
1755
1756 /* ************************************************************************** */
1757 /* TRANSFORM STUFF */
1758
1759 /* ***************** 'Euler Filter' Operator **************************** */
1760 /* Euler filter tools (as seen in Maya), are necessary for working with 'baked'
1761  * rotation curves (with Euler rotations). The main purpose of such tools is to
1762  * resolve any discontinuities that may arise in the curves due to the clamping
1763  * of values to -180 degrees to 180 degrees.
1764  */
1765
1766 /* set of three euler-rotation F-Curves */
1767 typedef struct tEulerFilter {
1768         struct tEulerFilter *next, *prev;
1769         
1770         ID *id;                         /* ID-block which owns the channels */
1771         FCurve *(fcurves[3]);           /* 3 Pointers to F-Curves */
1772         const char *rna_path;           /* Pointer to one of the RNA Path's used by one of the F-Curves */
1773 } tEulerFilter;
1774  
1775 static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
1776 {
1777         bAnimContext ac;
1778         
1779         ListBase anim_data = {NULL, NULL};
1780         bAnimListElem *ale;
1781         int filter;
1782         
1783         ListBase eulers = {NULL, NULL};
1784         tEulerFilter *euf = NULL;
1785         int groups = 0, failed = 0;
1786         
1787         /* get editor data */
1788         if (ANIM_animdata_get_context(C, &ac) == 0)
1789                 return OPERATOR_CANCELLED;
1790                 
1791         /* The process is done in two passes:
1792          *   1) Sets of three related rotation curves are identified from the selected channels,
1793          *              and are stored as a single 'operation unit' for the next step
1794          *       2) Each set of three F-Curves is processed for each keyframe, with the values being
1795          *      processed as necessary
1796          */
1797          
1798         /* step 1: extract only the rotation f-curves */
1799         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1800         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1801         
1802         for (ale = anim_data.first; ale; ale = ale->next) {
1803                 FCurve *fcu = (FCurve *)ale->data;
1804                 
1805                 /* check if this is an appropriate F-Curve 
1806                  *      - only rotation curves
1807                  *      - for pchan curves, make sure we're only using the euler curves
1808                  */
1809                 if (strstr(fcu->rna_path, "rotation_euler") == NULL)
1810                         continue;
1811                 else if (ELEM(fcu->array_index, 0, 1, 2) == 0) {
1812                         BKE_reportf(op->reports, RPT_WARNING,
1813                                     "Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)",
1814                                     (ale->id) ? ale->id->name : TIP_("<No ID>"), fcu->rna_path, fcu->array_index);
1815                         continue;
1816                 }
1817                 
1818                 /* optimization: assume that xyz curves will always be stored consecutively,
1819                  * so if the paths or the ID's don't match up, then a curve needs to be added 
1820                  * to a new group
1821                  */
1822                 if ((euf) && (euf->id == ale->id) && (STREQ(euf->rna_path, fcu->rna_path))) {
1823                         /* this should be fine to add to the existing group then */
1824                         euf->fcurves[fcu->array_index] = fcu;
1825                 }
1826                 else {
1827                         /* just add to a new block */
1828                         euf = MEM_callocN(sizeof(tEulerFilter), "tEulerFilter");
1829                         BLI_addtail(&eulers, euf);
1830                         groups++;
1831                         
1832                         euf->id = ale->id;
1833                         euf->rna_path = fcu->rna_path; /* this should be safe, since we're only using it for a short time */
1834                         euf->fcurves[fcu->array_index] = fcu;
1835                 }
1836
1837                 ale->update |= ANIM_UPDATE_DEFAULT;
1838         }
1839
1840         if (groups == 0) {
1841                 ANIM_animdata_freelist(&anim_data);
1842                 BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up");
1843                 return OPERATOR_CANCELLED;
1844         }
1845         
1846         /* step 2: go through each set of curves, processing the values at each keyframe 
1847          *      - it is assumed that there must be a full set of keyframes at each keyframe position
1848          */
1849         for (euf = eulers.first; euf; euf = euf->next) {
1850                 int f;
1851                 
1852                 /* sanity check: ensure that there are enough F-Curves to work on in this group */
1853                 /* TODO: also enforce assumption that there be a full set of keyframes at each position by ensuring that totvert counts are same? */
1854                 if (ELEM(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) {
1855                         /* report which components are missing */
1856                         BKE_reportf(op->reports, RPT_WARNING,
1857                                     "Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'",
1858                                     (euf->fcurves[0] == NULL) ? "X" : "",
1859                                     (euf->fcurves[1] == NULL) ? "Y" : "",
1860                                     (euf->fcurves[2] == NULL) ? "Z" : "",
1861                                     euf->id->name, euf->rna_path);
1862                                 
1863                         /* keep track of number of failed sets, and carry on to next group */
1864                         failed++;
1865                         continue;
1866                 }
1867
1868                 /* simple method: just treat any difference between keys of greater than 180 degrees as being a flip */
1869                 /* FIXME: there are more complicated methods that will be needed to fix more cases than just some */
1870                 for (f = 0; f < 3; f++) {
1871                         FCurve *fcu = euf->fcurves[f];
1872                         BezTriple *bezt, *prev;
1873                         unsigned int i;
1874                         
1875                         /* skip if not enough vets to do a decent analysis of... */
1876                         if (fcu->totvert <= 2)
1877                                 continue;
1878                         
1879                         /* prev follows bezt, bezt = "current" point to be fixed */
1880                         /* our method depends on determining a "difference" from the previous vert */
1881                         for (i = 1, prev = fcu->bezt, bezt = fcu->bezt + 1; i < fcu->totvert; i++, prev = bezt++) {
1882                                 const float sign = (prev->vec[1][1] > bezt->vec[1][1]) ? 1.0f : -1.0f;
1883                                 
1884                                 /* > 180 degree flip? */
1885                                 if ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) {
1886                                         /* 360 degrees to add/subtract frame value until difference is acceptably small that there's no more flip */
1887                                         const float fac = sign * 2.0f * (float)M_PI;
1888                                         
1889                                         while ((sign * (prev->vec[1][1] - bezt->vec[1][1])) >= (float)M_PI) {
1890                                                 bezt->vec[0][1] += fac;
1891                                                 bezt->vec[1][1] += fac;
1892                                                 bezt->vec[2][1] += fac;
1893                                         }
1894                                 }
1895                         }
1896                 }
1897         }
1898         BLI_freelistN(&eulers);
1899         
1900         ANIM_animdata_update(&ac, &anim_data);
1901         ANIM_animdata_freelist(&anim_data);
1902
1903         /* updates + finishing warnings */
1904         if (failed == groups) {
1905                 BKE_report(op->reports, RPT_ERROR, 
1906                            "No Euler Rotations could be corrected, ensure each rotation has keys for all components, "
1907                            "and that F-Curves for these are in consecutive XYZ order and selected");
1908                 return OPERATOR_CANCELLED;
1909         }
1910         else {
1911                 if (failed) {
1912                         BKE_report(op->reports, RPT_ERROR,
1913                                    "Some Euler Rotations could not be corrected due to missing/unselected/out-of-order F-Curves, "
1914                                    "ensure each rotation has keys for all components, and that F-Curves for these are in "
1915                                    "consecutive XYZ order and selected");
1916                 }
1917                 
1918                 /* set notifier that keyframes have changed */
1919                 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
1920                 
1921                 /* done at last */
1922                 return OPERATOR_FINISHED;
1923         }
1924 }
1925  
1926 void GRAPH_OT_euler_filter(wmOperatorType *ot)
1927 {
1928         /* identifiers */
1929         ot->name = "Euler Discontinuity Filter";
1930         ot->idname = "GRAPH_OT_euler_filter";
1931         ot->description = "Fix large jumps and flips in the selected "
1932                           "Euler Rotation F-Curves arising from rotation "
1933                           "values being clipped when baking physics";
1934         
1935         /* api callbacks */
1936         ot->exec = graphkeys_euler_filter_exec;
1937         ot->poll = graphop_editable_keyframes_poll;
1938         
1939         /* flags */
1940         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1941 }
1942
1943 /* ***************** Jump to Selected Frames Operator *********************** */
1944
1945 static int graphkeys_framejump_poll(bContext *C)
1946 {
1947         /* prevent changes during render */
1948         if (G.is_rendering)
1949                 return 0;
1950
1951         return graphop_visible_keyframes_poll(C);
1952 }
1953
1954 /* snap current-frame indicator to 'average time' of selected keyframe */
1955 static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
1956 {
1957         bAnimContext ac;
1958         ListBase anim_data = {NULL, NULL};
1959         bAnimListElem *ale;
1960         int filter;
1961         KeyframeEditData ked;
1962         
1963         /* get editor data */
1964         if (ANIM_animdata_get_context(C, &ac) == 0)
1965                 return OPERATOR_CANCELLED;
1966         
1967         /* init edit data */
1968         memset(&ked, 0, sizeof(KeyframeEditData));
1969         
1970         /* loop over action data, averaging values */
1971         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
1972         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1973         
1974         for (ale = anim_data.first; ale; ale = ale->next) {
1975                 AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
1976                 short mapping_flag = ANIM_get_normalization_flags(&ac);
1977                 KeyframeEditData current_ked;
1978                 float offset;
1979                 float unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS, &offset);
1980
1981                 memset(&current_ked, 0, sizeof(current_ked));
1982
1983                 if (adt) {
1984                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
1985                         ANIM_fcurve_keyframes_loop(&current_ked, ale->key_data, NULL, bezt_calc_average, NULL);
1986                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); 
1987                 }
1988                 else
1989                         ANIM_fcurve_keyframes_loop(&current_ked, ale->key_data, NULL, bezt_calc_average, NULL);
1990
1991                 ked.f1 += current_ked.f1;
1992                 ked.i1 += current_ked.i1;
1993                 ked.f2 += (current_ked.f2 + offset) * unit_scale;
1994                 ked.i2 += current_ked.i2;
1995         }
1996         
1997         ANIM_animdata_freelist(&anim_data);
1998         
1999         /* set the new current frame and cursor values, based on the average time and value */
2000         if (ked.i1) {
2001                 SpaceIpo *sipo = (SpaceIpo *)ac.sl;
2002                 Scene *scene = ac.scene;
2003                 
2004                 /* take the average values, rounding to the nearest int as necessary for int results */
2005                 if (sipo->mode == SIPO_MODE_DRIVERS) {
2006                         /* Drivers Mode - Affects cursor (float) */
2007                         sipo->cursorTime = ked.f1 / (float)ked.i1;
2008                         sipo->cursorVal  = ked.f2 / (float)ked.i1;
2009                 }
2010                 else {
2011                         /* Animation Mode - Affects current frame (int) */
2012                         CFRA = iroundf(ked.f1 / ked.i1);
2013                         SUBFRA = 0.f;
2014                         sipo->cursorVal = ked.f2 / (float)ked.i1;
2015                 }
2016         }
2017         
2018         /* set notifier that things have changed */
2019         WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene);
2020         
2021         return OPERATOR_FINISHED;
2022 }
2023
2024 void GRAPH_OT_frame_jump(wmOperatorType *ot)
2025 {
2026         /* identifiers */
2027         ot->name = "Jump to Keyframes";
2028         ot->idname = "GRAPH_OT_frame_jump";
2029         ot->description = "Place the cursor on the midpoint of selected keyframes";
2030         
2031         /* api callbacks */
2032         ot->exec = graphkeys_framejump_exec;
2033         ot->poll = graphkeys_framejump_poll;
2034         
2035         /* flags */
2036         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2037 }
2038
2039 /* ******************** Snap Keyframes Operator *********************** */
2040
2041 /* defines for snap keyframes tool */
2042 static EnumPropertyItem prop_graphkeys_snap_types[] = {
2043         {GRAPHKEYS_SNAP_CFRA, "CFRA", 0, "Current Frame",
2044          "Snap selected keyframes to the current frame"},
2045         {GRAPHKEYS_SNAP_VALUE, "VALUE", 0, "Cursor Value",
2046          "Set values of selected keyframes to the cursor value (Y/Horizontal component)"},
2047         {GRAPHKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame",
2048          "Snap selected keyframes to the nearest (whole) frame (use to fix accidental sub-frame offsets)"},
2049         {GRAPHKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second",
2050          "Snap selected keyframes to the nearest second"},
2051         {GRAPHKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker",
2052          "Snap selected keyframes to the nearest marker"},
2053         {GRAPHKEYS_SNAP_HORIZONTAL, "HORIZONTAL", 0, "Flatten Handles",
2054          "Flatten handles for a smoother transition"},
2055         {0, NULL, 0, NULL, NULL}
2056 };
2057
2058 /* this function is responsible for snapping keyframes to frame-times */
2059 static void snap_graph_keys(bAnimContext *ac, short mode) 
2060 {
2061         ListBase anim_data = {NULL, NULL};
2062         bAnimListElem *ale;
2063         int filter;
2064         
2065         SpaceIpo *sipo = (SpaceIpo *)ac->sl;
2066         KeyframeEditData ked;
2067         KeyframeEditFunc edit_cb;
2068         float cursor_value = 0.0f;
2069         
2070         /* filter data */
2071         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
2072         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2073         
2074         /* init custom data for iterating over keyframes */
2075         memset(&ked, 0, sizeof(KeyframeEditData)); 
2076         ked.scene = ac->scene;
2077         if (mode == GRAPHKEYS_SNAP_NEAREST_MARKER) {
2078                 ked.list.first = (ac->markers) ? ac->markers->first : NULL;
2079                 ked.list.last = (ac->markers) ? ac->markers->last : NULL;
2080         }
2081         else if (mode == GRAPHKEYS_SNAP_VALUE) {
2082                 cursor_value = (sipo) ? sipo->cursorVal : 0.0f;
2083         }
2084         else if (mode == GRAPHKEYS_SNAP_CFRA) {
2085                 /* In drivers mode, use the cursor value instead
2086                  * (We need to use a different callback for that though)
2087                  */
2088                 if (sipo->mode == SIPO_MODE_DRIVERS) {
2089                         ked.f1 = sipo->cursorTime;
2090                         mode = SNAP_KEYS_TIME;
2091                 }
2092         }
2093         
2094         /* get beztriple editing callbacks */
2095         edit_cb = ANIM_editkeyframes_snap(mode);
2096         
2097         /* snap keyframes */
2098         for (ale = anim_data.first; ale; ale = ale->next) {
2099                 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
2100                 
2101                 /* normalise cursor value (for normalised F-Curves display) */
2102                 if (mode == GRAPHKEYS_SNAP_VALUE) {
2103                         short mapping_flag = ANIM_get_normalization_flags(ac);
2104                         float offset;
2105                         float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag, &offset);
2106                         
2107                         ked.f1 = (cursor_value / unit_scale) - offset;
2108                 }
2109                 
2110                 /* perform snapping */
2111                 if (adt) {
2112                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
2113                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
2114                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
2115                 }
2116                 else 
2117                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
2118                 
2119                 ale->update |= ANIM_UPDATE_DEFAULT;
2120         }
2121
2122         ANIM_animdata_update(ac, &anim_data);
2123         ANIM_animdata_freelist(&anim_data);
2124 }
2125
2126 /* ------------------- */
2127
2128 static int graphkeys_snap_exec(bContext *C, wmOperator *op)
2129 {
2130         bAnimContext ac;
2131         short mode;
2132         
2133         /* get editor data */
2134         if (ANIM_animdata_get_context(C, &ac) == 0)
2135                 return OPERATOR_CANCELLED;
2136                 
2137         /* get snapping mode */
2138         mode = RNA_enum_get(op->ptr, "type");
2139         
2140         /* snap keyframes */
2141         snap_graph_keys(&ac, mode);
2142         
2143         /* set notifier that keyframes have changed */
2144         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
2145         
2146         return OPERATOR_FINISHED;
2147 }
2148  
2149 void GRAPH_OT_snap(wmOperatorType *ot)
2150 {
2151         /* identifiers */
2152         ot->name = "Snap Keys";
2153         ot->idname = "GRAPH_OT_snap";
2154         ot->description = "Snap selected keyframes to the chosen times/values";
2155         
2156         /* api callbacks */
2157         ot->invoke = WM_menu_invoke;
2158         ot->exec = graphkeys_snap_exec;
2159         ot->poll = graphop_editable_keyframes_poll;
2160         
2161         /* flags */
2162         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2163         
2164         /* id-props */
2165         ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_snap_types, 0, "Type", "");
2166 }
2167
2168 /* ******************** Mirror Keyframes Operator *********************** */
2169
2170 /* defines for mirror keyframes tool */
2171 static EnumPropertyItem prop_graphkeys_mirror_types[] = {
2172         {GRAPHKEYS_MIRROR_CFRA, "CFRA", 0, "By Times over Current Frame",
2173          "Flip times of selected keyframes using the current frame as the mirror line"},
2174         {GRAPHKEYS_MIRROR_VALUE, "VALUE", 0, "By Values over Cursor Value",
2175          "Flip values of selected keyframes using the cursor value (Y/Horizontal component) as the mirror line"},
2176         {GRAPHKEYS_MIRROR_YAXIS, "YAXIS", 0, "By Times over Time=0",
2177          "Flip times of selected keyframes, effectively reversing the order they appear in"},
2178         {GRAPHKEYS_MIRROR_XAXIS, "XAXIS", 0, "By Values over Value=0",
2179          "Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
2180         {GRAPHKEYS_MIRROR_MARKER, "MARKER", 0, "By Times over First Selected Marker",
2181          "Flip times of selected keyframes using the first selected marker as the reference point"},
2182         {0, NULL, 0, NULL, NULL}
2183 };
2184
2185 /* this function is responsible for mirroring keyframes */
2186 static void mirror_graph_keys(bAnimContext *ac, short mode) 
2187 {
2188         ListBase anim_data = {NULL, NULL};
2189         bAnimListElem *ale;
2190         int filter;
2191         
2192         SpaceIpo *sipo = (SpaceIpo *)ac->sl;
2193         KeyframeEditData ked;
2194         KeyframeEditFunc edit_cb;
2195         float cursor_value = 0.0f;
2196
2197         /* init custom data for looping over keyframes */
2198         memset(&ked, 0, sizeof(KeyframeEditData)); 
2199         ked.scene = ac->scene;
2200         
2201         /* store mode-specific custom data... */
2202         if (mode == GRAPHKEYS_MIRROR_MARKER) {
2203                 TimeMarker *marker = NULL;
2204                 
2205                 /* find first selected marker */
2206                 marker = ED_markers_get_first_selected(ac->markers);
2207                 
2208                 /* store marker's time (if available) */
2209                 if (marker)
2210                         ked.f1 = (float)marker->frame;
2211                 else
2212                         return;
2213         }
2214         else if (mode == GRAPHKEYS_MIRROR_VALUE) {
2215                 cursor_value = (sipo) ? sipo->cursorVal : 0.0f;
2216         }
2217         else if (mode == GRAPHKEYS_MIRROR_CFRA) {
2218                 /* In drivers mode, use the cursor value instead
2219                  * (We need to use a different callback for that though)
2220                  */
2221                 if (sipo->mode == SIPO_MODE_DRIVERS) {
2222                         ked.f1 = sipo->cursorTime;
2223                         mode = MIRROR_KEYS_TIME;
2224                 }
2225         }
2226         
2227         /* get beztriple editing callbacks */
2228         edit_cb = ANIM_editkeyframes_mirror(mode);
2229         
2230         /* filter data */
2231         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
2232         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2233         
2234         /* mirror keyframes */
2235         for (ale = anim_data.first; ale; ale = ale->next) {
2236                 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
2237                 
2238                 /* apply unit corrections */
2239                 if (mode == GRAPHKEYS_MIRROR_VALUE) {
2240                         short mapping_flag = ANIM_get_normalization_flags(ac);
2241                         float offset;
2242                         float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, ale->key_data, mapping_flag | ANIM_UNITCONV_ONLYKEYS, &offset);
2243                         
2244                         ked.f1 = (cursor_value + offset) * unit_scale;
2245                 }
2246                 
2247                 /* perform actual mirroring */
2248                 if (adt) {
2249                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 
2250                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
2251                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
2252                 }
2253                 else 
2254                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
2255                 
2256                 ale->update |= ANIM_UPDATE_DEFAULT;
2257         }
2258
2259         ANIM_animdata_update(ac, &anim_data);
2260         ANIM_animdata_freelist(&anim_data);
2261 }
2262
2263 /* ------------------- */
2264
2265 static int graphkeys_mirror_exec(bContext *C, wmOperator *op)
2266 {
2267         bAnimContext ac;
2268         short mode;
2269         
2270         /* get editor data */
2271         if (ANIM_animdata_get_context(C, &ac) == 0)
2272                 return OPERATOR_CANCELLED;
2273                 
2274         /* get mirroring mode */
2275         mode = RNA_enum_get(op->ptr, "type");
2276         
2277         /* mirror keyframes */
2278         mirror_graph_keys(&ac, mode);
2279         
2280         /* set notifier that keyframes have changed */
2281         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
2282         
2283         return OPERATOR_FINISHED;
2284 }
2285  
2286 void GRAPH_OT_mirror(wmOperatorType *ot)
2287 {
2288         /* identifiers */
2289         ot->name = "Mirror Keys";
2290         ot->idname = "GRAPH_OT_mirror";
2291         ot->description = "Flip selected keyframes over the selected mirror line";
2292         
2293         /* api callbacks */
2294         ot->invoke = WM_menu_invoke;
2295         ot->exec = graphkeys_mirror_exec;
2296         ot->poll = graphop_editable_keyframes_poll;
2297         
2298         /* flags */
2299         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2300         
2301         /* id-props */
2302         ot->prop = RNA_def_enum(ot->srna, "type", prop_graphkeys_mirror_types, 0, "Type", "");
2303 }
2304
2305 /* ******************** Smooth Keyframes Operator *********************** */
2306
2307 static int graphkeys_smooth_exec(bContext *C, wmOperator *UNUSED(op))
2308 {
2309         bAnimContext ac;
2310         ListBase anim_data = {NULL, NULL};
2311         bAnimListElem *ale;
2312         int filter;
2313         
2314         /* get editor data */
2315         if (ANIM_animdata_get_context(C, &ac) == 0)
2316                 return OPERATOR_CANCELLED;
2317         
2318         /* filter data */
2319         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
2320         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2321         
2322         /* smooth keyframes */
2323         for (ale = anim_data.first; ale; ale = ale->next) {
2324                 /* For now, we can only smooth by flattening handles AND smoothing curve values.
2325                  * Perhaps the mode argument could be removed, as that functionality is offered through
2326                  * Snap->Flatten Handles anyway.
2327                  */
2328                 smooth_fcurve(ale->key_data);
2329
2330                 ale->update |= ANIM_UPDATE_DEFAULT;
2331         }
2332
2333         ANIM_animdata_update(&ac, &anim_data);
2334         ANIM_animdata_freelist(&anim_data);
2335         
2336         /* set notifier that keyframes have changed */
2337         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
2338         
2339         return OPERATOR_FINISHED;
2340 }
2341  
2342 void GRAPH_OT_smooth(wmOperatorType *ot)
2343 {
2344         /* identifiers */
2345         ot->name = "Smooth Keys";
2346         ot->idname = "GRAPH_OT_smooth";
2347         ot->description = "Apply weighted moving means to make selected F-Curves less bumpy";
2348         
2349         /* api callbacks */
2350         ot->exec = graphkeys_smooth_exec;
2351         ot->poll = graphop_editable_keyframes_poll;
2352         
2353         /* flags */
2354         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2355 }
2356
2357 /* ************************************************************************** */
2358 /* F-CURVE MODIFIERS */
2359
2360 /* ******************** Add F-Modifier Operator *********************** */
2361
2362 static EnumPropertyItem *graph_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
2363 {
2364         EnumPropertyItem *item = NULL;
2365         int totitem = 0;
2366         int i = 0;
2367
2368         if (C == NULL) {
2369                 return rna_enum_fmodifier_type_items;
2370         }
2371
2372         /* start from 1 to skip the 'Invalid' modifier type */
2373         for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
2374                 const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
2375                 int index;
2376
2377                 /* check if modifier is valid for this context */
2378                 if (fmi == NULL)
2379                         continue;
2380
2381                 index = RNA_enum_from_value(rna_enum_fmodifier_type_items, fmi->type);
2382                 RNA_enum_item_add(&item, &totitem, &rna_enum_fmodifier_type_items[index]);
2383         }
2384
2385         RNA_enum_item_end(&item, &totitem);
2386         *r_free = true;
2387
2388         return item;
2389 }
2390
2391 static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
2392 {
2393         bAnimContext ac;
2394         ListBase anim_data = {NULL, NULL};
2395         bAnimListElem *ale;
2396         int filter;
2397         short type;
2398         
2399         /* get editor data */
2400         if (ANIM_animdata_get_context(C, &ac) == 0)
2401                 return OPERATOR_CANCELLED;
2402         
2403         /* get type of modifier to add */
2404         type = RNA_enum_get(op->ptr, "type");
2405         
2406         /* filter data */
2407         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
2408         if (RNA_boolean_get(op->ptr, "only_active"))
2409                 filter |= ANIMFILTER_ACTIVE;  // FIXME: enforce in this case only a single channel to get handled?
2410         else
2411                 filter |= (ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE);
2412         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2413         
2414         /* add f-modifier to each curve */
2415         for (ale = anim_data.first; ale; ale = ale->next) {
2416                 FCurve *fcu = (FCurve *)ale->data;
2417                 FModifier *fcm;
2418                 
2419                 /* add F-Modifier of specified type to active F-Curve, and make it the active one */
2420                 fcm = add_fmodifier(&fcu->modifiers, type);
2421                 if (fcm) {
2422                         set_active_fmodifier(&fcu->modifiers, fcm);
2423                 }
2424                 else {
2425                         BKE_report(op->reports, RPT_ERROR, "Modifier could not be added (see console for details)");
2426                         break;
2427                 }
2428
2429                 ale->update |= ANIM_UPDATE_DEPS;
2430         }
2431
2432         ANIM_animdata_update(&ac, &anim_data);
2433         ANIM_animdata_freelist(&anim_data);
2434         
2435         /* set notifier that things have changed */
2436         // FIXME: this really isn't the best description for it...
2437         WM_event_add_notifier(C, NC_ANIMATION, NULL);
2438         
2439         return OPERATOR_FINISHED;
2440 }
2441  
2442 void GRAPH_OT_fmodifier_add(wmOperatorType *ot)
2443 {
2444         PropertyRNA *prop;
2445
2446         /* identifiers */
2447         ot->name = "Add F-Curve Modifier";
2448         ot->idname = "GRAPH_OT_fmodifier_add";
2449         ot->description = "Add F-Modifiers to the selected F-Curves";
2450         
2451         /* api callbacks */
2452         ot->invoke = WM_menu_invoke;
2453         ot->exec = graph_fmodifier_add_exec;
2454         ot->poll = graphop_selected_fcurve_poll; 
2455         
2456         /* flags */
2457         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2458         
2459         /* id-props */
2460         prop = RNA_def_enum(ot->srna, "type", rna_enum_fmodifier_type_items, 0, "Type", "");
2461         RNA_def_enum_funcs(prop, graph_fmodifier_itemf);
2462         ot->prop = prop;
2463
2464         RNA_def_boolean(ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve");
2465 }
2466
2467 /* ******************** Copy F-Modifiers Operator *********************** */
2468
2469 static int graph_fmodifier_copy_exec(bContext *C, wmOperator *op)
2470 {
2471         bAnimContext ac;
2472         bAnimListElem *ale;
2473         bool ok = false;
2474         
2475         /* get editor data */
2476         if (ANIM_animdata_get_context(C, &ac) == 0)
2477                 return OPERATOR_CANCELLED;
2478         
2479         /* clear buffer first */
2480         free_fmodifiers_copybuf();
2481         
2482         /* get the active F-Curve */
2483         ale = get_active_fcurve_channel(&ac);
2484         
2485         /* if this exists, call the copy F-Modifiers API function */
2486         if (ale && ale->data) {
2487                 FCurve *fcu = (FCurve *)ale->data;
2488
2489                 /* TODO: when 'active' vs 'all' boolean is added, change last param! */
2490                 ok = ANIM_fmodifiers_copy_to_buf(&fcu->modifiers, 0);
2491
2492                 /* free temp data now */
2493                 MEM_freeN(ale);
2494         }
2495         
2496         /* successful or not? */
2497         if (ok == 0) {
2498                 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
2499                 return OPERATOR_CANCELLED;
2500         }
2501         else
2502                 return OPERATOR_FINISHED;
2503 }
2504  
2505 void GRAPH_OT_fmodifier_copy(wmOperatorType *ot)
2506 {
2507         /* identifiers */
2508         ot->name = "Copy F-Modifiers";
2509         ot->idname = "GRAPH_OT_fmodifier_copy";
2510         ot->description = "Copy the F-Modifier(s) of the active F-Curve";
2511         
2512         /* api callbacks */
2513         ot->exec = graph_fmodifier_copy_exec;
2514         ot->poll = graphop_active_fcurve_poll; 
2515         
2516         /* flags */
2517         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2518         
2519         /* id-props */
2520         //ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one");
2521 }
2522
2523 /* ******************** Paste F-Modifiers Operator *********************** */
2524
2525 static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op)
2526 {
2527         bAnimContext ac;
2528         ListBase anim_data = {NULL, NULL};
2529         bAnimListElem *ale;
2530         int filter, ok = 0;
2531         
2532         /* get editor data */
2533         if (ANIM_animdata_get_context(C, &ac) == 0)
2534                 return OPERATOR_CANCELLED;
2535         
2536         /* filter data */
2537         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
2538         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2539         
2540         /* paste modifiers */
2541         for (ale = anim_data.first; ale; ale = ale->next) {
2542                 FCurve *fcu = (FCurve *)ale->data;
2543                 int tot;
2544
2545                 /* TODO: do we want to replace existing modifiers? add user pref for that! */
2546                 tot = ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, 0);
2547
2548                 if (tot) {
2549                         ale->update |= ANIM_UPDATE_DEPS;
2550                 }
2551
2552                 ok += tot;
2553         }
2554
2555         if (ok) {
2556                 ANIM_animdata_update(&ac, &anim_data);
2557         }
2558         ANIM_animdata_freelist(&anim_data);
2559         
2560         /* successful or not? */
2561         if (ok) {
2562
2563                 /* set notifier that keyframes have changed */
2564                 WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
2565                 
2566                 return OPERATOR_FINISHED;
2567         }
2568         else {
2569                 BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
2570                 return OPERATOR_CANCELLED;
2571         }
2572 }
2573  
2574 void GRAPH_OT_fmodifier_paste(wmOperatorType *ot)
2575 {
2576         /* identifiers */
2577         ot->name = "Paste F-Modifiers";
2578         ot->idname = "GRAPH_OT_fmodifier_paste";
2579         ot->description = "Add copied F-Modifiers to the selected F-Curves";
2580         
2581         /* api callbacks */
2582         ot->exec = graph_fmodifier_paste_exec;
2583         ot->poll = graphop_active_fcurve_poll;
2584         
2585         /* flags */
2586         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2587 }
2588
2589 /* ************************************************************************** */