From 8c74ebb64f883701aecd291e5543b0f27ded8764 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 1 Aug 2016 09:01:43 +1000 Subject: [PATCH] Support Auto-Clamped Handle for Curve-Mapping This patch supports auto-clamped handles for curves, useful since without this it can be difficult to have 'flat' sections of a curve. --- source/blender/blenkernel/BKE_colortools.h | 2 +- source/blender/blenkernel/intern/colortools.c | 85 ++++++++++++++++--- .../editors/interface/interface_templates.c | 11 ++- source/blender/makesdna/DNA_color_types.h | 3 +- source/blender/makesrna/intern/rna_color.c | 3 +- 5 files changed, 86 insertions(+), 18 deletions(-) diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h index e5d348031e9..5b4f5910821 100644 --- a/source/blender/blenkernel/BKE_colortools.h +++ b/source/blender/blenkernel/BKE_colortools.h @@ -61,7 +61,7 @@ void curvemap_reset(struct CurveMap *cuma, const struct rctf void curvemap_remove(struct CurveMap *cuma, const short flag); bool curvemap_remove_point(struct CurveMap *cuma, struct CurveMapPoint *cmp); struct CurveMapPoint *curvemap_insert(struct CurveMap *cuma, float x, float y); -void curvemap_sethandle(struct CurveMap *cuma, int type); +void curvemap_handle_set(struct CurveMap *cuma, int type); void curvemapping_changed(struct CurveMapping *cumap, const bool rem_doubles); void curvemapping_changed_all(struct CurveMapping *cumap); diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 53a74024c51..4f3ffed41bc 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -293,8 +293,8 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope) cuma->curve[1].x = clipr->xmax; cuma->curve[1].y = clipr->ymin; if (slope == CURVEMAP_SLOPE_POS_NEG) { - cuma->curve[0].flag |= CUMA_VECTOR; - cuma->curve[1].flag |= CUMA_VECTOR; + cuma->curve[0].flag |= CUMA_HANDLE_VECTOR; + cuma->curve[1].flag |= CUMA_HANDLE_VECTOR; } break; case CURVE_PRESET_SHARP: @@ -391,15 +391,25 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope) } } -/* if type==1: vector, else auto */ -void curvemap_sethandle(CurveMap *cuma, int type) +/** + * \param type: eBezTriple_Handle + */ +void curvemap_handle_set(CurveMap *cuma, int type) { int a; for (a = 0; a < cuma->totpoint; a++) { if (cuma->curve[a].flag & CUMA_SELECT) { - if (type) cuma->curve[a].flag |= CUMA_VECTOR; - else cuma->curve[a].flag &= ~CUMA_VECTOR; + cuma->curve[a].flag &= ~(CUMA_HANDLE_VECTOR | CUMA_HANDLE_AUTO_ANIM); + if (type == HD_VECT) { + cuma->curve[a].flag |= CUMA_HANDLE_VECTOR; + } + else if (type == HD_AUTO_ANIM) { + cuma->curve[a].flag |= CUMA_HANDLE_AUTO_ANIM; + } + else { + /* pass */ + } } } } @@ -457,7 +467,7 @@ static void calchandle_curvemap( if (len_a == 0.0f) len_a = 1.0f; if (len_b == 0.0f) len_b = 1.0f; - if (bezt->h1 == HD_AUTO || bezt->h2 == HD_AUTO) { /* auto */ + if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM) || ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { /* auto */ float tvec[2]; tvec[0] = dvec_b[0] / len_b + dvec_a[0] / len_a; tvec[1] = dvec_b[1] / len_b + dvec_a[1] / len_a; @@ -465,13 +475,57 @@ static void calchandle_curvemap( len = len_v2(tvec) * 2.5614f; if (len != 0.0f) { - if (bezt->h1 == HD_AUTO) { + if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM)) { len_a /= len; madd_v2_v2v2fl(p2_h1, p2, tvec, -len_a); + + if ((bezt->h1 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */ + const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1]; + const float ydiff2 = next->vec[1][1] - bezt->vec[1][1]; + if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f) || + (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) + { + bezt->vec[0][1] = bezt->vec[1][1]; + } + else { /* handles should not be beyond y coord of two others */ + if (ydiff1 <= 0.0f) { + if (prev->vec[1][1] > bezt->vec[0][1]) { + bezt->vec[0][1] = prev->vec[1][1]; + } + } + else { + if (prev->vec[1][1] < bezt->vec[0][1]) { + bezt->vec[0][1] = prev->vec[1][1]; + } + } + } + } } - if (bezt->h2 == HD_AUTO) { + if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM)) { len_b /= len; madd_v2_v2v2fl(p2_h2, p2, tvec, len_b); + + if ((bezt->h2 == HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */ + const float ydiff1 = prev->vec[1][1] - bezt->vec[1][1]; + const float ydiff2 = next->vec[1][1] - bezt->vec[1][1]; + if ((ydiff1 <= 0.0f && ydiff2 <= 0.0f)|| + (ydiff1 >= 0.0f && ydiff2 >= 0.0f)) + { + bezt->vec[2][1] = bezt->vec[1][1]; + } + else { /* handles should not be beyond y coord of two others */ + if (ydiff1 <= 0.0f) { + if (next->vec[1][1] < bezt->vec[2][1]) { + bezt->vec[2][1] = next->vec[1][1]; + } + } + else { + if (next->vec[1][1] > bezt->vec[2][1]) { + bezt->vec[2][1] = next->vec[1][1]; + } + } + } + } } } } @@ -540,10 +594,15 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr) cuma->maxtable = max_ff(cuma->maxtable, cmp[a].x); bezt[a].vec[1][0] = cmp[a].x; bezt[a].vec[1][1] = cmp[a].y; - if (cmp[a].flag & CUMA_VECTOR) + if (cmp[a].flag & CUMA_HANDLE_VECTOR) { bezt[a].h1 = bezt[a].h2 = HD_VECT; - else + } + else if (cmp[a].flag & CUMA_HANDLE_AUTO_ANIM) { + bezt[a].h1 = bezt[a].h2 = HD_AUTO_ANIM; + } + else { bezt[a].h1 = bezt[a].h2 = HD_AUTO; + } } const BezTriple *bezt_prev = NULL; @@ -773,12 +832,12 @@ void curvemapping_changed(CurveMapping *cumap, const bool rem_doubles) dy = cmp[a].y - cmp[a + 1].y; if (sqrtf(dx * dx + dy * dy) < thresh) { if (a == 0) { - cmp[a + 1].flag |= CUMA_VECTOR; + cmp[a + 1].flag |= CUMA_HANDLE_VECTOR; if (cmp[a + 1].flag & CUMA_SELECT) cmp[a].flag |= CUMA_SELECT; } else { - cmp[a].flag |= CUMA_VECTOR; + cmp[a].flag |= CUMA_HANDLE_VECTOR; if (cmp[a].flag & CUMA_SELECT) cmp[a + 1].flag |= CUMA_SELECT; } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index aec4065adaf..58cadf5587a 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1940,6 +1940,7 @@ enum { UICURVE_FUNC_RESET_VIEW, UICURVE_FUNC_HANDLE_VECTOR, UICURVE_FUNC_HANDLE_AUTO, + UICURVE_FUNC_HANDLE_AUTO_ANIM, UICURVE_FUNC_EXTEND_HOZ, UICURVE_FUNC_EXTEND_EXP, }; @@ -1960,13 +1961,16 @@ static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event) cumap->curr = cumap->clipr; break; case UICURVE_FUNC_HANDLE_VECTOR: /* set vector */ - curvemap_sethandle(cuma, 1); + curvemap_handle_set(cuma, HD_VECT); curvemapping_changed(cumap, false); break; case UICURVE_FUNC_HANDLE_AUTO: /* set auto */ - curvemap_sethandle(cuma, 0); + curvemap_handle_set(cuma, HD_AUTO); curvemapping_changed(cumap, false); break; + case UICURVE_FUNC_HANDLE_AUTO_ANIM: /* set auto-clamped */ + curvemap_handle_set(cuma, HD_AUTO_ANIM); + curvemapping_changed(cumap, false); case UICURVE_FUNC_EXTEND_HOZ: /* extend horiz */ cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE; curvemapping_changed(cumap, false); @@ -2000,6 +2004,9 @@ static uiBlock *curvemap_tools_func( uiDefIconTextBut( block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO, ""); + uiDefIconTextBut( + block, UI_BTYPE_BUT_MENU, 1, ICON_BLANK1, IFACE_("Auto Clamped Handle"), + 0, yco -= UI_UNIT_Y, menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO_ANIM, ""); } if (show_extend) { diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h index 1d88b01cf62..f7ee1ff3915 100644 --- a/source/blender/makesdna/DNA_color_types.h +++ b/source/blender/makesdna/DNA_color_types.h @@ -49,7 +49,8 @@ typedef struct CurveMapPoint { /* curvepoint->flag */ enum { CUMA_SELECT = 1, - CUMA_VECTOR = 2 + CUMA_HANDLE_VECTOR = 2, + CUMA_HANDLE_AUTO_ANIM = 4, }; typedef struct CurveMap { diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 78e3bbe4176..24f2d8174af 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -690,7 +690,8 @@ static void rna_def_curvemappoint(BlenderRNA *brna) PropertyRNA *prop; static EnumPropertyItem prop_handle_type_items[] = { {0, "AUTO", 0, "Auto Handle", ""}, - {CUMA_VECTOR, "VECTOR", 0, "Vector Handle", ""}, + {CUMA_HANDLE_AUTO_ANIM, "AUTO_CLAMPED", 0, "Auto Clamped Handle", ""}, + {CUMA_HANDLE_VECTOR, "VECTOR", 0, "Vector Handle", ""}, {0, NULL, 0, NULL, NULL} };