From 2b796ed03d8d256a1325e62d19c51702937df027 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 15 Aug 2014 15:29:08 +1000 Subject: ColorRamp HSV, HSL Blend Modes D297 by charlie with own edits --- source/blender/blenkernel/intern/texture.c | 256 +++++++++++++++------ .../editors/interface/interface_templates.c | 13 +- source/blender/makesdna/DNA_texture_types.h | 33 ++- source/blender/makesrna/intern/rna_color.c | 44 +++- 4 files changed, 265 insertions(+), 81 deletions(-) diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 77f62771360..62e55a70d3f 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -41,6 +41,7 @@ #include "BLI_math.h" #include "BLI_kdopbvh.h" #include "BLI_utildefines.h" +#include "BLI_math_color.h" #include "DNA_key_types.h" #include "DNA_object_types.h" @@ -237,7 +238,7 @@ void init_colorband(ColorBand *coba, bool rangetype) } coba->tot = 2; - + coba->color_mode = COLBAND_BLEND_RGB; } ColorBand *add_colorband(bool rangetype) @@ -252,106 +253,219 @@ ColorBand *add_colorband(bool rangetype) /* ------------------------------------------------------------------------- */ +static float colorband_hue_interp( + const int ipotype_hue, + const float mfac, const float fac, + float h1, float h2) +{ + float h_interp; + int mode = 0; + +#define HUE_INTERP(h_a, h_b) ((mfac * (h_a)) + (fac * (h_b))) +#define HUE_MOD(h) (((h) < 1.0f) ? (h) : (h) - 1.0f) + + h1 = HUE_MOD(h1); + h2 = HUE_MOD(h2); + + BLI_assert(h1 >= 0.0f && h1 < 1.0f); + BLI_assert(h2 >= 0.0f && h2 < 1.0f); + + switch (ipotype_hue) { + case COLBAND_HUE_NEAR: + { + if ((h1 < h2) && (h2 - h1) > +0.5f) mode = 1; + else if ((h1 > h2) && (h2 - h1) < -0.5f) mode = 2; + else mode = 0; + break; + } + case COLBAND_HUE_FAR: + { + if ((h1 < h2) && (h2 - h1) < +0.5f) mode = 1; + else if ((h1 > h2) && (h2 - h1) > -0.5f) mode = 2; + else mode = 0; + break; + } + case COLBAND_HUE_CW: + { + if (h1 > h2) mode = 2; + else mode = 0; + break; + } + case COLBAND_HUE_CCW: + { + if (h1 < h2) mode = 1; + else mode = 0; + break; + } + } + + switch (mode) { + case 0: + h_interp = HUE_INTERP(h1, h2); + break; + case 1: + h_interp = HUE_INTERP(h1 + 1.0f, h2); + h_interp = HUE_MOD(h_interp); + break; + case 2: + h_interp = HUE_INTERP(h1, h2 + 1.0f); + h_interp = HUE_MOD(h_interp); + break; + } + + BLI_assert(h_interp >= 0.0f && h_interp < 1.0f); + +#undef HUE_INTERP +#undef HUE_MOD + + return h_interp; +} + bool do_colorband(const ColorBand *coba, float in, float out[4]) { const CBData *cbd1, *cbd2, *cbd0, *cbd3; - float fac, mfac, t[4]; + float fac; + int ipotype; int a; if (coba == NULL || coba->tot == 0) return 0; cbd1 = coba->data; + + ipotype = (coba->color_mode == COLBAND_BLEND_RGB) ? coba->ipotype : COLBAND_INTERP_LINEAR; + if (coba->tot == 1) { out[0] = cbd1->r; out[1] = cbd1->g; out[2] = cbd1->b; out[3] = cbd1->a; } + else if ((in <= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) { + out[0] = cbd1->r; + out[1] = cbd1->g; + out[2] = cbd1->b; + out[3] = cbd1->a; + } else { - if (in <= cbd1->pos && coba->ipotype < 2) { + CBData left, right; + + /* we're looking for first pos > in */ + for (a = 0; a < coba->tot; a++, cbd1++) if (cbd1->pos > in) break; + + if (a == coba->tot) { + cbd2 = cbd1 - 1; + right = *cbd2; + right.pos = 1.0f; + cbd1 = &right; + } + else if (a == 0) { + left = *cbd1; + left.pos = 0.0f; + cbd2 = &left; + } + else { + cbd2 = cbd1 - 1; + } + + if ((in >= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) { out[0] = cbd1->r; out[1] = cbd1->g; out[2] = cbd1->b; out[3] = cbd1->a; } else { - CBData left, right; - - /* we're looking for first pos > in */ - for (a = 0; a < coba->tot; a++, cbd1++) if (cbd1->pos > in) break; - - if (a == coba->tot) { - cbd2 = cbd1 - 1; - right = *cbd2; - right.pos = 1.0f; - cbd1 = &right; - } - else if (a == 0) { - left = *cbd1; - left.pos = 0.0f; - cbd2 = &left; + + if (cbd2->pos != cbd1->pos) { + fac = (in - cbd1->pos) / (cbd2->pos - cbd1->pos); } else { - cbd2 = cbd1 - 1; + /* was setting to 0.0 in 2.56 & previous, but this + * is incorrect for the last element, see [#26732] */ + fac = (a != coba->tot) ? 0.0f : 1.0f; } - - if (in >= cbd1->pos && coba->ipotype < 2) { - out[0] = cbd1->r; - out[1] = cbd1->g; - out[2] = cbd1->b; - out[3] = cbd1->a; + + if (coba->ipotype == COLBAND_INTERP_CONSTANT) { + /* constant */ + out[0] = cbd2->r; + out[1] = cbd2->g; + out[2] = cbd2->b; + out[3] = cbd2->a; } - else { - - if (cbd2->pos != cbd1->pos) - fac = (in - cbd1->pos) / (cbd2->pos - cbd1->pos); + else if (ipotype >= COLBAND_INTERP_B_SPLINE) { + /* ipo from right to left: 3 2 1 0 */ + float t[4]; + + if (a >= coba->tot - 1) cbd0 = cbd1; + else cbd0 = cbd1 + 1; + if (a < 2) cbd3 = cbd2; + else cbd3 = cbd2 - 1; + + CLAMP(fac, 0.0f, 1.0f); + + if (ipotype == COLBAND_INTERP_CARDINAL) { + key_curve_position_weights(fac, t, KEY_CARDINAL); + } else { - /* was setting to 0.0 in 2.56 & previous, but this - * is incorrect for the last element, see [#26732] */ - fac = (a != coba->tot) ? 0.0f : 1.0f; + key_curve_position_weights(fac, t, KEY_BSPLINE); } - - if (coba->ipotype == 4) { - /* constant */ - out[0] = cbd2->r; - out[1] = cbd2->g; - out[2] = cbd2->b; - out[3] = cbd2->a; - return 1; + + out[0] = t[3] * cbd3->r + t[2] * cbd2->r + t[1] * cbd1->r + t[0] * cbd0->r; + out[1] = t[3] * cbd3->g + t[2] * cbd2->g + t[1] * cbd1->g + t[0] * cbd0->g; + out[2] = t[3] * cbd3->b + t[2] * cbd2->b + t[1] * cbd1->b + t[0] * cbd0->b; + out[3] = t[3] * cbd3->a + t[2] * cbd2->a + t[1] * cbd1->a + t[0] * cbd0->a; + CLAMP(out[0], 0.0f, 1.0f); + CLAMP(out[1], 0.0f, 1.0f); + CLAMP(out[2], 0.0f, 1.0f); + CLAMP(out[3], 0.0f, 1.0f); + } + else { + float mfac; + + if (ipotype == COLBAND_INTERP_EASE) { + mfac = fac * fac; + fac = 3.0f * mfac - 2.0f * mfac * fac; } - - if (coba->ipotype >= 2) { - /* ipo from right to left: 3 2 1 0 */ - - if (a >= coba->tot - 1) cbd0 = cbd1; - else cbd0 = cbd1 + 1; - if (a < 2) cbd3 = cbd2; - else cbd3 = cbd2 - 1; - - CLAMP(fac, 0.0f, 1.0f); - - if (coba->ipotype == 3) - key_curve_position_weights(fac, t, KEY_CARDINAL); - else - key_curve_position_weights(fac, t, KEY_BSPLINE); - - out[0] = t[3] * cbd3->r + t[2] * cbd2->r + t[1] * cbd1->r + t[0] * cbd0->r; - out[1] = t[3] * cbd3->g + t[2] * cbd2->g + t[1] * cbd1->g + t[0] * cbd0->g; - out[2] = t[3] * cbd3->b + t[2] * cbd2->b + t[1] * cbd1->b + t[0] * cbd0->b; - out[3] = t[3] * cbd3->a + t[2] * cbd2->a + t[1] * cbd1->a + t[0] * cbd0->a; - CLAMP(out[0], 0.0f, 1.0f); - CLAMP(out[1], 0.0f, 1.0f); - CLAMP(out[2], 0.0f, 1.0f); - CLAMP(out[3], 0.0f, 1.0f); + + mfac = 1.0f - fac; + + if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSV)) { + float col1[3], col2[3]; + + linearrgb_to_srgb_v3_v3(col1, &cbd1->r); + linearrgb_to_srgb_v3_v3(col2, &cbd2->r); + + rgb_to_hsv_v(col1, col1); + rgb_to_hsv_v(col2, col2); + + out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]); + out[1] = mfac * col1[1] + fac * col2[1]; + out[2] = mfac * col1[2] + fac * col2[2]; + out[3] = mfac * cbd1->a + fac * cbd2->a; + + hsv_to_rgb_v(out, out); + + srgb_to_linearrgb_v3_v3(out, out); + } + else if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSL)) { + float col1[3], col2[3]; + + linearrgb_to_srgb_v3_v3(col1, &cbd1->r); + linearrgb_to_srgb_v3_v3(col2, &cbd2->r); + + rgb_to_hsl_v(col1, col1); + rgb_to_hsl_v(col2, col2); + + out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]); + out[1] = mfac * col1[1] + fac * col2[1]; + out[2] = mfac * col1[2] + fac * col2[2]; + out[3] = mfac * cbd1->a + fac * cbd2->a; + + hsl_to_rgb_v(out, out); + + srgb_to_linearrgb_v3_v3(out, out); } else { - - if (coba->ipotype == 1) { /* EASE */ - mfac = fac * fac; - fac = 3.0f * mfac - 2.0f * mfac * fac; - } - mfac = 1.0f - fac; - + /* COLBAND_BLEND_RGB */ out[0] = mfac * cbd1->r + fac * cbd2->r; out[1] = mfac * cbd1->g + fac * cbd2->g; out[2] = mfac * cbd1->b + fac * cbd2->b; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index cb5f5331c2e..7f85a2314ca 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -37,6 +37,7 @@ #include "DNA_object_types.h" #include "DNA_object_force.h" #include "DNA_brush_types.h" +#include "DNA_texture_types.h" #include "BLI_utildefines.h" #include "BLI_string.h" @@ -1529,7 +1530,15 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand row = uiLayoutRow(split, false); - uiItemR(row, &ptr, "interpolation", 0, "", ICON_NONE); + uiBlockBeginAlign(block); + uiItemR(row, &ptr, "color_mode", 0, "", ICON_NONE); + if (ELEM(coba->color_mode, COLBAND_BLEND_HSV, COLBAND_BLEND_HSL)) { + uiItemR(row, &ptr, "hue_interpolation", 0, "", ICON_NONE); + } + else { /* COLBAND_BLEND_RGB */ + uiItemR(row, &ptr, "interpolation", 0, "", ICON_NONE); + } + uiBlockEndAlign(block); row = uiLayoutRow(layout, false); @@ -1567,7 +1576,7 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand uiDefButS(block, NUM, 0, "", 0, 0, 5.0f * UI_UNIT_X, UI_UNIT_Y, &coba->cur, 0.0, (float)(MAX2(0, coba->tot - 1)), 0, 0, TIP_("Choose active color stop")); row = uiLayoutRow(subsplit, false); - uiItemR(row, &ptr, "position", 0, IFACE_("Pos"), ICON_NONE); + uiItemR(row, &ptr, "position", UI_ITEM_R_SLIDER, IFACE_("Pos"), ICON_NONE); bt = block->buttons.last; uiButSetFunc(bt, colorband_update_cb, bt, coba); diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index dc891f8d971..059a12bae8b 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -111,9 +111,12 @@ typedef struct CBData { /* 32 = MAXCOLORBAND */ /* note that this has to remain a single struct, for UserDef */ typedef struct ColorBand { - short flag, tot, cur, ipotype; + short tot, cur; + char ipotype, ipotype_hue; + char color_mode; + char pad[1]; + CBData data[32]; - } ColorBand; typedef struct EnvMap { @@ -510,6 +513,32 @@ typedef struct ColorMapping { #define MTEX_MAP_MODE_RANDOM 4 #define MTEX_MAP_MODE_STENCIL 5 +/* **************** ColorBand ********************* */ + +/* colormode */ +enum { + COLBAND_BLEND_RGB = 0, + COLBAND_BLEND_HSV = 1, + COLBAND_BLEND_HSL = 2, +}; + +/* interpolation */ +enum { + COLBAND_INTERP_LINEAR = 0, + COLBAND_INTERP_EASE = 1, + COLBAND_INTERP_B_SPLINE = 2, + COLBAND_INTERP_CARDINAL = 3, + COLBAND_INTERP_CONSTANT = 4, +}; + +/* color interpolation */ +enum { + COLBAND_HUE_NEAR = 0, + COLBAND_HUE_FAR = 1, + COLBAND_HUE_CW = 2, + COLBAND_HUE_CCW = 3, +}; + /* **************** EnvMap ********************* */ /* type */ diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 569519bc876..fa2a3258d1a 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -850,7 +850,12 @@ static void rna_def_color_ramp_element(BlenderRNA *brna) RNA_def_property_array(prop, 4); RNA_def_property_ui_text(prop, "Color", "Set color of selected color stop"); RNA_def_property_update(prop, 0, "rna_ColorRamp_update"); - + + prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_COLOR); + RNA_def_property_float_sdna(prop, NULL, "a"); + RNA_def_property_ui_text(prop, "Alpha", "Set alpha of selected color stop"); + RNA_def_property_update(prop, 0, "rna_ColorRamp_update"); + prop = RNA_def_property(srna, "position", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "pos"); RNA_def_property_range(prop, 0, 1); @@ -895,14 +900,29 @@ static void rna_def_color_ramp(BlenderRNA *brna) FunctionRNA *func; static EnumPropertyItem prop_interpolation_items[] = { - {1, "EASE", 0, "Ease", ""}, - {3, "CARDINAL", 0, "Cardinal", ""}, - {0, "LINEAR", 0, "Linear", ""}, - {2, "B_SPLINE", 0, "B-Spline", ""}, - {4, "CONSTANT", 0, "Constant", ""}, + {COLBAND_INTERP_EASE, "EASE", 0, "Ease", ""}, + {COLBAND_INTERP_CARDINAL, "CARDINAL", 0, "Cardinal", ""}, + {COLBAND_INTERP_LINEAR, "LINEAR", 0, "Linear", ""}, + {COLBAND_INTERP_B_SPLINE, "B_SPLINE", 0, "B-Spline", ""}, + {COLBAND_INTERP_CONSTANT, "CONSTANT", 0, "Constant", ""}, {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_mode_items[] = { + {COLBAND_BLEND_RGB, "RGB", 0, "RGB", ""}, + {COLBAND_BLEND_HSV, "HSV", 0, "HSV", ""}, + {COLBAND_BLEND_HSL, "HSL", 0, "HSL", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem prop_hsv_items[] = { + {COLBAND_HUE_NEAR, "NEAR", 0, "Near", ""}, + {COLBAND_HUE_FAR, "FAR", 0, "Far", ""}, + {COLBAND_HUE_CW, "CW", 0, "Clockwise", ""}, + {COLBAND_HUE_CCW, "CCW", 0, "Counter-Clockwise", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "ColorRamp", NULL); RNA_def_struct_sdna(srna, "ColorBand"); RNA_def_struct_path_func(srna, "rna_ColorRamp_path"); @@ -921,6 +941,18 @@ static void rna_def_color_ramp(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Interpolation", "Set interpolation between color stops"); RNA_def_property_update(prop, 0, "rna_ColorRamp_update"); + prop = RNA_def_property(srna, "hue_interpolation", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "ipotype_hue"); + RNA_def_property_enum_items(prop, prop_hsv_items); + RNA_def_property_ui_text(prop, "Color Interpolation", "Set color interpolation"); + RNA_def_property_update(prop, 0, "rna_ColorRamp_update"); + + prop = RNA_def_property(srna, "color_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "color_mode"); + RNA_def_property_enum_items(prop, prop_mode_items); + RNA_def_property_ui_text(prop, "Color Mode", "Set color mode to use for interpolation"); + RNA_def_property_update(prop, 0, "rna_ColorRamp_update"); + #if 0 /* use len(elements) */ prop = RNA_def_property(srna, "total", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "tot"); -- cgit v1.2.3