Blender V4.5
graph_view.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cmath>
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_listbase.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.hh"
21#include "RNA_define.hh"
22
23#include "BKE_context.hh"
24#include "BKE_fcurve.hh"
25#include "BKE_nla.hh"
26
27#include "UI_view2d.hh"
28
29#include "ED_anim_api.hh"
30#include "ED_markers.hh"
31#include "ED_screen.hh"
32
33#include "WM_api.hh"
34#include "WM_types.hh"
35
36#include "graph_intern.hh"
37
38/* -------------------------------------------------------------------- */
41
43 float *xmin,
44 float *xmax,
45 float *ymin,
46 float *ymax,
47 const bool do_sel_only,
48 const bool include_handles)
49{
50 Scene *scene = ac->scene;
51
52 ListBase anim_data = {nullptr, nullptr};
53 int filter;
54
55 /* Get data to filter, from Dope-sheet. */
58 if (U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) {
60 }
61
63 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
64
65 /* Set large values initial values that will be easy to override. */
66 if (xmin) {
67 *xmin = 999999999.0f;
68 }
69 if (xmax) {
70 *xmax = -999999999.0f;
71 }
72 if (ymin) {
73 *ymin = 999999999.0f;
74 }
75 if (ymax) {
76 *ymax = -999999999.0f;
77 }
78
79 /* Check if any channels to set range with. */
80 if (anim_data.first) {
81 bool foundBounds = false;
82
83 /* Go through channels, finding max extents. */
84 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
85 FCurve *fcu = (FCurve *)ale->key_data;
87 float unitFac, offset;
88
89 /* Get range. */
90 if (BKE_fcurve_calc_bounds(fcu, do_sel_only, include_handles, nullptr, &bounds)) {
91 short mapping_flag = ANIM_get_normalization_flags(ac->sl);
92
93 /* Apply NLA scaling. */
96
97 /* Apply unit corrections. */
98 unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
99 bounds.ymin += offset;
100 bounds.ymax += offset;
101 bounds.ymin *= unitFac;
102 bounds.ymax *= unitFac;
103
104 /* Try to set cur using these values, if they're more extreme than previously set values.
105 */
106 if ((xmin) && (bounds.xmin < *xmin)) {
107 *xmin = bounds.xmin;
108 }
109 if ((xmax) && (bounds.xmax > *xmax)) {
110 *xmax = bounds.xmax;
111 }
112 if ((ymin) && (bounds.ymin < *ymin)) {
113 *ymin = bounds.ymin;
114 }
115 if ((ymax) && (bounds.ymax > *ymax)) {
116 *ymax = bounds.ymax;
117 }
118
119 foundBounds = true;
120 }
121 }
122
123 /* Ensure that the extents are not too extreme that view implodes. */
124 if (foundBounds) {
125 if ((xmin && xmax) && (fabsf(*xmax - *xmin) < 0.001f)) {
126 *xmin -= 0.0005f;
127 *xmax += 0.0005f;
128 }
129 if ((ymin && ymax) && (fabsf(*ymax - *ymin) < 0.001f)) {
130 *ymin -= 0.05f;
131 *ymax += 0.05f;
132 }
133 }
134 else {
135 if (xmin) {
136 *xmin = float(PSFRA);
137 }
138 if (xmax) {
139 *xmax = float(PEFRA);
140 }
141 if (ymin) {
142 *ymin = -5;
143 }
144 if (ymax) {
145 *ymax = 5;
146 }
147 }
148
149 /* Free memory. */
150 ANIM_animdata_freelist(&anim_data);
151 }
152 else {
153 /* Set default range. */
154 if (ac->scene) {
155 if (xmin) {
156 *xmin = float(PSFRA);
157 }
158 if (xmax) {
159 *xmax = float(PEFRA);
160 }
161 }
162 else {
163 if (xmin) {
164 *xmin = -5;
165 }
166 if (xmax) {
167 *xmax = 100;
168 }
169 }
170
171 if (ymin) {
172 *ymin = -5;
173 }
174 if (ymax) {
175 *ymax = 5;
176 }
177 }
178}
179
181
182/* -------------------------------------------------------------------- */
185
187{
188 bAnimContext ac;
189 Scene *scene;
190 float min, max;
191
192 /* Get editor data. */
193 if (ANIM_animdata_get_context(C, &ac) == 0) {
194 return OPERATOR_CANCELLED;
195 }
196 if (ac.scene == nullptr) {
197 return OPERATOR_CANCELLED;
198 }
199
200 scene = ac.scene;
201
202 /* Set the range directly. */
203 get_graph_keyframe_extents(&ac, &min, &max, nullptr, nullptr, true, false);
204 scene->r.flag |= SCER_PRV_RANGE;
205 scene->r.psfra = round_fl_to_int(min);
206 scene->r.pefra = round_fl_to_int(max);
207
208 /* Set notifier that things have changed. */
209 /* XXX: Err... there's nothing for frame ranges yet, but this should do fine too. */
211
212 return OPERATOR_FINISHED;
213}
214
216{
217 /* Identifiers */
218 ot->name = "Set Preview Range to Selected";
219 ot->idname = "GRAPH_OT_previewrange_set";
220 ot->description = "Set Preview Range based on range of selected keyframes";
221
222 /* API callbacks */
224 /* XXX: unchecked poll to get F-samples working too, but makes modifier damage trickier. */
226
227 /* Flags */
229}
230
232
233/* -------------------------------------------------------------------- */
236
238 const bool do_sel_only,
239 const bool include_handles,
240 const int smooth_viewtx)
241{
242 bAnimContext ac;
243 rctf cur_new;
244
245 /* Get editor data. */
246 if (ANIM_animdata_get_context(C, &ac) == 0) {
247 return OPERATOR_CANCELLED;
248 }
249
250 /* Set the horizontal range, with an extra offset so that the extreme keys will be in view. */
252 &cur_new.xmin,
253 &cur_new.xmax,
254 &cur_new.ymin,
255 &cur_new.ymax,
256 do_sel_only,
257 include_handles);
258
259 /* Give some more space at the borders. */
260 cur_new = ANIM_frame_range_view2d_add_xmargin(ac.region->v2d, cur_new);
261 BLI_rctf_resize_y(&cur_new, 1.1f * BLI_rctf_size_y(&cur_new));
262
263 /* Take regions into account, that could block the view.
264 * Marker region is supposed to be larger than the scroll-bar, so prioritize it. */
265 float pad_top = UI_TIME_SCRUB_MARGIN_Y;
268 BLI_rctf_pad_y(&cur_new, ac.region->winy, pad_bottom, pad_top);
269
270 UI_view2d_smooth_view(C, ac.region, &cur_new, smooth_viewtx);
271 return OPERATOR_FINISHED;
272}
273
274/* ......... */
275
277{
278 const bool include_handles = RNA_boolean_get(op->ptr, "include_handles");
279 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
280
281 /* Whole range */
282 return graphkeys_viewall(C, false, include_handles, smooth_viewtx);
283}
284
286{
287 const bool include_handles = RNA_boolean_get(op->ptr, "include_handles");
288 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
289
290 /* Only selected. */
291 return graphkeys_viewall(C, true, include_handles, smooth_viewtx);
292}
293
294/* ......... */
295
297{
298 /* Identifiers */
299 ot->name = "Frame All";
300 ot->idname = "GRAPH_OT_view_all";
301 ot->description = "Reset viewable area to show full keyframe range";
302
303 /* API callbacks */
305 /* XXX: Unchecked poll to get F-samples working too, but makes modifier damage trickier. */
307
308 /* Flags */
309 ot->flag = 0;
310
311 /* Props */
312 ot->prop = RNA_def_boolean(ot->srna,
313 "include_handles",
314 true,
315 "Include Handles",
316 "Include handles of keyframes when calculating extents");
317}
318
320{
321 /* Identifiers */
322 ot->name = "Frame Selected";
323 ot->idname = "GRAPH_OT_view_selected";
324 ot->description = "Reset viewable area to show selected keyframe range";
325
326 /* API callbacks */
328 /* XXX: Unchecked poll to get F-samples working too, but makes modifier damage trickier. */
330
331 /* Flags */
332 ot->flag = 0;
333
334 /* Props */
335 ot->prop = RNA_def_boolean(ot->srna,
336 "include_handles",
337 true,
338 "Include Handles",
339 "Include handles of keyframes when calculating extents");
340}
341
343
344/* -------------------------------------------------------------------- */
347
349{
350 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
351 ANIM_center_frame(C, smooth_viewtx);
352 return OPERATOR_FINISHED;
353}
354
356{
357 /* Identifiers */
358 ot->name = "Go to Current Frame";
359 ot->idname = "GRAPH_OT_view_frame";
360 ot->description = "Move the view to the current frame";
361
362 /* API callbacks */
365
366 /* Flags */
367 ot->flag = 0;
368}
369
371
372/* -------------------------------------------------------------------- */
378
379/* Bake each F-Curve into a set of samples, and store as a ghost curve. */
380static void create_ghost_curves(bAnimContext *ac, int start, int end)
381{
382 SpaceGraph *sipo = (SpaceGraph *)ac->sl;
383 ListBase anim_data = {nullptr, nullptr};
384 int filter;
385
386 /* Free existing ghost curves. */
388
389 /* Sanity check. */
390 if (start >= end) {
391 printf("Error: Frame range for Ghost F-Curve creation is inappropriate\n");
392 return;
393 }
394
395 /* Filter data. */
399 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
400
401 /* Loop through filtered data and add keys between selected keyframes on every frame. */
402 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
403 FCurve *fcu = (FCurve *)ale->key_data;
404 FCurve *gcu = BKE_fcurve_create();
405 ChannelDriver *driver = fcu->driver;
406 FPoint *fpt;
407 float unitFac, offset;
408 int cfra;
409 short mapping_flag = ANIM_get_normalization_flags(ac->sl);
410
411 /* Disable driver so that it don't muck up the sampling process. */
412 fcu->driver = nullptr;
413
414 /* Calculate unit-mapping factor. */
415 unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
416
417 /* Create samples, but store them in a new curve
418 * - we cannot use fcurve_store_samples() as that will only overwrite the original curve.
419 */
420 gcu->fpt = fpt = MEM_calloc_arrayN<FPoint>((end - start + 1), "Ghost FPoint Samples");
421 gcu->totvert = end - start + 1;
422
423 /* Use the sampling callback at 1-frame intervals from start to end frames. */
424 for (cfra = start; cfra <= end; cfra++, fpt++) {
425 const float cfrae = ANIM_nla_tweakedit_remap(ale, cfra, NLATIME_CONVERT_UNMAP);
426
427 fpt->vec[0] = cfrae;
428 fpt->vec[1] = (fcurve_samplingcb_evalcurve(fcu, nullptr, cfrae) + offset) * unitFac;
429 }
430
431 /* Set color of ghost curve
432 * - make the color slightly darker.
433 */
434 gcu->color[0] = fcu->color[0] - 0.07f;
435 gcu->color[1] = fcu->color[1] - 0.07f;
436 gcu->color[2] = fcu->color[2] - 0.07f;
437
438 /* Store new ghost curve. */
439 BLI_addtail(&sipo->runtime.ghost_curves, gcu);
440
441 /* Restore driver. */
442 fcu->driver = driver;
443 }
444
445 /* Admin and redraws. */
446 ANIM_animdata_freelist(&anim_data);
447}
448
449/* ------------------- */
450
452{
453 bAnimContext ac;
454 View2D *v2d;
455 int start, end;
456
457 /* Get editor data. */
458 if (ANIM_animdata_get_context(C, &ac) == 0) {
459 return OPERATOR_CANCELLED;
460 }
461
462 /* Ghost curves are snapshots of the visible portions of the curves,
463 * so set range to be the visible range. */
464 v2d = &ac.region->v2d;
465 start = int(v2d->cur.xmin);
466 end = int(v2d->cur.xmax);
467
468 /* Bake selected curves into a ghost curve. */
469 create_ghost_curves(&ac, start, end);
470
471 /* Update this editor only. */
473
474 return OPERATOR_FINISHED;
475}
476
478{
479 /* Identifiers */
480 ot->name = "Create Ghost Curves";
481 ot->idname = "GRAPH_OT_ghost_curves_create";
482 ot->description =
483 "Create snapshot (Ghosts) of selected F-Curves as background aid for active Graph Editor";
484
485 /* API callbacks */
488
489 /* Flags */
491
492 /* TODO: add props for start/end frames */
493}
494
496
497/* -------------------------------------------------------------------- */
502
504{
505 bAnimContext ac;
506 SpaceGraph *sipo;
507
508 /* Get editor data. */
509 if (ANIM_animdata_get_context(C, &ac) == 0) {
510 return OPERATOR_CANCELLED;
511 }
512 sipo = (SpaceGraph *)ac.sl;
513
514 /* If no ghost curves, don't do anything. */
516 return OPERATOR_CANCELLED;
517 }
518 /* Free ghost curves. */
520
521 /* Update this editor only. */
523
524 return OPERATOR_FINISHED;
525}
526
528{
529 /* Identifiers */
530 ot->name = "Clear Ghost Curves";
531 ot->idname = "GRAPH_OT_ghost_curves_clear";
532 ot->description = "Clear F-Curve snapshots (Ghosts) for active Graph Editor";
533
534 /* API callbacks */
537
538 /* Flags */
540}
541
ScrArea * CTX_wm_area(const bContext *C)
FCurve * BKE_fcurve_create()
void BKE_fcurves_free(ListBase *list)
float fcurve_samplingcb_evalcurve(FCurve *fcu, void *data, float evaltime)
bool BKE_fcurve_calc_bounds(const FCurve *fcu, bool selected_keys_only, bool include_handles, const float frame_range[2], rctf *r_bounds)
@ NLATIME_CONVERT_MAP
Definition BKE_nla.hh:543
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:540
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
MINLINE int round_fl_to_int(float a)
void BLI_rctf_resize_y(struct rctf *rect, float y)
Definition rct.cc:651
void BLI_rctf_pad_y(struct rctf *rect, float boundary_size, float pad_min, float pad_max)
Definition rct.cc:689
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
#define PSFRA
@ SCER_PRV_RANGE
#define PEFRA
@ USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
eAnimCont_Types
eAnimFilter_Flags
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_CURVE_VISIBLE
@ ANIMFILTER_NODUPLIS
@ ANIMFILTER_FCURVESONLY
@ ANIMFILTER_SEL
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:714
bool ED_operator_graphedit_active(bContext *C)
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
void UI_view2d_smooth_view(const bContext *C, ARegion *region, const rctf *cur, int smooth_viewtx)
#define UI_MARKER_MARGIN_Y
Definition UI_view2d.hh:470
#define V2D_SCROLL_HANDLE_HEIGHT
Definition UI_view2d.hh:67
#define UI_TIME_SCRUB_MARGIN_Y
Definition UI_view2d.hh:471
#define NC_SCENE
Definition WM_types.hh:375
#define ND_FRAME
Definition WM_types.hh:431
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:463
short ANIM_get_normalization_flags(SpaceLink *space_link)
Definition anim_draw.cc:353
void ANIM_center_frame(bContext *C, int smooth_viewtx)
Definition anim_draw.cc:696
rctf ANIM_frame_range_view2d_add_xmargin(const View2D &view_2d, const rctf view_rect)
Definition anim_draw.cc:739
float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
Definition anim_draw.cc:562
float ANIM_nla_tweakedit_remap(bAnimListElem *ale, const float cframe, const eNlaTime_ConvertModes mode)
Definition anim_draw.cc:262
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode, void *data, const eAnimCont_Types datatype)
ListBase * ED_context_get_markers(const bContext *C)
#define U
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
#define fabsf(x)
#define filter
#define printf(...)
bool graphop_visible_keyframes_poll(bContext *C)
static wmOperatorStatus graphkeys_viewall(bContext *C, const bool do_sel_only, const bool include_handles, const int smooth_viewtx)
static wmOperatorStatus graphkeys_view_frame_exec(bContext *C, wmOperator *op)
static wmOperatorStatus graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *)
static wmOperatorStatus graphkeys_create_ghostcurves_exec(bContext *C, wmOperator *)
void GRAPH_OT_ghost_curves_create(wmOperatorType *ot)
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.cc:42
void GRAPH_OT_view_all(wmOperatorType *ot)
void GRAPH_OT_view_frame(wmOperatorType *ot)
void GRAPH_OT_view_selected(wmOperatorType *ot)
void GRAPH_OT_previewrange_set(wmOperatorType *ot)
void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot)
static wmOperatorStatus graphkeys_viewall_exec(bContext *C, wmOperator *op)
static void create_ghost_curves(bAnimContext *ac, int start, int end)
static wmOperatorStatus graphkeys_previewrange_exec(bContext *C, wmOperator *)
static wmOperatorStatus graphkeys_view_selected_exec(bContext *C, wmOperator *op)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
#define min(a, b)
Definition sort.cc:36
FPoint * fpt
ChannelDriver * driver
float color[3]
unsigned int totvert
float vec[2]
void * first
struct RenderData r
SpaceGraph_Runtime runtime
SpaceLink * sl
eAnimCont_Types datatype
ARegion * region
float xmax
float xmin
float ymax
float ymin
struct PointerRNA * ptr
max
Definition text_draw.cc:251
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4226
int WM_operator_smooth_viewtx_get(const wmOperator *op)