Animation: Improve drawing of locked FCurves #106052

Merged
Christoph Lendenfeld merged 12 commits from ChrisLend/blender:fcurve_locked_drawing into main 2023-07-07 15:05:58 +02:00
1 changed files with 104 additions and 64 deletions

View File

@ -155,7 +155,7 @@ static void set_fcurve_vertex_color(FCurve *fcu, bool sel)
}
else {
/* Curve's points CANNOT BE edited */
UI_GetThemeColor3fv(sel ? TH_TEXT_HI : TH_TEXT, color);
UI_GetThemeColor3fv(TH_VERTEX, color);
}
/* Fade the 'intensity' of the vertices based on the selection of the curves too
@ -169,8 +169,30 @@ static void set_fcurve_vertex_color(FCurve *fcu, bool sel)
immUniformColor4fv(color);
}
static void draw_fcurve_selected_keyframe_vertices(
FCurve *fcu, View2D *v2d, bool edit, bool sel, uint pos)
/* Draw a cross at the given position. Shader must already be bound.
* NOTE: the caller MUST HAVE GL_LINE_SMOOTH & GL_BLEND ENABLED, otherwise the controls don't
* have a consistent appearance (due to off-pixel alignments).
*/
static void draw_cross(float position[2], float scale[2], uint attr_id)
{
GPU_matrix_push();
GPU_matrix_translate_2fv(position);
GPU_matrix_scale_2f(1.0f / scale[0], 1.0f / scale[1]);
/* Draw X shape. */
const float line_length = 0.7f;
immBegin(GPU_PRIM_LINES, 4);
immVertex2f(attr_id, -line_length, -line_length);
immVertex2f(attr_id, +line_length, +line_length);
immVertex2f(attr_id, -line_length, +line_length);
immVertex2f(attr_id, +line_length, -line_length);
immEnd();
GPU_matrix_pop();
}
static void draw_fcurve_selected_keyframe_vertices(FCurve *fcu, View2D *v2d, bool sel, uint pos)
{
const float fac = 0.05f * BLI_rctf_size_x(&v2d->cur);
@ -185,18 +207,11 @@ static void draw_fcurve_selected_keyframe_vertices(
* don't pop in/out due to slight twitches of view size.
*/
if (IN_RANGE(bezt->vec[1][0], (v2d->cur.xmin - fac), (v2d->cur.xmax + fac))) {
if (edit) {
/* 'Keyframe' vertex only, as handle lines and handles have already been drawn
* - only draw those with correct selection state for the current drawing color
* -
*/
if ((bezt->f2 & SELECT) == sel) {
immVertex2fv(pos, bezt->vec[1]);
}
}
else {
/* no check for selection here, as curve is not editable... */
/* XXX perhaps we don't want to even draw points? maybe add an option for that later */
/* 'Keyframe' vertex only, as handle lines and handles have already been drawn
* - only draw those with correct selection state for the current drawing color
* -
*/
if ((bezt->f2 & SELECT) == sel) {
immVertex2fv(pos, bezt->vec[1]);
}
}
@ -205,6 +220,36 @@ static void draw_fcurve_selected_keyframe_vertices(
immEnd();
}
static void draw_locked_keyframe_vertices(FCurve *fcu,

const can be added for at least the attr_id. fcu could probably also be const, but that would have to ripple to other functions, which IMO is not worth it for this PR.

`const` can be added for at least the `attr_id`. `fcu` could probably also be `const`, but that would have to ripple to other functions, which IMO is not worth it for this PR.
View2D *v2d,
const uint attr_id,
const float unit_scale)
{
const float correction_factor = 0.05f * BLI_rctf_size_x(&v2d->cur);
/* get view settings */
const float vertex_size = UI_GetThemeValuef(TH_VERTEX_SIZE);
float scale[2];
UI_view2d_scale_get(v2d, &scale[0], &scale[1]);
scale[0] /= vertex_size;
/* Dividing by the unit scale is needed to display euler correctly (internally they are radians
* but displayed as degrees) and all curves when normalization is turned on. */
scale[1] = scale[1] / vertex_size * unit_scale;

This is the same as:

scale[1] = scale[1] / (vertex_size / unit_scale);

which is the same as:

scale[1] = scale[1] * unit_scale / vertex_size;

which would remove a division from the computations. And since multiplication is faster than division, give a minute performance gain.

I'll leave it up to you to decide on which one you want (slightly longer but faster code, vs. slightly shorter and likely just as fast because the compiler can optimize). I don't have any strong feelings here.

This is the same as: ``` scale[1] = scale[1] / (vertex_size / unit_scale); ``` which is the same as: ``` scale[1] = scale[1] * unit_scale / vertex_size; ``` which would remove a division from the computations. And since multiplication is faster than division, give a minute performance gain. I'll leave it up to you to decide on which one you want (slightly longer but faster code, vs. slightly shorter and likely just as fast because the compiler can optimize). I don't have any strong feelings here.
set_fcurve_vertex_color(fcu, false);
for (int i = 0; i < fcu->totvert; i++) {
BezTriple *bezt = &fcu->bezt[i];
if (!IN_RANGE(bezt->vec[1][0],
(v2d->cur.xmin - correction_factor),
(v2d->cur.xmax + correction_factor))) {
continue;
}
float position[2] = {bezt->vec[1][0], bezt->vec[1][1]};
draw_cross(position, scale, attr_id);
}
}
/**
* Draw the extra indicator for the active point.
*/
@ -232,17 +277,35 @@ static void draw_fcurve_active_vertex(const FCurve *fcu, const View2D *v2d, cons
}
/* helper func - draw keyframe vertices only for an F-Curve */
static void draw_fcurve_keyframe_vertices(FCurve *fcu, View2D *v2d, bool edit, uint pos)
static void draw_fcurve_keyframe_vertices(
FCurve *fcu, View2D *v2d, bool edit, const uint pos, const float unit_scale)
{
immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
if (edit) {
immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
immUniform1f("size", UI_GetThemeValuef(TH_VERTEX_SIZE) * UI_SCALE_FAC);
immUniform1f("size", UI_GetThemeValuef(TH_VERTEX_SIZE) * UI_SCALE_FAC);
draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, false, pos);
draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, true, pos);
draw_fcurve_active_vertex(fcu, v2d, pos);
draw_fcurve_selected_keyframe_vertices(fcu, v2d, false, pos);
draw_fcurve_selected_keyframe_vertices(fcu, v2d, true, pos);
draw_fcurve_active_vertex(fcu, v2d, pos);
immUnbindProgram();
immUnbindProgram();
}
else {
if (U.animation_flag & USER_ANIM_HIGH_QUALITY_DRAWING) {
GPU_line_smooth(true);
}
GPU_blend(GPU_BLEND_ALPHA);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
draw_locked_keyframe_vertices(fcu, v2d, pos, unit_scale);
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
if (U.animation_flag & USER_ANIM_HIGH_QUALITY_DRAWING) {
GPU_line_smooth(false);
}
}
}
/* helper func - draw handle vertices only for an F-Curve (if it is not protected) */
@ -345,10 +408,8 @@ static void draw_fcurve_handle_vertices(FCurve *fcu, View2D *v2d, bool sel_handl
immUnbindProgram();
}
static void draw_fcurve_vertices(ARegion *region,
FCurve *fcu,
bool do_handles,
bool sel_handle_only)
static void draw_fcurve_vertices(
ARegion *region, FCurve *fcu, bool do_handles, bool sel_handle_only, const float unit_scale)
{
View2D *v2d = &region->v2d;
@ -371,7 +432,7 @@ static void draw_fcurve_vertices(ARegion *region,
}
/* draw keyframes over the handles */
draw_fcurve_keyframe_vertices(fcu, v2d, !(fcu->flag & FCURVE_PROTECTED), pos);
draw_fcurve_keyframe_vertices(fcu, v2d, !(fcu->flag & FCURVE_PROTECTED), pos, unit_scale);
GPU_program_point_size(false);
GPU_blend(GPU_BLEND_NONE);
@ -494,40 +555,18 @@ static void draw_fcurve_handles(SpaceGraph *sipo, FCurve *fcu)
/* Samples ---------------- */
/* helper func - draw sample-range marker for an F-Curve as a cross
* NOTE: the caller MUST HAVE GL_LINE_SMOOTH & GL_BLEND ENABLED, otherwise, the controls don't
* have a consistent appearance (due to off-pixel alignments)...
*/
static void draw_fcurve_sample_control(
float x, float y, float xscale, float yscale, float hsize, uint pos)
{
/* adjust view transform before starting */
GPU_matrix_push();
GPU_matrix_translate_2f(x, y);
GPU_matrix_scale_2f(1.0f / xscale * hsize, 1.0f / yscale * hsize);
/* draw X shape */
immBegin(GPU_PRIM_LINES, 4);
immVertex2f(pos, -0.7f, -0.7f);
immVertex2f(pos, +0.7f, +0.7f);
immVertex2f(pos, -0.7f, +0.7f);
immVertex2f(pos, +0.7f, -0.7f);
immEnd();
/* restore view transform */
GPU_matrix_pop();
}
/* helper func - draw keyframe vertices only for an F-Curve */
static void draw_fcurve_samples(ARegion *region, FCurve *fcu)
static void draw_fcurve_samples(ARegion *region, FCurve *fcu, const float unit_scale)
{
FPoint *first, *last;
float hsize, xscale, yscale;
float scale[2];
/* get view settings */
hsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
UI_view2d_scale_get(&region->v2d, &xscale, &yscale);
const float hsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
UI_view2d_scale_get(&region->v2d, &scale[0], &scale[1]);
scale[0] /= hsize;
scale[1] /= hsize / unit_scale;
/* get verts */
first = fcu->fpt;
@ -546,8 +585,8 @@ static void draw_fcurve_samples(ARegion *region, FCurve *fcu)
immUniformThemeColor((fcu->flag & FCURVE_SELECTED) ? TH_TEXT_HI : TH_TEXT);
draw_fcurve_sample_control(first->vec[0], first->vec[1], xscale, yscale, hsize, pos);
draw_fcurve_sample_control(last->vec[0], last->vec[1], xscale, yscale, hsize, pos);
draw_cross(first->vec, scale, pos);
draw_cross(last->vec, scale, pos);
immUnbindProgram();
@ -1047,7 +1086,7 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
{
/* set color/drawing style for curve itself */
/* draw active F-Curve thicker than the rest to make it stand out */
if (fcu->flag & FCURVE_ACTIVE) {
if (fcu->flag & FCURVE_ACTIVE && !BKE_fcurve_is_protected(fcu)) {
GPU_line_width(2.5);
}
else {
@ -1072,8 +1111,8 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
immUniform2f(
"viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC);
immUniform1i("colors_len", 0); /* Simple dashes. */
immUniform1f("dash_width", 4.0f);
immUniform1f("udash_factor", 0.5f);
immUniform1f("dash_width", 16.0f * U.scale_factor);
immUniform1f("udash_factor", 0.35f * U.scale_factor);
}
else {
immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
@ -1156,7 +1195,7 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) {
short mapping_flag = ANIM_get_normalization_flags(ac);
float offset;
float unit_scale = ANIM_unit_mapping_get_factor(
const float unit_scale = ANIM_unit_mapping_get_factor(
ac->scene, ale->id, fcu, mapping_flag, &offset);
/* apply unit-scaling to all values via OpenGL */
@ -1176,11 +1215,12 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
draw_fcurve_handles(sipo, fcu);
}
draw_fcurve_vertices(region, fcu, do_handles, (sipo->flag & SIPO_SELVHANDLESONLY));
draw_fcurve_vertices(
region, fcu, do_handles, (sipo->flag & SIPO_SELVHANDLESONLY), unit_scale);
}
else {
/* samples: only draw two indicators at either end as indicators */
draw_fcurve_samples(region, fcu);
draw_fcurve_samples(region, fcu, unit_scale);
}
GPU_matrix_pop();