Blender V5.0
anim_draw.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_sys_types.h"
10
11#include "DNA_anim_types.h"
12#include "DNA_object_types.h"
13#include "DNA_scene_types.h"
14#include "DNA_screen_types.h"
15#include "DNA_sequence_types.h"
16#include "DNA_space_types.h"
17#include "DNA_userdef_types.h"
18#include "DNA_workspace_types.h"
19
20#include "BLI_listbase.h"
21#include "BLI_math_rotation.h"
22#include "BLI_math_vector.h"
23#include "BLI_rect.h"
24#include "BLI_utildefines.h"
25
26#include "BKE_context.hh"
27#include "BKE_curve.hh"
28#include "BKE_fcurve.hh"
29#include "BKE_global.hh"
30#include "BKE_mask.h"
31#include "BKE_nla.hh"
32
33#include "ED_anim_api.hh"
34#include "ED_keyframes_edit.hh"
36#include "ED_sequencer.hh"
37
38#include "RNA_access.hh"
39#include "RNA_path.hh"
40
41#include "UI_resources.hh"
42#include "UI_view2d.hh"
43
44#include "GPU_immediate.hh"
45#include "GPU_state.hh"
46
47#include "SEQ_time.hh"
48
49#include <utility>
50
51/* *************************************************** */
52/* CURRENT FRAME DRAWING */
53
54void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
55{
56 Scene *scene = CTX_data_scene(C);
57
58 const float time = scene->r.cfra + scene->r.subframe;
59 const float x = float(time * scene->r.framelen);
60
61 GPU_line_width((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0);
62
64 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
65
67
68 /* Draw a light green line to indicate current frame */
70
72 immVertex2f(pos, x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */
73 immVertex2f(pos, x, v2d->cur.ymax);
74 immEnd();
76}
77
78/* *************************************************** */
79/* PREVIEW RANGE 'CURTAINS' */
80/* NOTE: 'Preview Range' tools are defined in `anim_ops.cc`. */
81
82void ANIM_draw_previewrange(const Scene *scene, View2D *v2d, int end_frame_width)
83{
84 /* Only draw this if preview range is set. */
85 if (PRVRANGEON) {
87
89 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
90
93
94 /* Only draw two separate 'curtains' if there's no overlap between them. */
95 if (scene->r.psfra < scene->r.pefra + end_frame_width) {
96 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, float(scene->r.psfra), v2d->cur.ymax);
98 float(scene->r.pefra + end_frame_width),
99 v2d->cur.ymin,
100 v2d->cur.xmax,
101 v2d->cur.ymax);
102 }
103 else {
104 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
105 }
106
108
110 }
111}
112
114{
115 using namespace blender;
116 SpaceAction *space_action = CTX_wm_space_action(C);
117 if (!space_action || (space_action->overlays.flag & ADS_OVERLAY_SHOW_OVERLAYS) == 0 ||
118 (space_action->overlays.flag & ADS_SHOW_SCENE_STRIP_FRAME_RANGE) == 0)
119 {
120 return;
121 }
122 WorkSpace *workspace = CTX_wm_workspace(C);
123 if (!workspace) {
124 return;
125 }
126 if ((workspace->flags & WORKSPACE_SYNC_SCENE_TIME) == 0) {
127 return;
128 }
129 const Scene *sequencer_scene = workspace->sequencer_scene;
130 if (!sequencer_scene) {
131 return;
132 }
133 const Strip *scene_strip = blender::ed::vse::get_scene_strip_for_time_sync(sequencer_scene);
134 if (!scene_strip || !scene_strip->scene) {
135 return;
136 }
138
140 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
141
144
145 /* ..._handle are frames in "sequencer logic", meaning that on the right_handle point in time,
146 * the strip is not visible any more. The last visible frame of the strip is actually on
147 * (right_handle-1), hence the -1 when computing the end_frame. */
148 const float left_handle = seq::time_left_handle_frame_get(sequencer_scene, scene_strip);
149 const float right_handle = seq::time_right_handle_frame_get(sequencer_scene, scene_strip);
150 float start_frame = seq::give_frame_index(sequencer_scene, scene_strip, left_handle) +
151 scene_strip->scene->r.sfra;
152 float end_frame = seq::give_frame_index(sequencer_scene, scene_strip, right_handle - 1) +
153 scene_strip->scene->r.sfra;
154
155 /* This can happen when the strip time is reversed. */
156 if (start_frame > end_frame) {
157 std::swap(start_frame, end_frame);
158 }
159
160 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, start_frame, v2d->cur.ymax);
161 immRectf(pos, end_frame, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
162
164
166}
167
168/* *************************************************** */
169/* SCENE FRAME RANGE */
170
172{
173 /* draw darkened area outside of active timeline frame range */
175
177 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
178
181
182 if (scene->r.sfra < scene->r.efra) {
183 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, float(scene->r.sfra), v2d->cur.ymax);
184 immRectf(pos, float(scene->r.efra), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
185 }
186 else {
187 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
188 }
189
191
192 /* thin lines where the actual frames are */
194
196
197 immVertex2f(pos, float(scene->r.sfra), v2d->cur.ymin);
198 immVertex2f(pos, float(scene->r.sfra), v2d->cur.ymax);
199
200 immVertex2f(pos, float(scene->r.efra), v2d->cur.ymin);
201 immVertex2f(pos, float(scene->r.efra), v2d->cur.ymax);
202
203 immEnd();
205}
206
208 AnimData *adt, bAction *action, View2D *v2d, float ymin, float ymax)
209{
210 if ((action->flag & ACT_FRAME_RANGE) == 0) {
211 return;
212 }
213
214 /* Compute the dimensions. */
215 CLAMP_MIN(ymin, v2d->cur.ymin);
216 CLAMP_MAX(ymax, v2d->cur.ymax);
217
218 if (ymin > ymax) {
219 return;
220 }
221
222 const float sfra = BKE_nla_tweakedit_remap(adt, action->frame_start, NLATIME_CONVERT_MAP);
223 const float efra = BKE_nla_tweakedit_remap(adt, action->frame_end, NLATIME_CONVERT_MAP);
224
225 /* Diagonal stripe filled area outside of the frame range. */
227
229 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
230
232
233 float color[4];
235
236 immUniform4f("color1", color[0], color[1], color[2], color[3]);
237 immUniform4f("color2", 0.0f, 0.0f, 0.0f, 0.0f);
238 immUniform1i("size1", 2 * UI_SCALE_FAC);
239 immUniform1i("size2", 4 * UI_SCALE_FAC);
240
241 if (sfra < efra) {
242 immRectf(pos, v2d->cur.xmin, ymin, sfra, ymax);
243 immRectf(pos, efra, ymin, v2d->cur.xmax, ymax);
244 }
245 else {
246 immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax, ymax);
247 }
248
250
252
253 /* Thin lines where the actual frames are. */
256
257 GPU_line_width(1.0f);
258
260
261 immVertex2f(pos, sfra, ymin);
262 immVertex2f(pos, sfra, ymax);
263
264 immVertex2f(pos, efra, ymin);
265 immVertex2f(pos, efra, ymax);
266
267 immEnd();
269}
270
271/* *************************************************** */
272/* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes). */
273
275{
276 /* Historically, there was another check in the code that this function replaced:
277 * if (!ELEM(ac->datatype,
278 * ANIMCONT_ACTION,
279 * ANIMCONT_SHAPEKEY,
280 * ANIMCONT_DOPESHEET,
281 * ANIMCONT_FCURVES,
282 * ANIMCONT_NLA,
283 * ANIMCONT_CHANNEL,
284 * ANIMCONT_TIMELINE))
285 * {
286 * ... prevent NLA-remapping ...
287 * }
288 *
289 * I (Sybren) suspect that this was actually hiding some animation type check. When that code was
290 * written, I think there was no GreasePencil data showing in the regular Dope Sheet editor.
291 */
292
293 switch (ale->type) {
295 /* NLA Control Curves occur on NLA strips,
296 * and shouldn't be subjected to this kind of mapping. */
297 return false;
298 case ANIMTYPE_FCURVE: {
299 /* The F-Curve data of a driver should never get NLA-remapped. */
300 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
301 return !fcurve->driver;
302 }
304 case ANIMTYPE_GPLAYER:
308 /* Grease Pencil doesn't use the NLA, so don't bother remapping. */
309 return false;
312 /* I (Sybren) don't _think_ masks can use the NLA. */
313 return false;
314 case ANIMTYPE_SUMMARY:
315 /* The summary line cannot do NLA remapping since it may contain multiple actions. */
316 return false;
317 default:
318 /* NLA time remapping is the default behavior, and only should be
319 * prohibited for the above types. */
320 return true;
321 }
322}
323
325 const float cframe,
326 const eNlaTime_ConvertModes mode)
327{
328 if (!ANIM_nla_mapping_allowed(ale)) {
329 return cframe;
330 }
331 return BKE_nla_tweakedit_remap(ale->adt, cframe, mode);
332}
333
334/* ------------------- */
335
336/* Helper function for ANIM_nla_mapping_apply_fcurve() -> "restore",
337 * i.e. mapping points back to action-time. */
339{
340 /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
341 AnimData *adt = static_cast<AnimData *>(ked->data);
342 short only_keys = short(ked->i1);
343
344 /* adjust BezTriple handles only if allowed to */
345 if (only_keys == 0) {
346 bezt->vec[0][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_UNMAP);
347 bezt->vec[2][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_UNMAP);
348 }
349
350 bezt->vec[1][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_UNMAP);
351
352 return 0;
353}
354
355/* helper function for ANIM_nla_mapping_apply_fcurve() -> "apply",
356 * i.e. mapping points to NLA-mapped global time */
358{
359 /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
360 AnimData *adt = static_cast<AnimData *>(ked->data);
361 short only_keys = short(ked->i1);
362
363 /* adjust BezTriple handles only if allowed to */
364 if (only_keys == 0) {
365 bezt->vec[0][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_MAP);
366 bezt->vec[2][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_MAP);
367 }
368
369 bezt->vec[1][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_MAP);
370
371 return 0;
372}
373
374void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
375{
376 if (adt == nullptr || BLI_listbase_is_empty(&adt->nla_tracks)) {
377 return;
378 }
379 KeyframeEditData ked = {{nullptr}};
380 KeyframeEditFunc map_cb;
381
382 /* init edit data
383 * - AnimData is stored in 'data'
384 * - only_keys is stored in 'i1'
385 */
386 ked.data = (void *)adt;
387 ked.i1 = int(only_keys);
388
389 /* get editing callback */
390 if (restore) {
392 }
393 else {
394 map_cb = bezt_nlamapping_apply;
395 }
396
397 /* apply to F-Curve */
398 ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, map_cb, nullptr);
399}
400
402 FCurve *fcu,
403 const bool restore,
404 const bool only_keys)
405{
406 if (!ANIM_nla_mapping_allowed(ale)) {
407 return;
408 }
409 ANIM_nla_mapping_apply_fcurve(ale->adt, fcu, restore, only_keys);
410}
411
412/* *************************************************** */
413/* UNITS CONVERSION MAPPING (required for drawing and editing keyframes) */
414
416{
417 if (space_link->spacetype == SPACE_GRAPH) {
418 SpaceGraph *sipo = reinterpret_cast<SpaceGraph *>(space_link);
419 bool use_normalization = (sipo->flag & SIPO_NORMALIZE) != 0;
420 bool freeze_normalization = (sipo->flag & SIPO_NORMALIZE_FREEZE) != 0;
421 return use_normalization ? (ANIM_UNITCONV_NORMALIZE |
422 (freeze_normalization ? ANIM_UNITCONV_NORMALIZE_FREEZE : 0)) :
423 0;
424 }
425
426 return 0;
427}
428
430 const FCurve *fcu,
431 float *r_min_coord,
432 float *r_max_coord)
433{
434 float min_coord = FLT_MAX;
435 float max_coord = -FLT_MAX;
436 const bool use_preview_only = PRVRANGEON;
437
438 if (fcu->bezt || fcu->fpt) {
439 int start = 0;
440 int end = fcu->totvert;
441
442 if (use_preview_only) {
443 if (fcu->bezt) {
444 /* Preview frame ranges need to be converted to bezt array indices. */
445 bool replace = false;
447 fcu->bezt, scene->r.psfra, fcu->totvert, &replace);
448
450 fcu->bezt, scene->r.pefra + 1, fcu->totvert, &replace);
451 }
452 else if (fcu->fpt) {
453 const int unclamped_start = int(scene->r.psfra - fcu->fpt[0].vec[0]);
454 start = max_ii(unclamped_start, 0);
455 end = min_ii(unclamped_start + (scene->r.pefra - scene->r.psfra) + 1, fcu->totvert);
456 }
457 }
458
459 if (fcu->bezt) {
460 const BezTriple *bezt = fcu->bezt + start;
461 for (int i = start; i < end; i++, bezt++) {
462
463 if (i == 0) {
464 /* We ignore extrapolation flags and handle here, and use the
465 * control point position only. so we normalize "interesting"
466 * part of the curve.
467 *
468 * Here we handle left extrapolation.
469 */
470 max_coord = max_ff(max_coord, bezt->vec[1][1]);
471 min_coord = min_ff(min_coord, bezt->vec[1][1]);
472 }
473 else {
474 const BezTriple *prev_bezt = bezt - 1;
475 if (!ELEM(prev_bezt->ipo, BEZT_IPO_BEZ, BEZT_IPO_BACK, BEZT_IPO_ELASTIC)) {
476 /* The points on the curve will lie inside the start and end points.
477 * Calculate min/max using both previous and current CV.
478 */
479 max_coord = max_ff(max_coord, bezt->vec[1][1]);
480 min_coord = min_ff(min_coord, bezt->vec[1][1]);
481 max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
482 min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
483 }
484 else {
485 const int resol = fcu->driver ?
486 32 :
487 min_ii(int(5.0f * len_v2v2(bezt->vec[1], prev_bezt->vec[1])),
488 32);
489 if (resol < 2) {
490 max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
491 min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
492 }
493 else {
494 if (!ELEM(prev_bezt->ipo, BEZT_IPO_BACK, BEZT_IPO_ELASTIC)) {
495 /* Calculate min/max using bezier forward differencing. */
496 float data[120];
497 float v1[2], v2[2], v3[2], v4[2];
498
499 v1[0] = prev_bezt->vec[1][0];
500 v1[1] = prev_bezt->vec[1][1];
501 v2[0] = prev_bezt->vec[2][0];
502 v2[1] = prev_bezt->vec[2][1];
503
504 v3[0] = bezt->vec[0][0];
505 v3[1] = bezt->vec[0][1];
506 v4[0] = bezt->vec[1][0];
507 v4[1] = bezt->vec[1][1];
508
509 BKE_fcurve_correct_bezpart(v1, v2, v3, v4);
510
512 v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float[3]));
514 v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float[3]));
515
516 for (int j = 0; j <= resol; ++j) {
517 const float *fp = &data[j * 3];
518 max_coord = max_ff(max_coord, fp[1]);
519 min_coord = min_ff(min_coord, fp[1]);
520 }
521 }
522 else {
523 /* Calculate min/max using full fcurve evaluation.
524 * [slower than bezier forward differencing but evaluates Back/Elastic
525 * interpolation as well]. */
526 float step_size = (bezt->vec[1][0] - prev_bezt->vec[1][0]) / resol;
527 for (int j = 0; j <= resol; j++) {
528 float eval_time = prev_bezt->vec[1][0] + step_size * j;
529 float eval_value = evaluate_fcurve_only_curve(fcu, eval_time);
530 max_coord = max_ff(max_coord, eval_value);
531 min_coord = min_ff(min_coord, eval_value);
532 }
533 }
534 }
535 }
536 }
537 }
538 }
539 else if (fcu->fpt) {
540 const FPoint *fpt = fcu->fpt + start;
541 for (int i = start; i < end; ++i, ++fpt) {
542 min_coord = min_ff(min_coord, fpt->vec[1]);
543 max_coord = max_ff(max_coord, fpt->vec[1]);
544 }
545 }
546 }
547
548 if (r_min_coord) {
549 *r_min_coord = min_coord;
550 }
551 if (r_max_coord) {
552 *r_max_coord = max_coord;
553 }
554}
555
556static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, float *r_offset)
557{
558 float factor = 1.0f, offset = 0.0f;
559
561 if (r_offset) {
562 *r_offset = fcu->prev_offset;
563 }
564
565 return 1.0f / fcu->prev_norm_factor;
566 }
567
569 if (r_offset) {
570 *r_offset = fcu->prev_offset;
571 }
572 if (fcu->prev_norm_factor == 0.0f) {
573 /* Happens when Auto Normalize was disabled before
574 * any curves were displayed.
575 */
576 return 1.0f;
577 }
578 return fcu->prev_norm_factor;
579 }
580
581 if (G.moving & G_TRANSFORM_FCURVES) {
582 if (r_offset) {
583 *r_offset = fcu->prev_offset;
584 }
585 if (fcu->prev_norm_factor == 0.0f) {
586 /* Same as above. */
587 return 1.0f;
588 }
589 return fcu->prev_norm_factor;
590 }
591
592 fcu->prev_norm_factor = 1.0f;
593
594 float max_coord = -FLT_MAX;
595 float min_coord = FLT_MAX;
596 fcurve_scene_coord_range_get(scene, fcu, &min_coord, &max_coord);
597
598 /* We use an ULPS-based floating point comparison here, with the
599 * rationale that if there are too few possible values between
600 * `min_coord` and `max_coord`, then after display normalization it
601 * will certainly be a weird quantized experience for the user anyway. */
602 if (min_coord < max_coord && ulp_diff_ff(min_coord, max_coord) > 256) {
603 /* Normalize. */
604 const float range = max_coord - min_coord;
605 factor = 2.0f / range;
606 offset = -min_coord - range / 2.0f;
607 }
608 else {
609 /* Skip normalization. */
610 factor = 1.0f;
611 offset = -min_coord;
612 }
613
614 BLI_assert(factor != 0.0f);
615 if (r_offset) {
616 *r_offset = offset;
617 }
618
619 fcu->prev_norm_factor = factor;
620 fcu->prev_offset = offset;
621 return factor;
622}
623
624float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
625{
627 return normalization_factor_get(scene, fcu, flag, r_offset);
628 }
629
630 if (r_offset) {
631 *r_offset = 0.0f;
632 }
633
634 /* TODO: change the pointer parameters to references, as this function should not be called
635 * without an animated ID or a scene (to get the preferred units). */
636
637 if (!id || !fcu || !fcu->rna_path || !scene) {
638 /* Not enough information to do the remapping, so just show the data as-is. */
639 return 1.0f;
640 }
641
643 PropertyRNA *prop;
645 if (!RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
646 /* Without resolving the property, its type & subtype are unknown; remapping is impossible. */
647 return 1.0f;
648 }
649
651
652 switch (prop_unit) {
655 return 1.0f;
656 }
657
659 return DEG2RADF(1.0f);
660 }
661 return RAD2DEGF(1.0f);
662
663 default:
664 /* TODO: other rotation types here as necessary */
665 break;
666 }
667
668 return 1.0f;
669}
670
671static bool find_prev_next_keyframes(bContext *C, int *r_nextfra, int *r_prevfra)
672{
673 Scene *scene = CTX_data_scene(C);
676 bDopeSheet ads = {nullptr};
677 AnimKeylist *keylist = ED_keylist_create();
678 const ActKeyColumn *aknext, *akprev;
679 float cfranext, cfraprev;
680 bool donenext = false, doneprev = false;
681 int nextcount = 0, prevcount = 0;
682
683 cfranext = cfraprev = float(scene->r.cfra);
684
685 /* Seed up dummy dope-sheet context with flags to perform necessary filtering. */
686 if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
687 /* only selected channels are included */
689 }
690
691 /* populate tree with keyframe nodes */
692 scene_to_keylist(&ads, scene, keylist, 0, {-FLT_MAX, FLT_MAX});
693 gpencil_to_keylist(&ads, scene->gpd, keylist, false);
694
695 if (ob) {
696 ob_to_keylist(&ads, ob, keylist, 0, {-FLT_MAX, FLT_MAX});
697 gpencil_to_keylist(&ads, static_cast<bGPdata *>(ob->data), keylist, false);
698 }
699
700 if (mask) {
702 mask_to_keylist(&ads, masklay, keylist);
703 }
705
706 /* TODO(jbakker): Key-lists are ordered, no need to do any searching at all. */
707 /* find matching keyframe in the right direction */
708 do {
709 aknext = ED_keylist_find_next(keylist, cfranext);
710
711 if (aknext) {
712 if (scene->r.cfra == int(aknext->cfra)) {
713 /* make this the new starting point for the search and ignore */
714 cfranext = aknext->cfra;
715 }
716 else {
717 /* this changes the frame, so set the frame and we're done */
718 if (++nextcount == U.view_frame_keyframes) {
719 donenext = true;
720 }
721 }
722 cfranext = aknext->cfra;
723 }
724 } while ((aknext != nullptr) && (donenext == false));
725
726 do {
727 akprev = ED_keylist_find_prev(keylist, cfraprev);
728
729 if (akprev) {
730 if (scene->r.cfra == int(akprev->cfra)) {
731 /* make this the new starting point for the search */
732 }
733 else {
734 /* this changes the frame, so set the frame and we're done */
735 if (++prevcount == U.view_frame_keyframes) {
736 doneprev = true;
737 }
738 }
739 cfraprev = akprev->cfra;
740 }
741 } while ((akprev != nullptr) && (doneprev == false));
742
743 /* free temp stuff */
744 ED_keylist_free(keylist);
745
746 /* any success? */
747 if (doneprev || donenext) {
748 if (doneprev) {
749 *r_prevfra = cfraprev;
750 }
751 else {
752 *r_prevfra = scene->r.cfra - (cfranext - scene->r.cfra);
753 }
754
755 if (donenext) {
756 *r_nextfra = cfranext;
757 }
758 else {
759 *r_nextfra = scene->r.cfra + (scene->r.cfra - cfraprev);
760 }
761
762 return true;
763 }
764
765 return false;
766}
767
768void ANIM_center_frame(bContext *C, int smooth_viewtx)
769{
770 ARegion *region = CTX_wm_region(C);
771 Scene *scene = CTX_data_scene(C);
772 float w = BLI_rctf_size_x(&region->v2d.cur);
773 rctf newrct;
774 int nextfra, prevfra;
775
776 switch (U.view_frame_type) {
778 const float fps = scene->frames_per_second();
779 newrct.xmax = scene->r.cfra + U.view_frame_seconds * fps + 1;
780 newrct.xmin = scene->r.cfra - U.view_frame_seconds * fps - 1;
781 newrct.ymax = region->v2d.cur.ymax;
782 newrct.ymin = region->v2d.cur.ymin;
783 break;
784 }
785
786 /* hardest case of all, look for all keyframes around frame and display those */
788 if (find_prev_next_keyframes(C, &nextfra, &prevfra)) {
789 newrct.xmax = nextfra;
790 newrct.xmin = prevfra;
791 newrct.ymax = region->v2d.cur.ymax;
792 newrct.ymin = region->v2d.cur.ymin;
793 break;
794 }
795 /* else drop through, keep range instead */
797
799 default:
800 newrct.xmax = scene->r.cfra + (w / 2);
801 newrct.xmin = scene->r.cfra - (w / 2);
802 newrct.ymax = region->v2d.cur.ymax;
803 newrct.ymin = region->v2d.cur.ymin;
804 break;
805 }
806
807 UI_view2d_smooth_view(C, region, &newrct, smooth_viewtx);
808}
809/* *************************************************** */
810
811rctf ANIM_frame_range_view2d_add_xmargin(const View2D &view_2d, const rctf view_rect)
812{
813 /* Keyframe diamonds seem to be drawn at 10 pixels wide, multiplied by the UI scale. */
814 const float keyframe_size = 10 * UI_SCALE_FAC;
815 const float margin_in_px = 4 * keyframe_size;
816
817 /* This cannot use UI_view2d_scale_get_x(view_2d) because that would use the
818 * current scale of the view, and not the one we'd get once `view_rect` is
819 * applied. And this function should not assume that view_2d.cur == view_rect.
820 *
821 * As an added bonus, the division is inverted (compared to
822 * UI_view2d_scale_get_x()) so that we can multiply with the result instead of
823 * doing yet another division. */
824 const float target_scale = BLI_rctf_size_x(&view_rect) / BLI_rcti_size_x(&view_2d.mask);
825 const float margin_in_frames = margin_in_px * target_scale;
826
827 /* Limit the margin to a maximum of 12.5% of the available size. This will
828 * make the margins smaller when the view gets smaller, but for large views
829 * still retain the fixed size calculated above */
830 const float margin_max = 0.125f * BLI_rctf_size_x(&view_rect);
831 const float margin = std::min(margin_in_frames, margin_max);
832
833 rctf rect_with_margin = view_rect;
834 rect_with_margin.xmin -= margin;
835 rect_with_margin.xmax += margin;
836
837 return rect_with_margin;
838}
WorkSpace * CTX_wm_workspace(const bContext *C)
Mask * CTX_data_edit_mask(const bContext *C)
SpaceAction * CTX_wm_space_action(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
Definition curve.cc:1669
int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[], float frame, int arraylen, bool *r_replace)
float evaluate_fcurve_only_curve(const FCurve *fcu, float evaltime)
void BKE_fcurve_correct_bezpart(const float v1[2], float v2[2], float v3[2], const float v4[2])
@ G_TRANSFORM_FCURVES
struct MaskLayer * BKE_mask_layer_active(struct Mask *mask)
eNlaTime_ConvertModes
Definition BKE_nla.hh:544
@ NLATIME_CONVERT_MAP
Definition BKE_nla.hh:552
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:549
float BKE_nla_tweakedit_remap(AnimData *adt, float cframe, eNlaTime_ConvertModes mode)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ATTR_FALLTHROUGH
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE uint ulp_diff_ff(float a, float b)
#define DEG2RADF(_deg)
#define RAD2DEGF(_rad)
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
unsigned int uint
#define CLAMP_MAX(a, c)
#define ELEM(...)
#define CLAMP_MIN(a, b)
@ ADS_FILTER_ONLYSEL
@ ACT_FRAME_RANGE
@ ADS_SHOW_SCENE_STRIP_FRAME_RANGE
@ ADS_OVERLAY_SHOW_OVERLAYS
@ BEZT_IPO_ELASTIC
@ BEZT_IPO_BACK
@ BEZT_IPO_BEZ
Object is a sort of wrapper for general info.
@ SCE_KEYS_NO_SELONLY
@ USER_UNIT_ROT_RADIANS
#define PRVRANGEON
@ SPACE_GRAPH
@ SIPO_NORMALIZE_FREEZE
@ SIPO_NORMALIZE
#define UI_SCALE_FAC
@ ZOOM_FRAME_MODE_SECONDS
@ ZOOM_FRAME_MODE_KEYFRAMES
@ ZOOM_FRAME_MODE_KEEP_RANGE
@ WORKSPACE_SYNC_SCENE_TIME
@ ANIMTYPE_SUMMARY
@ ANIMTYPE_NLACURVE
@ ANIMTYPE_GREASE_PENCIL_DATABLOCK
@ ANIMTYPE_GPLAYER
@ ANIMTYPE_MASKDATABLOCK
@ ANIMTYPE_MASKLAYER
@ ANIMTYPE_DSGPENCIL
@ ANIMTYPE_FCURVE
@ ANIMTYPE_GREASE_PENCIL_LAYER
@ ANIMTYPE_GREASE_PENCIL_LAYER_GROUP
@ DRAWCFRA_WIDE
@ ANIM_UNITCONV_NORMALIZE
@ ANIM_UNITCONV_NORMALIZE_FREEZE
@ ANIM_UNITCONV_RESTORE
short(*)(KeyframeEditData *ked, BezTriple *bezt) KeyframeEditFunc
void immUniform4f(const char *name, float x, float y, float z, float w)
void immEnd()
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset)
void immVertex2f(uint attr_id, float x, float y)
void immUniformThemeColor(int color_id)
void immUniformThemeColorShade(int color_id, int offset)
void immUniform1i(const char *name, int x)
GPUVertFormat * immVertexFormat()
void immBegin(GPUPrimType, uint vertex_len)
void immRectf(uint pos, float x1, float y1, float x2, float y2)
@ GPU_PRIM_LINES
@ GPU_SHADER_2D_DIAG_STRIPES
@ GPU_SHADER_3D_UNIFORM_COLOR
void GPU_line_width(float width)
Definition gpu_state.cc:166
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
PropertyUnit
Definition RNA_types.hh:172
@ PROP_UNIT_ROTATION
Definition RNA_types.hh:178
#define RNA_SUBTYPE_UNIT(subtype)
Definition RNA_types.hh:218
#define C
Definition RandGen.cpp:29
@ TH_ANIM_SCENE_STRIP_RANGE
@ TH_BACK
@ TH_CFRAME
@ TH_ANIM_PREVIEW_RANGE
void UI_GetThemeColorShadeAlpha4fv(int colorid, int coloffset, int alphaoffset, float col[4])
void UI_view2d_smooth_view(const bContext *C, ARegion *region, const rctf *cur, int smooth_viewtx)
short ANIM_get_normalization_flags(SpaceLink *space_link)
Definition anim_draw.cc:415
static short bezt_nlamapping_apply(KeyframeEditData *ked, BezTriple *bezt)
Definition anim_draw.cc:357
static bool find_prev_next_keyframes(bContext *C, int *r_nextfra, int *r_prevfra)
Definition anim_draw.cc:671
void ANIM_draw_action_framerange(AnimData *adt, bAction *action, View2D *v2d, float ymin, float ymax)
Definition anim_draw.cc:207
void ANIM_nla_mapping_apply_if_needed_fcurve(bAnimListElem *ale, FCurve *fcu, const bool restore, const bool only_keys)
Definition anim_draw.cc:401
static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, float *r_offset)
Definition anim_draw.cc:556
void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
Definition anim_draw.cc:54
void ANIM_center_frame(bContext *C, int smooth_viewtx)
Definition anim_draw.cc:768
void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
Definition anim_draw.cc:374
void ANIM_draw_scene_strip_range(const bContext *C, View2D *v2d)
Definition anim_draw.cc:113
bool ANIM_nla_mapping_allowed(const bAnimListElem *ale)
Definition anim_draw.cc:274
static void fcurve_scene_coord_range_get(Scene *scene, const FCurve *fcu, float *r_min_coord, float *r_max_coord)
Definition anim_draw.cc:429
rctf ANIM_frame_range_view2d_add_xmargin(const View2D &view_2d, const rctf view_rect)
Definition anim_draw.cc:811
void ANIM_draw_previewrange(const Scene *scene, View2D *v2d, int end_frame_width)
Definition anim_draw.cc:82
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
static short bezt_nlamapping_restore(KeyframeEditData *ked, BezTriple *bezt)
Definition anim_draw.cc:338
void ANIM_draw_framerange(Scene *scene, View2D *v2d)
Definition anim_draw.cc:171
#define U
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v2
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
nullptr float
uint pos
short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, FCurve *fcu, KeyframeEditFunc key_ok, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb)
void mask_to_keylist(bDopeSheet *, MaskLayer *masklay, AnimKeylist *keylist)
const ActKeyColumn * ED_keylist_find_prev(const AnimKeylist *keylist, const float cfra)
void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, AnimKeylist *keylist, const bool active)
void scene_to_keylist(bDopeSheet *ads, Scene *sce, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void ob_to_keylist(bDopeSheet *ads, Object *ob, AnimKeylist *keylist, const int saction_flag, blender::float2 range)
void ED_keylist_prepare_for_direct_access(AnimKeylist *keylist)
AnimKeylist * ED_keylist_create()
void ED_keylist_free(AnimKeylist *keylist)
const ActKeyColumn * ED_keylist_find_next(const AnimKeylist *keylist, const float cfra)
format
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
#define G(x, y, z)
const Strip * get_scene_strip_for_time_sync(const Scene *sequence_scene)
int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
float give_frame_index(const Scene *scene, const Strip *strip, float timeline_frame)
Definition strip_time.cc:52
int time_left_handle_frame_get(const Scene *, const Strip *strip)
PropertySubType RNA_property_subtype(PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:560
#define FLT_MAX
Definition stdcycles.h:14
ListBase nla_tracks
float vec[3][3]
char * rna_path
FPoint * fpt
ChannelDriver * driver
BezTriple * bezt
float prev_norm_factor
float prev_offset
unsigned int totvert
float vec[2]
Definition DNA_ID.h:414
struct bGPdata * gpd
struct RenderData r
struct UnitSettings unit
SpaceActionOverlays overlays
struct Scene * scene
struct Scene * sequencer_scene
float frame_start
AnimData * adt
eAnim_ChannelType type
float xmax
float xmin
float ymax
float ymin
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238
uint8_t flag
Definition wm_window.cc:145