Blender V4.5
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_space_types.h"
16#include "DNA_userdef_types.h"
17
18#include "BLI_listbase.h"
19#include "BLI_math_rotation.h"
20#include "BLI_math_vector.h"
21#include "BLI_rect.h"
22#include "BLI_utildefines.h"
23
24#include "BKE_context.hh"
25#include "BKE_curve.hh"
26#include "BKE_fcurve.hh"
27#include "BKE_global.hh"
28#include "BKE_mask.h"
29#include "BKE_nla.hh"
30
31#include "ED_anim_api.hh"
32#include "ED_keyframes_edit.hh"
34
35#include "RNA_access.hh"
36#include "RNA_path.hh"
37
38#include "UI_resources.hh"
39#include "UI_view2d.hh"
40
41#include "GPU_immediate.hh"
42#include "GPU_state.hh"
43
44/* *************************************************** */
45/* CURRENT FRAME DRAWING */
46
47void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
48{
49 Scene *scene = CTX_data_scene(C);
50
51 const float time = scene->r.cfra + scene->r.subframe;
52 const float x = float(time * scene->r.framelen);
53
54 GPU_line_width((flag & DRAWCFRA_WIDE) ? 3.0 : 2.0);
55
58
60
61 /* Draw a light green line to indicate current frame */
63
65 immVertex2f(pos, x, v2d->cur.ymin - 500.0f); /* XXX arbitrary... want it go to bottom */
66 immVertex2f(pos, x, v2d->cur.ymax);
67 immEnd();
69}
70
71/* *************************************************** */
72/* PREVIEW RANGE 'CURTAINS' */
73/* NOTE: 'Preview Range' tools are defined in `anim_ops.cc`. */
74
75void ANIM_draw_previewrange(const Scene *scene, View2D *v2d, int end_frame_width)
76{
77 /* Only draw this if preview range is set. */
78 if (PRVRANGEON) {
80
83
86
87 /* Only draw two separate 'curtains' if there's no overlap between them. */
88 if (scene->r.psfra < scene->r.pefra + end_frame_width) {
89 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, float(scene->r.psfra), v2d->cur.ymax);
91 float(scene->r.pefra + end_frame_width),
92 v2d->cur.ymin,
93 v2d->cur.xmax,
94 v2d->cur.ymax);
95 }
96 else {
97 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
98 }
99
101
103 }
104}
105
106/* *************************************************** */
107/* SCENE FRAME RANGE */
108
110{
111 /* draw darkened area outside of active timeline frame range */
113
116
119
120 if (scene->r.sfra < scene->r.efra) {
121 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, float(scene->r.sfra), v2d->cur.ymax);
122 immRectf(pos, float(scene->r.efra), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
123 }
124 else {
125 immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
126 }
127
129
130 /* thin lines where the actual frames are */
132
134
135 immVertex2f(pos, float(scene->r.sfra), v2d->cur.ymin);
136 immVertex2f(pos, float(scene->r.sfra), v2d->cur.ymax);
137
138 immVertex2f(pos, float(scene->r.efra), v2d->cur.ymin);
139 immVertex2f(pos, float(scene->r.efra), v2d->cur.ymax);
140
141 immEnd();
143}
144
146 AnimData *adt, bAction *action, View2D *v2d, float ymin, float ymax)
147{
148 if ((action->flag & ACT_FRAME_RANGE) == 0) {
149 return;
150 }
151
152 /* Compute the dimensions. */
153 CLAMP_MIN(ymin, v2d->cur.ymin);
154 CLAMP_MAX(ymax, v2d->cur.ymax);
155
156 if (ymin > ymax) {
157 return;
158 }
159
160 const float sfra = BKE_nla_tweakedit_remap(adt, action->frame_start, NLATIME_CONVERT_MAP);
161 const float efra = BKE_nla_tweakedit_remap(adt, action->frame_end, NLATIME_CONVERT_MAP);
162
163 /* Diagonal stripe filled area outside of the frame range. */
165
168
170
171 float color[4];
172 UI_GetThemeColorShadeAlpha4fv(TH_BACK, -40, -50, color);
173
174 immUniform4f("color1", color[0], color[1], color[2], color[3]);
175 immUniform4f("color2", 0.0f, 0.0f, 0.0f, 0.0f);
176 immUniform1i("size1", 2 * UI_SCALE_FAC);
177 immUniform1i("size2", 4 * UI_SCALE_FAC);
178
179 if (sfra < efra) {
180 immRectf(pos, v2d->cur.xmin, ymin, sfra, ymax);
181 immRectf(pos, efra, ymin, v2d->cur.xmax, ymax);
182 }
183 else {
184 immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax, ymax);
185 }
186
188
190
191 /* Thin lines where the actual frames are. */
194
195 GPU_line_width(1.0f);
196
198
199 immVertex2f(pos, sfra, ymin);
200 immVertex2f(pos, sfra, ymax);
201
202 immVertex2f(pos, efra, ymin);
203 immVertex2f(pos, efra, ymax);
204
205 immEnd();
207}
208
209/* *************************************************** */
210/* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes). */
211
213{
214 /* Historically, there was another check in the code that this function replaced:
215 * if (!ELEM(ac->datatype,
216 * ANIMCONT_ACTION,
217 * ANIMCONT_SHAPEKEY,
218 * ANIMCONT_DOPESHEET,
219 * ANIMCONT_FCURVES,
220 * ANIMCONT_NLA,
221 * ANIMCONT_CHANNEL,
222 * ANIMCONT_TIMELINE))
223 * {
224 * ... prevent NLA-remapping ...
225 * }
226 *
227 * I (Sybren) suspect that this was actually hiding some animation type check. When that code was
228 * written, I think there was no GreasePencil data showing in the regular Dope Sheet editor.
229 */
230
231 switch (ale->type) {
233 /* NLA Control Curves occur on NLA strips,
234 * and shouldn't be subjected to this kind of mapping. */
235 return false;
236 case ANIMTYPE_FCURVE: {
237 /* The F-Curve data of a driver should never get NLA-remapped. */
238 FCurve *fcurve = static_cast<FCurve *>(ale->key_data);
239 return !fcurve->driver;
240 }
242 case ANIMTYPE_GPLAYER:
246 /* Grease Pencil doesn't use the NLA, so don't bother remapping. */
247 return false;
250 /* I (Sybren) don't _think_ masks can use the NLA. */
251 return false;
252 case ANIMTYPE_SUMMARY:
253 /* The summary line cannot do NLA remapping since it may contain multiple actions. */
254 return false;
255 default:
256 /* NLA time remapping is the default behavior, and only should be
257 * prohibited for the above types. */
258 return true;
259 }
260}
261
263 const float cframe,
264 const eNlaTime_ConvertModes mode)
265{
266 if (!ANIM_nla_mapping_allowed(ale)) {
267 return cframe;
268 }
269 return BKE_nla_tweakedit_remap(ale->adt, cframe, mode);
270}
271
272/* ------------------- */
273
274/* Helper function for ANIM_nla_mapping_apply_fcurve() -> "restore",
275 * i.e. mapping points back to action-time. */
277{
278 /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
279 AnimData *adt = static_cast<AnimData *>(ked->data);
280 short only_keys = short(ked->i1);
281
282 /* adjust BezTriple handles only if allowed to */
283 if (only_keys == 0) {
284 bezt->vec[0][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_UNMAP);
285 bezt->vec[2][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_UNMAP);
286 }
287
288 bezt->vec[1][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_UNMAP);
289
290 return 0;
291}
292
293/* helper function for ANIM_nla_mapping_apply_fcurve() -> "apply",
294 * i.e. mapping points to NLA-mapped global time */
296{
297 /* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
298 AnimData *adt = static_cast<AnimData *>(ked->data);
299 short only_keys = short(ked->i1);
300
301 /* adjust BezTriple handles only if allowed to */
302 if (only_keys == 0) {
303 bezt->vec[0][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_MAP);
304 bezt->vec[2][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_MAP);
305 }
306
307 bezt->vec[1][0] = BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_MAP);
308
309 return 0;
310}
311
312void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
313{
314 if (adt == nullptr || BLI_listbase_is_empty(&adt->nla_tracks)) {
315 return;
316 }
317 KeyframeEditData ked = {{nullptr}};
318 KeyframeEditFunc map_cb;
319
320 /* init edit data
321 * - AnimData is stored in 'data'
322 * - only_keys is stored in 'i1'
323 */
324 ked.data = (void *)adt;
325 ked.i1 = int(only_keys);
326
327 /* get editing callback */
328 if (restore) {
330 }
331 else {
332 map_cb = bezt_nlamapping_apply;
333 }
334
335 /* apply to F-Curve */
336 ANIM_fcurve_keyframes_loop(&ked, fcu, nullptr, map_cb, nullptr);
337}
338
340 FCurve *fcu,
341 const bool restore,
342 const bool only_keys)
343{
344 if (!ANIM_nla_mapping_allowed(ale)) {
345 return;
346 }
347 ANIM_nla_mapping_apply_fcurve(ale->adt, fcu, restore, only_keys);
348}
349
350/* *************************************************** */
351/* UNITS CONVERSION MAPPING (required for drawing and editing keyframes) */
352
354{
355 if (space_link->spacetype == SPACE_GRAPH) {
356 SpaceGraph *sipo = reinterpret_cast<SpaceGraph *>(space_link);
357 bool use_normalization = (sipo->flag & SIPO_NORMALIZE) != 0;
358 bool freeze_normalization = (sipo->flag & SIPO_NORMALIZE_FREEZE) != 0;
359 return use_normalization ? (ANIM_UNITCONV_NORMALIZE |
360 (freeze_normalization ? ANIM_UNITCONV_NORMALIZE_FREEZE : 0)) :
361 0;
362 }
363
364 return 0;
365}
366
368 const FCurve *fcu,
369 float *r_min_coord,
370 float *r_max_coord)
371{
372 float min_coord = FLT_MAX;
373 float max_coord = -FLT_MAX;
374 const bool use_preview_only = PRVRANGEON;
375
376 if (fcu->bezt || fcu->fpt) {
377 int start = 0;
378 int end = fcu->totvert;
379
380 if (use_preview_only) {
381 if (fcu->bezt) {
382 /* Preview frame ranges need to be converted to bezt array indices. */
383 bool replace = false;
385 fcu->bezt, scene->r.psfra, fcu->totvert, &replace);
386
388 fcu->bezt, scene->r.pefra + 1, fcu->totvert, &replace);
389 }
390 else if (fcu->fpt) {
391 const int unclamped_start = int(scene->r.psfra - fcu->fpt[0].vec[0]);
392 start = max_ii(unclamped_start, 0);
393 end = min_ii(unclamped_start + (scene->r.pefra - scene->r.psfra) + 1, fcu->totvert);
394 }
395 }
396
397 if (fcu->bezt) {
398 const BezTriple *bezt = fcu->bezt + start;
399 for (int i = start; i < end; i++, bezt++) {
400
401 if (i == 0) {
402 /* We ignore extrapolation flags and handle here, and use the
403 * control point position only. so we normalize "interesting"
404 * part of the curve.
405 *
406 * Here we handle left extrapolation.
407 */
408 max_coord = max_ff(max_coord, bezt->vec[1][1]);
409 min_coord = min_ff(min_coord, bezt->vec[1][1]);
410 }
411 else {
412 const BezTriple *prev_bezt = bezt - 1;
413 if (!ELEM(prev_bezt->ipo, BEZT_IPO_BEZ, BEZT_IPO_BACK, BEZT_IPO_ELASTIC)) {
414 /* The points on the curve will lie inside the start and end points.
415 * Calculate min/max using both previous and current CV.
416 */
417 max_coord = max_ff(max_coord, bezt->vec[1][1]);
418 min_coord = min_ff(min_coord, bezt->vec[1][1]);
419 max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
420 min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
421 }
422 else {
423 const int resol = fcu->driver ?
424 32 :
425 min_ii(int(5.0f * len_v2v2(bezt->vec[1], prev_bezt->vec[1])),
426 32);
427 if (resol < 2) {
428 max_coord = max_ff(max_coord, prev_bezt->vec[1][1]);
429 min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
430 }
431 else {
432 if (!ELEM(prev_bezt->ipo, BEZT_IPO_BACK, BEZT_IPO_ELASTIC)) {
433 /* Calculate min/max using bezier forward differencing. */
434 float data[120];
435 float v1[2], v2[2], v3[2], v4[2];
436
437 v1[0] = prev_bezt->vec[1][0];
438 v1[1] = prev_bezt->vec[1][1];
439 v2[0] = prev_bezt->vec[2][0];
440 v2[1] = prev_bezt->vec[2][1];
441
442 v3[0] = bezt->vec[0][0];
443 v3[1] = bezt->vec[0][1];
444 v4[0] = bezt->vec[1][0];
445 v4[1] = bezt->vec[1][1];
446
447 BKE_fcurve_correct_bezpart(v1, v2, v3, v4);
448
450 v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float[3]));
452 v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float[3]));
453
454 for (int j = 0; j <= resol; ++j) {
455 const float *fp = &data[j * 3];
456 max_coord = max_ff(max_coord, fp[1]);
457 min_coord = min_ff(min_coord, fp[1]);
458 }
459 }
460 else {
461 /* Calculate min/max using full fcurve evaluation.
462 * [slower than bezier forward differencing but evaluates Back/Elastic
463 * interpolation as well]. */
464 float step_size = (bezt->vec[1][0] - prev_bezt->vec[1][0]) / resol;
465 for (int j = 0; j <= resol; j++) {
466 float eval_time = prev_bezt->vec[1][0] + step_size * j;
467 float eval_value = evaluate_fcurve_only_curve(fcu, eval_time);
468 max_coord = max_ff(max_coord, eval_value);
469 min_coord = min_ff(min_coord, eval_value);
470 }
471 }
472 }
473 }
474 }
475 }
476 }
477 else if (fcu->fpt) {
478 const FPoint *fpt = fcu->fpt + start;
479 for (int i = start; i < end; ++i, ++fpt) {
480 min_coord = min_ff(min_coord, fpt->vec[1]);
481 max_coord = max_ff(max_coord, fpt->vec[1]);
482 }
483 }
484 }
485
486 if (r_min_coord) {
487 *r_min_coord = min_coord;
488 }
489 if (r_max_coord) {
490 *r_max_coord = max_coord;
491 }
492}
493
494static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, float *r_offset)
495{
496 float factor = 1.0f, offset = 0.0f;
497
499 if (r_offset) {
500 *r_offset = fcu->prev_offset;
501 }
502
503 return 1.0f / fcu->prev_norm_factor;
504 }
505
507 if (r_offset) {
508 *r_offset = fcu->prev_offset;
509 }
510 if (fcu->prev_norm_factor == 0.0f) {
511 /* Happens when Auto Normalize was disabled before
512 * any curves were displayed.
513 */
514 return 1.0f;
515 }
516 return fcu->prev_norm_factor;
517 }
518
519 if (G.moving & G_TRANSFORM_FCURVES) {
520 if (r_offset) {
521 *r_offset = fcu->prev_offset;
522 }
523 if (fcu->prev_norm_factor == 0.0f) {
524 /* Same as above. */
525 return 1.0f;
526 }
527 return fcu->prev_norm_factor;
528 }
529
530 fcu->prev_norm_factor = 1.0f;
531
532 float max_coord = -FLT_MAX;
533 float min_coord = FLT_MAX;
534 fcurve_scene_coord_range_get(scene, fcu, &min_coord, &max_coord);
535
536 /* We use an ULPS-based floating point comparison here, with the
537 * rationale that if there are too few possible values between
538 * `min_coord` and `max_coord`, then after display normalization it
539 * will certainly be a weird quantized experience for the user anyway. */
540 if (min_coord < max_coord && ulp_diff_ff(min_coord, max_coord) > 256) {
541 /* Normalize. */
542 const float range = max_coord - min_coord;
543 factor = 2.0f / range;
544 offset = -min_coord - range / 2.0f;
545 }
546 else {
547 /* Skip normalization. */
548 factor = 1.0f;
549 offset = -min_coord;
550 }
551
552 BLI_assert(factor != 0.0f);
553 if (r_offset) {
554 *r_offset = offset;
555 }
556
557 fcu->prev_norm_factor = factor;
558 fcu->prev_offset = offset;
559 return factor;
560}
561
562float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short flag, float *r_offset)
563{
565 return normalization_factor_get(scene, fcu, flag, r_offset);
566 }
567
568 if (r_offset) {
569 *r_offset = 0.0f;
570 }
571
572 /* sanity checks */
573 if (id && fcu && fcu->rna_path) {
575 PropertyRNA *prop;
576
577 /* get RNA property that F-Curve affects */
579 if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
580 /* rotations: radians <-> degrees? */
582 /* if the radians flag is not set, default to using degrees which need conversions */
583 if ((scene) && (scene->unit.system_rotation == USER_UNIT_ROT_RADIANS) == 0) {
585 return DEG2RADF(1.0f); /* degrees to radians */
586 }
587 return RAD2DEGF(1.0f); /* radians to degrees */
588 }
589 }
590
591 /* TODO: other rotation types here as necessary */
592 }
593 }
594
595 /* no mapping needs to occur... */
596 return 1.0f;
597}
598
599static bool find_prev_next_keyframes(bContext *C, int *r_nextfra, int *r_prevfra)
600{
601 Scene *scene = CTX_data_scene(C);
604 bDopeSheet ads = {nullptr};
605 AnimKeylist *keylist = ED_keylist_create();
606 const ActKeyColumn *aknext, *akprev;
607 float cfranext, cfraprev;
608 bool donenext = false, doneprev = false;
609 int nextcount = 0, prevcount = 0;
610
611 cfranext = cfraprev = float(scene->r.cfra);
612
613 /* Seed up dummy dope-sheet context with flags to perform necessary filtering. */
614 if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
615 /* only selected channels are included */
617 }
618
619 /* populate tree with keyframe nodes */
620 scene_to_keylist(&ads, scene, keylist, 0, {-FLT_MAX, FLT_MAX});
621 gpencil_to_keylist(&ads, scene->gpd, keylist, false);
622
623 if (ob) {
624 ob_to_keylist(&ads, ob, keylist, 0, {-FLT_MAX, FLT_MAX});
625 gpencil_to_keylist(&ads, static_cast<bGPdata *>(ob->data), keylist, false);
626 }
627
628 if (mask) {
630 mask_to_keylist(&ads, masklay, keylist);
631 }
633
634 /* TODO(jbakker): Key-lists are ordered, no need to do any searching at all. */
635 /* find matching keyframe in the right direction */
636 do {
637 aknext = ED_keylist_find_next(keylist, cfranext);
638
639 if (aknext) {
640 if (scene->r.cfra == int(aknext->cfra)) {
641 /* make this the new starting point for the search and ignore */
642 cfranext = aknext->cfra;
643 }
644 else {
645 /* this changes the frame, so set the frame and we're done */
646 if (++nextcount == U.view_frame_keyframes) {
647 donenext = true;
648 }
649 }
650 cfranext = aknext->cfra;
651 }
652 } while ((aknext != nullptr) && (donenext == false));
653
654 do {
655 akprev = ED_keylist_find_prev(keylist, cfraprev);
656
657 if (akprev) {
658 if (scene->r.cfra == int(akprev->cfra)) {
659 /* make this the new starting point for the search */
660 }
661 else {
662 /* this changes the frame, so set the frame and we're done */
663 if (++prevcount == U.view_frame_keyframes) {
664 doneprev = true;
665 }
666 }
667 cfraprev = akprev->cfra;
668 }
669 } while ((akprev != nullptr) && (doneprev == false));
670
671 /* free temp stuff */
672 ED_keylist_free(keylist);
673
674 /* any success? */
675 if (doneprev || donenext) {
676 if (doneprev) {
677 *r_prevfra = cfraprev;
678 }
679 else {
680 *r_prevfra = scene->r.cfra - (cfranext - scene->r.cfra);
681 }
682
683 if (donenext) {
684 *r_nextfra = cfranext;
685 }
686 else {
687 *r_nextfra = scene->r.cfra + (scene->r.cfra - cfraprev);
688 }
689
690 return true;
691 }
692
693 return false;
694}
695
696void ANIM_center_frame(bContext *C, int smooth_viewtx)
697{
698 ARegion *region = CTX_wm_region(C);
699 Scene *scene = CTX_data_scene(C);
700 float w = BLI_rctf_size_x(&region->v2d.cur);
701 rctf newrct;
702 int nextfra, prevfra;
703
704 switch (U.view_frame_type) {
706 const float fps = FPS;
707 newrct.xmax = scene->r.cfra + U.view_frame_seconds * fps + 1;
708 newrct.xmin = scene->r.cfra - U.view_frame_seconds * fps - 1;
709 newrct.ymax = region->v2d.cur.ymax;
710 newrct.ymin = region->v2d.cur.ymin;
711 break;
712 }
713
714 /* hardest case of all, look for all keyframes around frame and display those */
716 if (find_prev_next_keyframes(C, &nextfra, &prevfra)) {
717 newrct.xmax = nextfra;
718 newrct.xmin = prevfra;
719 newrct.ymax = region->v2d.cur.ymax;
720 newrct.ymin = region->v2d.cur.ymin;
721 break;
722 }
723 /* else drop through, keep range instead */
725
727 default:
728 newrct.xmax = scene->r.cfra + (w / 2);
729 newrct.xmin = scene->r.cfra - (w / 2);
730 newrct.ymax = region->v2d.cur.ymax;
731 newrct.ymin = region->v2d.cur.ymin;
732 break;
733 }
734
735 UI_view2d_smooth_view(C, region, &newrct, smooth_viewtx);
736}
737/* *************************************************** */
738
739rctf ANIM_frame_range_view2d_add_xmargin(const View2D &view_2d, const rctf view_rect)
740{
741 /* Keyframe diamonds seem to be drawn at 10 pixels wide, multiplied by the UI scale. */
742 const float keyframe_size = 10 * UI_SCALE_FAC;
743 const float margin_in_px = 4 * keyframe_size;
744
745 /* This cannot use UI_view2d_scale_get_x(view_2d) because that would use the
746 * current scale of the view, and not the one we'd get once `view_rect` is
747 * applied. And this function should not assume that view_2d.cur == view_rect.
748 *
749 * As an added bonus, the division is inverted (compared to
750 * UI_view2d_scale_get_x()) so that we can multiply with the result instead of
751 * doing yet another division. */
752 const float target_scale = BLI_rctf_size_x(&view_rect) / BLI_rcti_size_x(&view_2d.mask);
753 const float margin_in_frames = margin_in_px * target_scale;
754
755 /* Limit the margin to a maximum of 12.5% of the available size. This will
756 * make the margins smaller when the view gets smaller, but for large views
757 * still retain the fixed size calculated above */
758 const float margin_max = 0.125f * BLI_rctf_size_x(&view_rect);
759 const float margin = std::min(margin_in_frames, margin_max);
760
761 rctf rect_with_margin = view_rect;
762 rect_with_margin.xmin -= margin;
763 rect_with_margin.xmax += margin;
764
765 return rect_with_margin;
766}
Mask * CTX_data_edit_mask(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:1673
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:535
@ NLATIME_CONVERT_MAP
Definition BKE_nla.hh:543
@ NLATIME_CONVERT_UNMAP
Definition BKE_nla.hh:540
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
@ BEZT_IPO_ELASTIC
@ BEZT_IPO_BACK
@ BEZT_IPO_BEZ
Object is a sort of wrapper for general info.
@ USER_UNIT_ROT_RADIANS
#define FPS
@ SCE_KEYS_NO_SELONLY
#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
@ 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 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 immBindBuiltinProgram(eGPUBuiltinShader shader_id)
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
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
void GPU_line_width(float width)
Definition gpu_state.cc:166
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ PROP_UNIT_ROTATION
Definition RNA_types.hh:166
#define RNA_SUBTYPE_UNIT(subtype)
Definition RNA_types.hh:206
#define C
Definition RandGen.cpp:29
@ 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:353
static short bezt_nlamapping_apply(KeyframeEditData *ked, BezTriple *bezt)
Definition anim_draw.cc:295
static bool find_prev_next_keyframes(bContext *C, int *r_nextfra, int *r_prevfra)
Definition anim_draw.cc:599
void ANIM_draw_action_framerange(AnimData *adt, bAction *action, View2D *v2d, float ymin, float ymax)
Definition anim_draw.cc:145
void ANIM_nla_mapping_apply_if_needed_fcurve(bAnimListElem *ale, FCurve *fcu, const bool restore, const bool only_keys)
Definition anim_draw.cc:339
static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, float *r_offset)
Definition anim_draw.cc:494
void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
Definition anim_draw.cc:47
void ANIM_center_frame(bContext *C, int smooth_viewtx)
Definition anim_draw.cc:696
void ANIM_nla_mapping_apply_fcurve(AnimData *adt, FCurve *fcu, bool restore, bool only_keys)
Definition anim_draw.cc:312
bool ANIM_nla_mapping_allowed(const bAnimListElem *ale)
Definition anim_draw.cc:212
static void fcurve_scene_coord_range_get(Scene *scene, const FCurve *fcu, float *r_min_coord, float *r_max_coord)
Definition anim_draw.cc:367
rctf ANIM_frame_range_view2d_add_xmargin(const View2D &view_2d, const rctf view_rect)
Definition anim_draw.cc:739
void ANIM_draw_previewrange(const Scene *scene, View2D *v2d, int end_frame_width)
Definition anim_draw.cc:75
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
static short bezt_nlamapping_restore(KeyframeEditData *ked, BezTriple *bezt)
Definition anim_draw.cc:276
void ANIM_draw_framerange(Scene *scene, View2D *v2d)
Definition anim_draw.cc:109
#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
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)
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:404
struct bGPdata * gpd
struct RenderData r
struct UnitSettings unit
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:4226
uint8_t flag
Definition wm_window.cc:139