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