From 3c38d804062f65fde064ea5a595ab5b82314d7a1 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 8 Jun 2023 12:22:24 +0200 Subject: [PATCH 1/3] refactor draw fcurve function --- .../blender/editors/space_graph/graph_draw.c | 217 ++++++++++-------- 1 file changed, 118 insertions(+), 99 deletions(-) diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 215f5836aa5..58253eac462 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -819,7 +819,68 @@ static bool fcurve_can_use_simple_bezt_drawing(FCurve *fcu) return true; } -/* helper func - draw one repeat of an F-Curve (using Bezier curve approximations) */ +static int calculate_bezt_draw_resolution(BezTriple *bezt, + BezTriple *prevbezt, + const int max_bez_resolution, + const bool is_driver) +{ + if (is_driver) { + return max_bez_resolution; + } + + int resolution = (int)(5.0f * len_v2v2(bezt->vec[1], prevbezt->vec[1])); + + /* NOTE: higher values will crash */ + /* TODO: view scale should factor into this someday too... */ + if (resolution > max_bez_resolution) { + resolution = max_bez_resolution; + } + return resolution; +} + +/** Draw a segment from \param prevbezt to \param bezt at the given \param resolution. + * immBeginAtMost is expected to be called with enough space for this function to run. + */ +static void draw_bezt(BezTriple *bezt, BezTriple *prevbezt, int resolution, uint pos) +{ + float prev_key[2], prev_handle[2], bez_handle[2], bez_key[2]; + float data[120]; + + if (resolution < 2) { + prev_key[0] = prevbezt->vec[1][0]; + prev_key[1] = prevbezt->vec[1][1]; + immVertex2fv(pos, prev_key); + return; + } + + prev_key[0] = prevbezt->vec[1][0]; + prev_key[1] = prevbezt->vec[1][1]; + prev_handle[0] = prevbezt->vec[2][0]; + prev_handle[1] = prevbezt->vec[2][1]; + + bez_handle[0] = bezt->vec[0][0]; + bez_handle[1] = bezt->vec[0][1]; + bez_key[0] = bezt->vec[1][0]; + bez_key[1] = bezt->vec[1][1]; + + BKE_fcurve_correct_bezpart(prev_key, prev_handle, bez_handle, bez_key); + + BKE_curve_forward_diff_bezier( + prev_key[0], prev_handle[0], bez_handle[0], bez_key[0], data, resolution, sizeof(float[3])); + BKE_curve_forward_diff_bezier(prev_key[1], + prev_handle[1], + bez_handle[1], + bez_key[1], + data + 1, + resolution, + sizeof(float[3])); + + for (float *fp = data; resolution; resolution--, fp += 3) { + immVertex2fv(pos, fp); + } +} + +/* Helper function - draw one repeat of an F-Curve (using Bezier curve approximations). */ static void draw_fcurve_curve_bezts( bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, uint pos, const bool draw_extrapolation) { @@ -827,178 +888,136 @@ static void draw_fcurve_curve_bezts( return; } - BezTriple *prevbezt = fcu->bezt; - BezTriple *bezt = prevbezt + 1; - float v1[2], v2[2], v3[2], v4[2]; - float *fp, data[120]; - float fac = 0.0f; - int b = fcu->totvert - 1; - int resol; - float unit_scale, offset; - short mapping_flag = ANIM_get_normalization_flags(ac); - - /* apply unit mapping */ + /* Apply unit mapping. */ GPU_matrix_push(); - unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset); + float offset; + short mapping_flag = ANIM_get_normalization_flags(ac); + const float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset); GPU_matrix_scale_2f(1.0f, unit_scale); GPU_matrix_translate_2f(0.0f, offset); /* For now, this assumes the worst case scenario, where all the keyframes have * bezier interpolation, and are drawn at full res. * This is tricky to optimize, but maybe can be improved at some point... */ - immBeginAtMost(GPU_PRIM_LINE_STRIP, (b * 32 + 3)); + int b = fcu->totvert - 1; + const int max_bezt_resolution = 32; + immBeginAtMost(GPU_PRIM_LINE_STRIP, (b * max_bezt_resolution + 3)); - /* extrapolate to left? */ + BezTriple *prevbezt = fcu->bezt; + BezTriple *bezt = prevbezt + 1; + + float vertex_position[2]; + float fac = 0.0f; + + /* Extrapolate to the left? */ if (draw_extrapolation && prevbezt->vec[1][0] > v2d->cur.xmin) { /* left-side of view comes before first keyframe, so need to extend as not cyclic */ - v1[0] = v2d->cur.xmin; + vertex_position[0] = v2d->cur.xmin; /* y-value depends on the interpolation */ if ((fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) || (prevbezt->ipo == BEZT_IPO_CONST) || (prevbezt->ipo == BEZT_IPO_LIN && fcu->totvert == 1)) { /* just extend across the first keyframe's value */ - v1[1] = prevbezt->vec[1][1]; + vertex_position[1] = prevbezt->vec[1][1]; } else if (prevbezt->ipo == BEZT_IPO_LIN) { /* extrapolate linear doesn't use the handle, use the next points center instead */ - fac = (prevbezt->vec[1][0] - bezt->vec[1][0]) / (prevbezt->vec[1][0] - v1[0]); + fac = (prevbezt->vec[1][0] - bezt->vec[1][0]) / (prevbezt->vec[1][0] - vertex_position[0]); if (fac) { fac = 1.0f / fac; } - v1[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[1][1] - bezt->vec[1][1]); + vertex_position[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[1][1] - bezt->vec[1][1]); } else { /* based on angle of handle 1 (relative to keyframe) */ - fac = (prevbezt->vec[0][0] - prevbezt->vec[1][0]) / (prevbezt->vec[1][0] - v1[0]); + fac = (prevbezt->vec[0][0] - prevbezt->vec[1][0]) / + (prevbezt->vec[1][0] - vertex_position[0]); if (fac) { fac = 1.0f / fac; } - v1[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[0][1] - prevbezt->vec[1][1]); + vertex_position[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[0][1] - prevbezt->vec[1][1]); } - immVertex2fv(pos, v1); + immVertex2fv(pos, vertex_position); } - /* if only one keyframe, add it now */ + /* If only one keyframe, add it now. */ if (fcu->totvert == 1) { - v1[0] = prevbezt->vec[1][0]; - v1[1] = prevbezt->vec[1][1]; - immVertex2fv(pos, v1); + vertex_position[0] = prevbezt->vec[1][0]; + vertex_position[1] = prevbezt->vec[1][1]; + immVertex2fv(pos, vertex_position); } - /* draw curve between first and last keyframe (if there are enough to do so) */ + /* Draw curve between first and last keyframe (if there are enough to do so). */ /* TODO: optimize this to not have to calc stuff out of view too? */ while (b--) { if (prevbezt->ipo == BEZT_IPO_CONST) { /* Constant-Interpolation: draw segment between previous keyframe and next, * but holding same value */ - v1[0] = prevbezt->vec[1][0]; - v1[1] = prevbezt->vec[1][1]; - immVertex2fv(pos, v1); + vertex_position[0] = prevbezt->vec[1][0]; + vertex_position[1] = prevbezt->vec[1][1]; + immVertex2fv(pos, vertex_position); - v1[0] = bezt->vec[1][0]; - v1[1] = prevbezt->vec[1][1]; - immVertex2fv(pos, v1); + vertex_position[0] = bezt->vec[1][0]; + vertex_position[1] = prevbezt->vec[1][1]; + immVertex2fv(pos, vertex_position); } else if (prevbezt->ipo == BEZT_IPO_LIN) { /* Linear interpolation: just add one point (which should add a new line segment) */ - v1[0] = prevbezt->vec[1][0]; - v1[1] = prevbezt->vec[1][1]; - immVertex2fv(pos, v1); + vertex_position[0] = prevbezt->vec[1][0]; + vertex_position[1] = prevbezt->vec[1][1]; + immVertex2fv(pos, vertex_position); } else if (prevbezt->ipo == BEZT_IPO_BEZ) { - /* Bezier-Interpolation: draw curve as series of segments between keyframes - * - resol determines number of points to sample in between keyframes - */ - - /* resol depends on distance between points - * (not just horizontal) OR is a fixed high res */ - /* TODO: view scale should factor into this someday too... */ - if (fcu->driver) { - resol = 32; - } - else { - resol = (int)(5.0f * len_v2v2(bezt->vec[1], prevbezt->vec[1])); - } - - if (resol < 2) { - /* only draw one */ - v1[0] = prevbezt->vec[1][0]; - v1[1] = prevbezt->vec[1][1]; - immVertex2fv(pos, v1); - } - else { - /* clamp resolution to max of 32 */ - /* NOTE: higher values will crash */ - if (resol > 32) { - resol = 32; - } - - v1[0] = prevbezt->vec[1][0]; - v1[1] = prevbezt->vec[1][1]; - v2[0] = prevbezt->vec[2][0]; - v2[1] = prevbezt->vec[2][1]; - - v3[0] = bezt->vec[0][0]; - v3[1] = bezt->vec[0][1]; - v4[0] = bezt->vec[1][0]; - v4[1] = bezt->vec[1][1]; - - BKE_fcurve_correct_bezpart(v1, v2, v3, v4); - - BKE_curve_forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float[3])); - BKE_curve_forward_diff_bezier( - v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float[3])); - - for (fp = data; resol; resol--, fp += 3) { - immVertex2fv(pos, fp); - } - } + int resolution = calculate_bezt_draw_resolution( + bezt, prevbezt, max_bezt_resolution, fcu->driver != NULL); + draw_bezt(bezt, prevbezt, max_bezt_resolution, pos); } - /* get next pointers */ + /* Get next pointers. */ prevbezt = bezt; bezt++; - /* last point? */ + /* Last point? */ if (b == 0) { - v1[0] = prevbezt->vec[1][0]; - v1[1] = prevbezt->vec[1][1]; - immVertex2fv(pos, v1); + vertex_position[0] = prevbezt->vec[1][0]; + vertex_position[1] = prevbezt->vec[1][1]; + immVertex2fv(pos, vertex_position); } } - /* extrapolate to right? (see code for left-extrapolation above too) */ + /* Extrapolate to the right? (see code for left-extrapolation above too) */ if (draw_extrapolation && prevbezt->vec[1][0] < v2d->cur.xmax) { - v1[0] = v2d->cur.xmax; + vertex_position[0] = v2d->cur.xmax; - /* y-value depends on the interpolation */ + /* y-value depends on the interpolation. */ if ((fcu->extend == FCURVE_EXTRAPOLATE_CONSTANT) || (fcu->flag & FCURVE_INT_VALUES) || (prevbezt->ipo == BEZT_IPO_CONST) || (prevbezt->ipo == BEZT_IPO_LIN && fcu->totvert == 1)) { /* based on last keyframe's value */ - v1[1] = prevbezt->vec[1][1]; + vertex_position[1] = prevbezt->vec[1][1]; } else if (prevbezt->ipo == BEZT_IPO_LIN) { - /* extrapolate linear doesn't use the handle, use the previous points center instead */ + /* Extrapolate linear doesn't use the handle, use the previous points center instead. */ bezt = prevbezt - 1; - fac = (prevbezt->vec[1][0] - bezt->vec[1][0]) / (prevbezt->vec[1][0] - v1[0]); + fac = (prevbezt->vec[1][0] - bezt->vec[1][0]) / (prevbezt->vec[1][0] - vertex_position[0]); if (fac) { fac = 1.0f / fac; } - v1[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[1][1] - bezt->vec[1][1]); + vertex_position[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[1][1] - bezt->vec[1][1]); } else { - /* based on angle of handle 1 (relative to keyframe) */ - fac = (prevbezt->vec[2][0] - prevbezt->vec[1][0]) / (prevbezt->vec[1][0] - v1[0]); + /* Based on angle of handle 1 (relative to keyframe). */ + fac = (prevbezt->vec[2][0] - prevbezt->vec[1][0]) / + (prevbezt->vec[1][0] - vertex_position[0]); if (fac) { fac = 1.0f / fac; } - v1[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[2][1] - prevbezt->vec[1][1]); + vertex_position[1] = prevbezt->vec[1][1] - fac * (prevbezt->vec[2][1] - prevbezt->vec[1][1]); } - immVertex2fv(pos, v1); + immVertex2fv(pos, vertex_position); } immEnd(); -- 2.30.2 From a19b3b0ccf5b4b0142be832d0e5f316459f89031 Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 8 Jun 2023 12:33:44 +0200 Subject: [PATCH 2/3] passed wrong variable --- source/blender/editors/space_graph/graph_draw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 58253eac462..58151cc8d55 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -972,7 +972,7 @@ static void draw_fcurve_curve_bezts( else if (prevbezt->ipo == BEZT_IPO_BEZ) { int resolution = calculate_bezt_draw_resolution( bezt, prevbezt, max_bezt_resolution, fcu->driver != NULL); - draw_bezt(bezt, prevbezt, max_bezt_resolution, pos); + draw_bezt(bezt, prevbezt, resolution, pos); } /* Get next pointers. */ -- 2.30.2 From fc10c7b78008344fa75d51299de1089860cb7c7e Mon Sep 17 00:00:00 2001 From: Christoph Lendenfeld Date: Thu, 15 Jun 2023 18:11:07 +0200 Subject: [PATCH 3/3] make resolution const --- source/blender/editors/space_graph/graph_draw.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 8ecbfbc8364..76ada19a9ac 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -828,14 +828,11 @@ static int calculate_bezt_draw_resolution(BezTriple *bezt, return max_bez_resolution; } - int resolution = (int)(5.0f * len_v2v2(bezt->vec[1], prevbezt->vec[1])); + const int resolution = (int)(5.0f * len_v2v2(bezt->vec[1], prevbezt->vec[1])); /* NOTE: higher values will crash */ /* TODO: view scale should factor into this someday too... */ - if (resolution > max_bez_resolution) { - resolution = max_bez_resolution; - } - return resolution; + return min_ii(resolution, max_bez_resolution); } /** Draw a segment from \param prevbezt to \param bezt at the given \param resolution. -- 2.30.2