Blender V5.0
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_math_base.h"
15#include "BLI_rect.h"
16
17#include "DNA_anim_types.h"
18#include "DNA_scene_types.h"
19#include "DNA_space_types.h"
20
21#include "RNA_access.hh"
22#include "RNA_define.hh"
23
24#include "BKE_context.hh"
25#include "BKE_fcurve.hh"
26#include "BKE_nla.hh"
27
28#include "UI_view2d.hh"
29
30#include "ED_anim_api.hh"
31#include "ED_markers.hh"
32#include "ED_screen.hh"
33
34#include "WM_api.hh"
35#include "WM_types.hh"
36
37#include "graph_intern.hh"
38
39/* -------------------------------------------------------------------- */
42
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
53 ListBase anim_data = {nullptr, nullptr};
54 int filter;
55
56 /* Get data to filter, from Dope-sheet. */
59 if (U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) {
61 }
62
64 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
65
66 /* Set large values initial values that will be easy to override. */
67 if (xmin) {
68 *xmin = 999999999.0f;
69 }
70 if (xmax) {
71 *xmax = -999999999.0f;
72 }
73 if (ymin) {
74 *ymin = 999999999.0f;
75 }
76 if (ymax) {
77 *ymax = -999999999.0f;
78 }
79
80 /* Check if any channels to set range with. */
81 if (anim_data.first) {
82 bool foundBounds = false;
83
84 /* Go through channels, finding max extents. */
85 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
86 FCurve *fcu = (FCurve *)ale->key_data;
88 float unitFac, offset;
89
90 /* Get range. */
91 if (BKE_fcurve_calc_bounds(fcu, do_sel_only, include_handles, nullptr, &bounds)) {
92 short mapping_flag = ANIM_get_normalization_flags(ac->sl);
93
94 /* Apply NLA scaling. */
97
98 /* Apply unit corrections. */
99 unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset);
100 bounds.ymin += offset;
101 bounds.ymax += offset;
102 bounds.ymin *= unitFac;
103 bounds.ymax *= unitFac;
104
105 /* Try to set cur using these values, if they're more extreme than previously set values.
106 */
107 if ((xmin) && (bounds.xmin < *xmin)) {
108 *xmin = bounds.xmin;
109 }
110 if ((xmax) && (bounds.xmax > *xmax)) {
111 *xmax = bounds.xmax;
112 }
113 if ((ymin) && (bounds.ymin < *ymin)) {
114 *ymin = bounds.ymin;
115 }
116 if ((ymax) && (bounds.ymax > *ymax)) {
117 *ymax = bounds.ymax;
118 }
119
120 foundBounds = true;
121 }
122 }
123
124 /* Ensure that the extents are not too extreme that view implodes. */
125 if (foundBounds) {
126 if ((xmin && xmax) && (fabsf(*xmax - *xmin) < 0.001f)) {
127 *xmin -= 0.0005f;
128 *xmax += 0.0005f;
129 }
130 if ((ymin && ymax) && (fabsf(*ymax - *ymin) < 0.001f)) {
131 *ymin -= 0.05f;
132 *ymax += 0.05f;
133 }
134 }
135 else {
136 if (xmin) {
137 *xmin = float(PSFRA);
138 }
139 if (xmax) {
140 *xmax = float(PEFRA);
141 }
142 if (ymin) {
143 *ymin = -5;
144 }
145 if (ymax) {
146 *ymax = 5;
147 }
148 }
149
150 /* Free memory. */
151 ANIM_animdata_freelist(&anim_data);
152 }
153 else {
154 /* Set default range. */
155 if (ac->scene) {
156 if (xmin) {
157 *xmin = float(PSFRA);
158 }
159 if (xmax) {
160 *xmax = float(PEFRA);
161 }
162 }
163 else {
164 if (xmin) {
165 *xmin = -5;
166 }
167 if (xmax) {
168 *xmax = 100;
169 }
170 }
171
172 if (ymin) {
173 *ymin = -5;
174 }
175 if (ymax) {
176 *ymax = 5;
177 }
178 }
179}
180
182
183/* -------------------------------------------------------------------- */
186
188{
189 bAnimContext ac;
190 Scene *scene;
191 float min, max;
192
193 /* Get editor data. */
194 if (ANIM_animdata_get_context(C, &ac) == 0) {
195 return OPERATOR_CANCELLED;
196 }
197 if (ac.scene == nullptr) {
198 return OPERATOR_CANCELLED;
199 }
200
201 scene = ac.scene;
202
203 /* Set the range directly. */
204 get_graph_keyframe_extents(&ac, &min, &max, nullptr, nullptr, true, false);
205 scene->r.flag |= SCER_PRV_RANGE;
206 scene->r.psfra = round_fl_to_int(min);
207 scene->r.pefra = round_fl_to_int(max);
208
209 /* Set notifier that things have changed. */
210 /* XXX: Err... there's nothing for frame ranges yet, but this should do fine too. */
212
213 return OPERATOR_FINISHED;
214}
215
217{
218 /* Identifiers */
219 ot->name = "Set Preview Range to Selected";
220 ot->idname = "GRAPH_OT_previewrange_set";
221 ot->description = "Set Preview Range based on range of selected keyframes";
222
223 /* API callbacks */
225 /* XXX: unchecked poll to get F-samples working too, but makes modifier damage trickier. */
227
228 /* Flags */
230}
231
233
234/* -------------------------------------------------------------------- */
237
239 const bool do_sel_only,
240 const bool include_handles,
241 const int smooth_viewtx)
242{
243 bAnimContext ac;
244 rctf cur_new;
245
246 /* Get editor data. */
247 if (ANIM_animdata_get_context(C, &ac) == 0) {
248 return OPERATOR_CANCELLED;
249 }
250
251 /* Set the horizontal range, with an extra offset so that the extreme keys will be in view. */
253 &cur_new.xmin,
254 &cur_new.xmax,
255 &cur_new.ymin,
256 &cur_new.ymax,
257 do_sel_only,
258 include_handles);
259
260 /* Give some more space at the borders. */
261 cur_new = ANIM_frame_range_view2d_add_xmargin(ac.region->v2d, cur_new);
262 BLI_rctf_resize_y(&cur_new, 1.1f * BLI_rctf_size_y(&cur_new));
263
264 /* Take regions into account, that could block the view.
265 * Marker region is supposed to be larger than the scroll-bar, so prioritize it. */
266 float pad_top = UI_TIME_SCRUB_MARGIN_Y;
269 BLI_rctf_pad_y(&cur_new, ac.region->winy, pad_bottom, pad_top);
270
271 UI_view2d_smooth_view(C, ac.region, &cur_new, smooth_viewtx);
272 return OPERATOR_FINISHED;
273}
274
275/* ......... */
276
278{
279 const bool include_handles = RNA_boolean_get(op->ptr, "include_handles");
280 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
281
282 /* Whole range */
283 return graphkeys_viewall(C, false, include_handles, smooth_viewtx);
284}
285
287{
288 const bool include_handles = RNA_boolean_get(op->ptr, "include_handles");
289 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
290
291 /* Only selected. */
292 return graphkeys_viewall(C, true, include_handles, smooth_viewtx);
293}
294
295/* ......... */
296
298{
299 /* Identifiers */
300 ot->name = "Frame All";
301 ot->idname = "GRAPH_OT_view_all";
302 ot->description = "Reset viewable area to show full keyframe range";
303
304 /* API callbacks */
306 /* XXX: Unchecked poll to get F-samples working too, but makes modifier damage trickier. */
308
309 /* Flags */
310 ot->flag = 0;
311
312 /* Props */
313 ot->prop = RNA_def_boolean(ot->srna,
314 "include_handles",
315 true,
316 "Include Handles",
317 "Include handles of keyframes when calculating extents");
318}
319
321{
322 /* Identifiers */
323 ot->name = "Frame Selected";
324 ot->idname = "GRAPH_OT_view_selected";
325 ot->description = "Reset viewable area to show selected keyframe range";
326
327 /* API callbacks */
329 /* XXX: Unchecked poll to get F-samples working too, but makes modifier damage trickier. */
331
332 /* Flags */
333 ot->flag = 0;
334
335 /* Props */
336 ot->prop = RNA_def_boolean(ot->srna,
337 "include_handles",
338 true,
339 "Include Handles",
340 "Include handles of keyframes when calculating extents");
341}
342
344
345/* -------------------------------------------------------------------- */
348
350{
351 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
352 ANIM_center_frame(C, smooth_viewtx);
353 return OPERATOR_FINISHED;
354}
355
357{
358 /* Identifiers */
359 ot->name = "Go to Current Frame";
360 ot->idname = "GRAPH_OT_view_frame";
361 ot->description = "Move the view to the current frame";
362
363 /* API callbacks */
366
367 /* Flags */
368 ot->flag = 0;
369}
370
372
373/* -------------------------------------------------------------------- */
379
380/* Bake each F-Curve into a set of samples, and store as a ghost curve. */
381static void create_ghost_curves(bAnimContext *ac, int start, int end)
382{
383 SpaceGraph *sipo = (SpaceGraph *)ac->sl;
384 ListBase anim_data = {nullptr, nullptr};
385 int filter;
386
387 /* Free existing 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. */
400 ac, &anim_data, eAnimFilter_Flags(filter), ac->data, eAnimCont_Types(ac->datatype));
401
402 /* Loop through filtered data and add keys between selected keyframes on every frame. */
403 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
404 FCurve *fcu = (FCurve *)ale->key_data;
405 FCurve *gcu = BKE_fcurve_create();
406 ChannelDriver *driver = fcu->driver;
407 FPoint *fpt;
408 float unitFac, offset;
409 int cfra;
410 short mapping_flag = ANIM_get_normalization_flags(ac->sl);
411
412 /* Disable driver so that it don't muck up the sampling process. */
413 fcu->driver = nullptr;
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_calloc_arrayN<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 const float cfrae = ANIM_nla_tweakedit_remap(ale, cfra, NLATIME_CONVERT_UNMAP);
427
428 fpt->vec[0] = cfrae;
429 fpt->vec[1] = (fcurve_samplingcb_evalcurve(fcu, nullptr, 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
497
498/* -------------------------------------------------------------------- */
503
505{
506 bAnimContext ac;
507 SpaceGraph *sipo;
508
509 /* Get editor data. */
510 if (ANIM_animdata_get_context(C, &ac) == 0) {
511 return OPERATOR_CANCELLED;
512 }
513 sipo = (SpaceGraph *)ac.sl;
514
515 /* If no ghost curves, don't do anything. */
517 return OPERATOR_CANCELLED;
518 }
519 /* Free ghost curves. */
521
522 /* Update this editor only. */
524
525 return OPERATOR_FINISHED;
526}
527
529{
530 /* Identifiers */
531 ot->name = "Clear Ghost Curves";
532 ot->idname = "GRAPH_OT_ghost_curves_clear";
533 ot->description = "Clear F-Curve snapshots (Ghosts) for active Graph Editor";
534
535 /* API callbacks */
538
539 /* Flags */
541}
542
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:552
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:549
#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:693
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:478
#define V2D_SCROLL_HANDLE_HEIGHT
Definition UI_view2d.hh:67
#define UI_TIME_SCRUB_MARGIN_Y
Definition UI_view2d.hh:479
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_FRAME
Definition WM_types.hh:434
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:463
short ANIM_get_normalization_flags(SpaceLink *space_link)
Definition anim_draw.cc:415
void ANIM_center_frame(bContext *C, int smooth_viewtx)
Definition anim_draw.cc:768
rctf ANIM_frame_range_view2d_add_xmargin(const View2D &view_2d, const rctf view_rect)
Definition anim_draw.cc:811
float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
Definition anim_draw.cc:624
float ANIM_nla_tweakedit_remap(bAnimListElem *ale, const float cframe, const eNlaTime_ConvertModes mode)
Definition anim_draw.cc:324
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
nullptr float
#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:43
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
#define fabsf
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:4237
int WM_operator_smooth_viewtx_get(const wmOperator *op)