Blender  V2.93
graph_view.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2020 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 #include <math.h>
21 
22 #include "MEM_guardedalloc.h"
23 
24 #include "BLI_listbase.h"
25 #include "BLI_math.h"
26 #include "BLI_rect.h"
27 
28 #include "DNA_anim_types.h"
29 #include "DNA_scene_types.h"
30 #include "DNA_space_types.h"
31 
32 #include "RNA_access.h"
33 #include "RNA_define.h"
34 
35 #include "BKE_context.h"
36 #include "BKE_fcurve.h"
37 #include "BKE_nla.h"
38 
39 #include "UI_interface.h"
40 #include "UI_view2d.h"
41 
42 #include "ED_anim_api.h"
43 #include "ED_markers.h"
44 #include "ED_screen.h"
45 
46 #include "WM_api.h"
47 #include "WM_types.h"
48 
49 #include "graph_intern.h"
50 
51 /* *************************** Calculate Range ************************** */
52 
53 /* Get the min/max keyframes. */
54 /* Note: it should return total boundbox, filter for selection only can be argument... */
56  float *xmin,
57  float *xmax,
58  float *ymin,
59  float *ymax,
60  const bool do_sel_only,
61  const bool include_handles)
62 {
63  Scene *scene = ac->scene;
64  SpaceGraph *sipo = (SpaceGraph *)ac->sl;
65 
66  ListBase anim_data = {NULL, NULL};
67  bAnimListElem *ale;
68  int filter;
69 
70  /* Get data to filter, from Dopesheet. */
72  if (sipo->flag & SIPO_SELCUVERTSONLY) {
74  }
75 
76  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
77 
78  /* Set large values initial values that will be easy to override. */
79  if (xmin) {
80  *xmin = 999999999.0f;
81  }
82  if (xmax) {
83  *xmax = -999999999.0f;
84  }
85  if (ymin) {
86  *ymin = 999999999.0f;
87  }
88  if (ymax) {
89  *ymax = -999999999.0f;
90  }
91 
92  /* Check if any channels to set range with. */
93  if (anim_data.first) {
94  bool foundBounds = false;
95 
96  /* Go through channels, finding max extents. */
97  for (ale = anim_data.first; ale; ale = ale->next) {
98  AnimData *adt = ANIM_nla_mapping_get(ac, ale);
99  FCurve *fcu = (FCurve *)ale->key_data;
100  float txmin, txmax, tymin, tymax;
101  float unitFac, offset;
102 
103  /* Get range. */
105  fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) {
106  short mapping_flag = ANIM_get_normalization_flags(ac);
107 
108  /* Apply NLA scaling. */
109  if (adt) {
110  txmin = BKE_nla_tweakedit_remap(adt, txmin, NLATIME_CONVERT_MAP);
111  txmax = BKE_nla_tweakedit_remap(adt, txmax, NLATIME_CONVERT_MAP);
112  }
113 
114  /* Apply unit corrections. */
115  unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
116  tymin += offset;
117  tymax += offset;
118  tymin *= unitFac;
119  tymax *= unitFac;
120 
121  /* Try to set cur using these values, if they're more extreme than previously set values.
122  */
123  if ((xmin) && (txmin < *xmin)) {
124  *xmin = txmin;
125  }
126  if ((xmax) && (txmax > *xmax)) {
127  *xmax = txmax;
128  }
129  if ((ymin) && (tymin < *ymin)) {
130  *ymin = tymin;
131  }
132  if ((ymax) && (tymax > *ymax)) {
133  *ymax = tymax;
134  }
135 
136  foundBounds = true;
137  }
138  }
139 
140  /* Ensure that the extents are not too extreme that view implodes...*/
141  if (foundBounds) {
142  if ((xmin && xmax) && (fabsf(*xmax - *xmin) < 0.001f)) {
143  *xmin -= 0.0005f;
144  *xmax += 0.0005f;
145  }
146  if ((ymin && ymax) && (fabsf(*ymax - *ymin) < 0.001f)) {
147  *ymax -= 0.0005f;
148  *ymax += 0.0005f;
149  }
150  }
151  else {
152  if (xmin) {
153  *xmin = (float)PSFRA;
154  }
155  if (xmax) {
156  *xmax = (float)PEFRA;
157  }
158  if (ymin) {
159  *ymin = -5;
160  }
161  if (ymax) {
162  *ymax = 5;
163  }
164  }
165 
166  /* Free memory. */
167  ANIM_animdata_freelist(&anim_data);
168  }
169  else {
170  /* Set default range. */
171  if (ac->scene) {
172  if (xmin) {
173  *xmin = (float)PSFRA;
174  }
175  if (xmax) {
176  *xmax = (float)PEFRA;
177  }
178  }
179  else {
180  if (xmin) {
181  *xmin = -5;
182  }
183  if (xmax) {
184  *xmax = 100;
185  }
186  }
187 
188  if (ymin) {
189  *ymin = -5;
190  }
191  if (ymax) {
192  *ymax = 5;
193  }
194  }
195 }
196 
197 /* ****************** Automatic Preview-Range Operator ****************** */
198 
200 {
201  bAnimContext ac;
202  Scene *scene;
203  float min, max;
204 
205  /* Get editor data. */
206  if (ANIM_animdata_get_context(C, &ac) == 0) {
207  return OPERATOR_CANCELLED;
208  }
209  if (ac.scene == NULL) {
210  return OPERATOR_CANCELLED;
211  }
212 
213  scene = ac.scene;
214 
215  /* Set the range directly. */
216  get_graph_keyframe_extents(&ac, &min, &max, NULL, NULL, false, false);
220 
221  /* Set notifier that things have changed. */
222  // XXX Err... there's nothing for frame ranges yet, but this should do fine too.
224 
225  return OPERATOR_FINISHED;
226 }
227 
229 {
230  /* Identifiers */
231  ot->name = "Auto-Set Preview Range";
232  ot->idname = "GRAPH_OT_previewrange_set";
233  ot->description = "Automatically set Preview Range based on range of keyframes";
234 
235  /* API callbacks */
237  /* XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier. */
239 
240  /* Flags */
242 }
243 
244 /* ****************** View-All Operator ****************** */
245 
247  const bool do_sel_only,
248  const bool include_handles,
249  const int smooth_viewtx)
250 {
251  bAnimContext ac;
252  rctf cur_new;
253 
254  /* Get editor data. */
255  if (ANIM_animdata_get_context(C, &ac) == 0) {
256  return OPERATOR_CANCELLED;
257  }
258 
259  /* Set the horizontal range, with an extra offset so that the extreme keys will be in view. */
261  &cur_new.xmin,
262  &cur_new.xmax,
263  &cur_new.ymin,
264  &cur_new.ymax,
265  do_sel_only,
266  include_handles);
267 
268  /* Give some more space at the borders. */
269  BLI_rctf_scale(&cur_new, 1.1f);
270 
271  /* Take regions into account, that could block the view.
272  * Marker region is supposed to be larger than the scroll-bar, so prioritize it.*/
273  float pad_top = UI_TIME_SCRUB_MARGIN_Y;
276  BLI_rctf_pad_y(&cur_new, ac.region->winy, pad_bottom, pad_top);
277 
278  UI_view2d_smooth_view(C, ac.region, &cur_new, smooth_viewtx);
279  return OPERATOR_FINISHED;
280 }
281 
282 /* ......... */
283 
285 {
286  const bool include_handles = RNA_boolean_get(op->ptr, "include_handles");
287  const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
288 
289  /* Whole range */
290  return graphkeys_viewall(C, false, include_handles, smooth_viewtx);
291 }
292 
294 {
295  const bool include_handles = RNA_boolean_get(op->ptr, "include_handles");
296  const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
297 
298  /* Only selected. */
299  return graphkeys_viewall(C, true, include_handles, smooth_viewtx);
300 }
301 
302 /* ......... */
303 
305 {
306  /* Identifiers */
307  ot->name = "Frame All";
308  ot->idname = "GRAPH_OT_view_all";
309  ot->description = "Reset viewable area to show full keyframe range";
310 
311  /* API callbacks */
313  /* XXX: Unchecked poll to get fsamples working too, but makes modifier damage trickier... */
315 
316  /* Flags */
317  ot->flag = 0;
318 
319  /* Props */
321  "include_handles",
322  true,
323  "Include Handles",
324  "Include handles of keyframes when calculating extents");
325 }
326 
328 {
329  /* Identifiers */
330  ot->name = "Frame Selected";
331  ot->idname = "GRAPH_OT_view_selected";
332  ot->description = "Reset viewable area to show selected keyframe range";
333 
334  /* API callbacks */
336  /* XXX: Unchecked poll to get fsamples working too, but makes modifier damage trickier... */
338 
339  /* Flags */
340  ot->flag = 0;
341 
342  /* Props */
344  "include_handles",
345  true,
346  "Include Handles",
347  "Include handles of keyframes when calculating extents");
348 }
349 
350 /* ********************** View Frame Operator ****************************** */
351 
353 {
354  const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
355  ANIM_center_frame(C, smooth_viewtx);
356  return OPERATOR_FINISHED;
357 }
358 
360 {
361  /* Identifiers */
362  ot->name = "Go to Current Frame";
363  ot->idname = "GRAPH_OT_view_frame";
364  ot->description = "Move the view to the current frame";
365 
366  /* API callbacks */
369 
370  /* Flags */
371  ot->flag = 0;
372 }
373 
374 /* ******************** Create Ghost-Curves Operator *********************** */
375 /* This operator samples the data of the selected F-Curves to F-Points, storing them
376  * as 'ghost curves' in the active Graph Editor.
377  */
378 
379 /* Bake each F-Curve into a set of samples, and store as a ghost curve. */
380 static void create_ghost_curves(bAnimContext *ac, int start, int end)
381 {
382  SpaceGraph *sipo = (SpaceGraph *)ac->sl;
383  ListBase anim_data = {NULL, NULL};
384  bAnimListElem *ale;
385  int filter;
386 
387  /* Free existing ghost curves. */
388  BKE_fcurves_free(&sipo->runtime.ghost_curves);
389 
390  /* Sanity check. */
391  if (start >= end) {
392  printf("Error: Frame range for Ghost F-Curve creation is inappropriate\n");
393  return;
394  }
395 
396  /* Filter data. */
399  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
400 
401  /* Loop through filtered data and add keys between selected keyframes on every frame . */
402  for (ale = anim_data.first; ale; ale = ale->next) {
403  FCurve *fcu = (FCurve *)ale->key_data;
404  FCurve *gcu = BKE_fcurve_create();
405  AnimData *adt = ANIM_nla_mapping_get(ac, ale);
406  ChannelDriver *driver = fcu->driver;
407  FPoint *fpt;
408  float unitFac, offset;
409  int cfra;
410  short mapping_flag = ANIM_get_normalization_flags(ac);
411 
412  /* Disable driver so that it don't muck up the sampling process. */
413  fcu->driver = NULL;
414 
415  /* Calculate unit-mapping factor. */
416  unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
417 
418  /* Create samples, but store them in a new curve
419  * - we cannot use fcurve_store_samples() as that will only overwrite the original curve.
420  */
421  gcu->fpt = fpt = MEM_callocN(sizeof(FPoint) * (end - start + 1), "Ghost FPoint Samples");
422  gcu->totvert = end - start + 1;
423 
424  /* Use the sampling callback at 1-frame intervals from start to end frames. */
425  for (cfra = start; cfra <= end; cfra++, fpt++) {
426  float cfrae = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
427 
428  fpt->vec[0] = cfrae;
429  fpt->vec[1] = (fcurve_samplingcb_evalcurve(fcu, NULL, cfrae) + offset) * unitFac;
430  }
431 
432  /* Set color of ghost curve
433  * - make the color slightly darker.
434  */
435  gcu->color[0] = fcu->color[0] - 0.07f;
436  gcu->color[1] = fcu->color[1] - 0.07f;
437  gcu->color[2] = fcu->color[2] - 0.07f;
438 
439  /* Store new ghost curve. */
440  BLI_addtail(&sipo->runtime.ghost_curves, gcu);
441 
442  /* Restore driver. */
443  fcu->driver = driver;
444  }
445 
446  /* Admin and redraws. */
447  ANIM_animdata_freelist(&anim_data);
448 }
449 
450 /* ------------------- */
451 
453 {
454  bAnimContext ac;
455  View2D *v2d;
456  int start, end;
457 
458  /* Get editor data. */
459  if (ANIM_animdata_get_context(C, &ac) == 0) {
460  return OPERATOR_CANCELLED;
461  }
462 
463  /* Ghost curves are snapshots of the visible portions of the curves,
464  * so set range to be the visible range. */
465  v2d = &ac.region->v2d;
466  start = (int)v2d->cur.xmin;
467  end = (int)v2d->cur.xmax;
468 
469  /* Bake selected curves into a ghost curve. */
470  create_ghost_curves(&ac, start, end);
471 
472  /* Update this editor only. */
474 
475  return OPERATOR_FINISHED;
476 }
477 
479 {
480  /* Identifiers */
481  ot->name = "Create Ghost Curves";
482  ot->idname = "GRAPH_OT_ghost_curves_create";
483  ot->description =
484  "Create snapshot (Ghosts) of selected F-Curves as background aid for active Graph Editor";
485 
486  /* API callbacks */
489 
490  /* Flags */
492 
493  /* TODO: add props for start/end frames */
494 }
495 
496 /* ******************** Clear Ghost-Curves Operator *********************** */
497 /* This operator clears the 'ghost curves' for the active Graph Editor */
498 
500 {
501  bAnimContext ac;
502  SpaceGraph *sipo;
503 
504  /* Get editor data. */
505  if (ANIM_animdata_get_context(C, &ac) == 0) {
506  return OPERATOR_CANCELLED;
507  }
508  sipo = (SpaceGraph *)ac.sl;
509 
510  /* If no ghost curves, don't do anything. */
512  return OPERATOR_CANCELLED;
513  }
514  /* Free ghost curves. */
516 
517  /* Update this editor only. */
519 
520  return OPERATOR_FINISHED;
521 }
522 
524 {
525  /* Identifiers */
526  ot->name = "Clear Ghost Curves";
527  ot->idname = "GRAPH_OT_ghost_curves_clear";
528  ot->description = "Clear F-Curve snapshots (Ghosts) for active Graph Editor";
529 
530  /* API callbacks */
533 
534  /* Flags */
536 }
typedef float(TangentPoint)[2]
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
bool BKE_fcurve_calc_bounds(struct FCurve *fcu, float *xmin, float *xmax, float *ymin, float *ymax, const bool do_sel_only, const bool include_handles)
Definition: fcurve.c:664
void BKE_fcurves_free(ListBase *list)
Definition: fcurve.c:103
struct FCurve * BKE_fcurve_create(void)
Definition: fcurve.c:68
float fcurve_samplingcb_evalcurve(struct FCurve *fcu, void *data, float evaltime)
@ NLATIME_CONVERT_MAP
Definition: BKE_nla.h:156
@ NLATIME_CONVERT_UNMAP
Definition: BKE_nla.h:153
float BKE_nla_tweakedit_remap(struct AnimData *adt, float cframe, short mode)
Definition: nla.c:582
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
MINLINE int round_fl_to_int(float a)
void BLI_rctf_pad_y(struct rctf *rect, const float boundary_size, const float pad_min, const float pad_max)
Definition: rct.c:706
void BLI_rctf_scale(rctf *rect, const float scale)
Definition: rct.c:694
#define UNUSED(x)
#define PSFRA
#define SCER_PRV_RANGE
#define PEFRA
@ SIPO_SELCUVERTSONLY
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ ANIMFILTER_DATA_VISIBLE
Definition: ED_anim_api.h:295
@ ANIMFILTER_CURVE_VISIBLE
Definition: ED_anim_api.h:300
@ ANIMFILTER_NODUPLIS
Definition: ED_anim_api.h:328
@ ANIMFILTER_SEL
Definition: ED_anim_api.h:311
void ED_area_tag_redraw(ScrArea *area)
Definition: area.c:745
bool ED_operator_graphedit_active(struct bContext *C)
Definition: screen_ops.c:314
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
void UI_view2d_smooth_view(struct bContext *C, struct ARegion *region, const struct rctf *cur, const int smooth_viewtx)
#define UI_MARKER_MARGIN_Y
Definition: UI_view2d.h:282
#define V2D_SCROLL_HANDLE_HEIGHT
Definition: UI_view2d.h:70
#define UI_TIME_SCRUB_MARGIN_Y
Definition: UI_view2d.h:283
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define NC_SCENE
Definition: WM_types.h:279
#define ND_FRAME
Definition: WM_types.h:334
void ANIM_animdata_freelist(ListBase *anim_data)
Definition: anim_deps.c:425
AnimData * ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
Definition: anim_draw.c:178
void ANIM_center_frame(struct bContext *C, int smooth_viewtx)
Definition: anim_draw.c:588
float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
Definition: anim_draw.c:453
short ANIM_get_normalization_flags(bAnimContext *ac)
Definition: anim_draw.c:285
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
Definition: anim_filter.c:405
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_Flags filter_mode, void *data, eAnimCont_Types datatype)
Definition: anim_filter.c:3442
ListBase * ED_context_get_markers(const bContext *C)
Definition: anim_markers.c:103
Scene scene
bool graphop_visible_keyframes_poll(struct bContext *C)
Definition: graph_utils.c:131
static int graphkeys_view_selected_exec(bContext *C, wmOperator *op)
Definition: graph_view.c:293
static int graphkeys_view_frame_exec(bContext *C, wmOperator *op)
Definition: graph_view.c:352
static int graphkeys_create_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op))
Definition: graph_view.c:452
void GRAPH_OT_ghost_curves_create(wmOperatorType *ot)
Definition: graph_view.c:478
void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, float *ymin, float *ymax, const bool do_sel_only, const bool include_handles)
Definition: graph_view.c:55
void GRAPH_OT_view_all(wmOperatorType *ot)
Definition: graph_view.c:304
static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
Definition: graph_view.c:199
void GRAPH_OT_view_frame(wmOperatorType *ot)
Definition: graph_view.c:359
void GRAPH_OT_view_selected(wmOperatorType *ot)
Definition: graph_view.c:327
void GRAPH_OT_previewrange_set(wmOperatorType *ot)
Definition: graph_view.c:228
void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot)
Definition: graph_view.c:523
static int graphkeys_viewall_exec(bContext *C, wmOperator *op)
Definition: graph_view.c:284
static void create_ghost_curves(bAnimContext *ac, int start, int end)
Definition: graph_view.c:380
static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op))
Definition: graph_view.c:499
static int graphkeys_viewall(bContext *C, const bool do_sel_only, const bool include_handles, const int smooth_viewtx)
Definition: graph_view.c:246
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
#define fabsf(x)
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
#define min(a, b)
Definition: sort.c:51
ChannelDriver * driver
float color[3]
float vec[2]
struct RenderData r
SpaceGraph_Runtime runtime
struct ARegion * region
Definition: ED_anim_api.h:89
struct Scene * scene
Definition: ED_anim_api.h:97
struct SpaceLink * sl
Definition: ED_anim_api.h:87
struct bAnimListElem * next
Definition: ED_anim_api.h:135
void * key_data
Definition: ED_anim_api.h:154
struct ID * id
Definition: ED_anim_api.h:168
float xmax
Definition: DNA_vec_types.h:85
float xmin
Definition: DNA_vec_types.h:85
float ymax
Definition: DNA_vec_types.h:86
float ymin
Definition: DNA_vec_types.h:86
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
PropertyRNA * prop
Definition: WM_types.h:814
struct PointerRNA * ptr
float max
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3156
int WM_operator_smooth_viewtx_get(const wmOperator *op)
Definition: wm_operators.c:944