From 1218b3fceb4b5591d641597797c07e46f58df1c0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 11 Dec 2017 19:28:40 +1100 Subject: [PATCH 1/7] Cleanup: whitespace --- make.bat | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/make.bat b/make.bat index febe15f2ced..d6319ee8308 100644 --- a/make.bat +++ b/make.bat @@ -76,22 +76,22 @@ if NOT "%1" == "" ( ) else if "%1" == "x64" ( set BUILD_ARCH=x64 ) else if "%1" == "2017" ( - set BUILD_VS_VER=15 - set BUILD_VS_YEAR=2017 - set BUILD_VS_LIBDIRPOST=vc14 + set BUILD_VS_VER=15 + set BUILD_VS_YEAR=2017 + set BUILD_VS_LIBDIRPOST=vc14 ) else if "%1" == "2015" ( - set BUILD_VS_VER=14 - set BUILD_VS_YEAR=2015 - set BUILD_VS_LIBDIRPOST=vc14 + set BUILD_VS_VER=14 + set BUILD_VS_YEAR=2015 + set BUILD_VS_LIBDIRPOST=vc14 ) else if "%1" == "2013" ( - set BUILD_VS_VER=12 - set BUILD_VS_YEAR=2013 - set BUILD_VS_LIBDIRPOST=vc12 + set BUILD_VS_VER=12 + set BUILD_VS_YEAR=2013 + set BUILD_VS_LIBDIRPOST=vc12 ) else if "%1" == "packagename" ( - set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DCPACK_OVERRIDE_PACKAGENAME="%2" - shift /1 + set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DCPACK_OVERRIDE_PACKAGENAME="%2" + shift /1 ) else if "%1" == "nobuild" ( - set NOBUILD=1 + set NOBUILD=1 ) else if "%1" == "showhash" ( for /f "delims=" %%i in ('git rev-parse HEAD') do echo Branch_hash=%%i cd release/datafiles/locale @@ -231,7 +231,7 @@ if NOT EXIST %BUILD_VS_LIBDIR% ( if /I "!GetLibs!"=="Y" ( echo. echo Downloading %BUILD_VS_SVNDIR% libraries, please wait. - echo. + echo. svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/%BUILD_VS_SVNDIR% %BUILD_VS_LIBDIR% ) ) @@ -255,18 +255,18 @@ if NOT EXIST %BUILD_DIR%\nul ( mkdir %BUILD_DIR% ) if "%MUST_CLEAN%"=="1" ( - echo Cleaning %BUILD_DIR% - msbuild ^ - %BUILD_DIR%\Blender.sln ^ - /target:clean ^ - /property:Configuration=%BUILD_TYPE% ^ - /verbosity:minimal ^ - /p:platform=%MSBUILD_PLATFORM% + echo Cleaning %BUILD_DIR% + msbuild ^ + %BUILD_DIR%\Blender.sln ^ + /target:clean ^ + /property:Configuration=%BUILD_TYPE% ^ + /verbosity:minimal ^ + /p:platform=%MSBUILD_PLATFORM% - if %ERRORLEVEL% NEQ 0 ( - echo Cleaned "%BUILD_DIR%" - ) - goto EOF + if %ERRORLEVEL% NEQ 0 ( + echo Cleaned "%BUILD_DIR%" + ) + goto EOF ) REM Only configure on first run or when called with nobuild if NOT EXIST %BUILD_DIR%\Blender.sln set MUST_CONFIGURE=1 @@ -284,8 +284,8 @@ if "%MUST_CONFIGURE%"=="1" ( goto EOF ) ) -if DEFINED MSVC_VC_DIR echo call "%MSVC_VC_DIR%\vcvarsall.bat" > %BUILD_DIR%\rebuild.cmd -if DEFINED MSVC_VS_DIR echo call "%MSVC_VS_DIR%\Common7\Tools\VsDevCmd.bat" > %BUILD_DIR%\rebuild.cmd +if DEFINED MSVC_VC_DIR echo call "%MSVC_VC_DIR%\vcvarsall.bat" > %BUILD_DIR%\rebuild.cmd +if DEFINED MSVC_VS_DIR echo call "%MSVC_VS_DIR%\Common7\Tools\VsDevCmd.bat" > %BUILD_DIR%\rebuild.cmd echo cmake . >> %BUILD_DIR%\rebuild.cmd echo msbuild ^ %BUILD_DIR%\Blender.sln ^ From 54f7bb45829565b47764d351b5e55d7ae3f2c420 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 12 Dec 2017 01:38:33 +1100 Subject: [PATCH 2/7] Fix for inset when accessed from spacebar search --- source/blender/editors/mesh/editmesh_inset.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index afe52ec69f4..6fd4203e085 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -373,10 +373,12 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event) case LEFTMOUSE: case PADENTER: case RETKEY: - edbm_inset_calc(op); - edbm_inset_exit(C, op); - return OPERATOR_FINISHED; - + if (event->val == KM_PRESS) { + edbm_inset_calc(op); + edbm_inset_exit(C, op); + return OPERATOR_FINISHED; + } + break; case LEFTSHIFTKEY: case RIGHTSHIFTKEY: if (event->val == KM_PRESS) { From 7719f7d27a9e1d7dc9d1040a6eb9e056ab3af8c1 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 11 Dec 2017 15:47:12 +0100 Subject: [PATCH 3/7] Fix T53528: Empty thumbnails in filebrowser Bug in recent refactor. --- source/blender/windowmanager/intern/wm_files.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 57f4219f23f..21e6abacfec 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -1029,7 +1029,7 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, BlendThumbnail **t ibuf = ED_view3d_draw_offscreen_imbuf_simple( scene, scene->camera, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, - IB_rect, OB_SOLID, V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL, + IB_rect, V3D_OFSDRAW_NONE, OB_SOLID, R_ALPHAPREMUL, 0, NULL, NULL, NULL, err_out); } else { From 43f33ea30052b525b5cee5cea2a9e6431597660c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 11 Dec 2017 17:38:47 +0100 Subject: [PATCH 4/7] Node selection: Stop operator when mouse selection selected a node Previously, hitting Shift-LMB will first invoke selection operator, which then later on is transformed to mouse tweak used for reroute operator. This was causing problems extending selection with Shift-LMB when clicking fast or from a tablet. --- source/blender/editors/space_node/node_select.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index dc7863bb354..c684b98ce55 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -476,9 +476,8 @@ static int node_select_exec(bContext *C, wmOperator *op) if (node_mouse_select(bmain, snode, ar, mval, extend)) { /* send notifiers */ WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); - - /* allow tweak event to work too */ - return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; + + return OPERATOR_FINISHED; } else { /* allow tweak event to work too */ From 7ae4c3a01923cccfa372072b880507c58557f45a Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Tue, 12 Dec 2017 10:19:55 +1100 Subject: [PATCH 5/7] Add eyedropper to color-ramp widget D2886 by @LazyDodo with edit's by @campbellbarton The line drawn with the eyedropper is used to fill the color-ramp. --- source/blender/blenkernel/BKE_colorband.h | 2 + source/blender/blenkernel/intern/colorband.c | 65 ++++ .../editors/interface/interface_eyedropper.c | 329 +++++++++++++++++- .../editors/interface/interface_intern.h | 3 + .../blender/editors/interface/interface_ops.c | 5 + .../editors/interface/interface_templates.c | 5 + 6 files changed, 406 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/BKE_colorband.h b/source/blender/blenkernel/BKE_colorband.h index aa64e793331..6841d94d360 100644 --- a/source/blender/blenkernel/BKE_colorband.h +++ b/source/blender/blenkernel/BKE_colorband.h @@ -36,6 +36,8 @@ struct ColorBand; #define MAXCOLORBAND 32 void BKE_colorband_init(struct ColorBand *coba, bool rangetype); +void BKE_colorband_init_from_table_rgba( + struct ColorBand *coba, const float (*array)[4], const int array_len); struct ColorBand *BKE_colorband_add(bool rangetype); bool BKE_colorband_evaluate(const struct ColorBand *coba, float in, float out[4]); void BKE_colorband_evaluate_table_rgba(const struct ColorBand *coba, float **array, int *size); diff --git a/source/blender/blenkernel/intern/colorband.c b/source/blender/blenkernel/intern/colorband.c index a9f4ae083d0..bd02676015e 100644 --- a/source/blender/blenkernel/intern/colorband.c +++ b/source/blender/blenkernel/intern/colorband.c @@ -80,6 +80,71 @@ void BKE_colorband_init(ColorBand *coba, bool rangetype) coba->color_mode = COLBAND_BLEND_RGB; } +static void colorband_init_from_table_rgba_simple( + ColorBand *coba, + const float (*array)[4], const int array_len) +{ + /* No Re-sample, just de-duplicate. */ + const float eps = (1.0f / 255.0f) + 1e-6f; + BLI_assert(array_len < MAXCOLORBAND); + int stops = min_ii(MAXCOLORBAND, array_len); + if (stops) { + const float step_size = 1.0f / (float)max_ii(stops - 1, 1); + int i_curr = -1; + for (int i_step = 0; i_step < stops; i_step++) { + if ((i_curr != -1) && compare_v4v4(&coba->data[i_curr].r, array[i_step], eps)) { + continue; + } + i_curr += 1; + copy_v4_v4(&coba->data[i_curr].r, array[i_step]); + coba->data[i_curr].pos = i_step * step_size; + coba->data[i_curr].cur = i_curr; + } + coba->tot = i_curr + 1; + coba->cur = 0; + } + else { + /* coba is empty, set 1 black stop */ + zero_v3(&coba->data[0].r); + coba->data[0].a = 1.0f; + coba->cur = 0; + coba->tot = 1; + } +} + +static void colorband_init_from_table_rgba_resample( + ColorBand *coba, + const float (*array)[4], const int array_len) +{ + /* TODO: more optimal method of color simplification, + * for now just pick evenly spaced colors. */ + BLI_assert(array_len >= MAXCOLORBAND); + float step = array_len / (float)MAXCOLORBAND; + float color_step = 1.0f / (MAXCOLORBAND - 1); + for (int i = 0; i < MAXCOLORBAND; i++) { + int cur_color = (int)(step * i); + copy_v4_v4(&coba->data[i].r, array[cur_color]); + coba->data[i].pos = i * color_step; + coba->data[i].cur = i; + } + coba->tot = MAXCOLORBAND; + coba->cur = 0; +} + +void BKE_colorband_init_from_table_rgba( + ColorBand *coba, + const float (*array)[4], const int array_len) +{ + if (array_len < MAXCOLORBAND) { + /* No Re-sample, just de-duplicate. */ + colorband_init_from_table_rgba_simple(coba, array, array_len); + } + else { + /* Re-sample */ + colorband_init_from_table_rgba_resample(coba, array, array_len); + } +} + ColorBand *BKE_colorband_add(bool rangetype) { ColorBand *coba; diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 564b29d3343..9cf40c07c0d 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -74,6 +74,9 @@ /* for Driver eyedropper */ #include "ED_keyframing.h" +/* for colorband eyedropper*/ +#include "BLI_bitmap_draw_2d.h" +#include "BKE_colorband.h" /* -------------------------------------------------------------------- */ /* Keymap @@ -88,6 +91,16 @@ enum { EYE_MODAL_SAMPLE_RESET, }; +/* Color-band point sample. */ +enum { + EYE_MODAL_POINT_CANCEL = 1, + EYE_MODAL_POINT_SAMPLE, + EYE_MODAL_POINT_CONFIRM, + EYE_MODAL_POINT_RESET, + EYE_MODAL_POINT_REMOVE_LAST, +}; + + wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) { static const EnumPropertyItem modal_items[] = { @@ -116,6 +129,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_RESET); /* assign to operators */ + WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id"); WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth"); @@ -124,6 +138,37 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf) return keymap; } +wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items_point[] = { + {EYE_MODAL_POINT_CANCEL, "CANCEL", 0, "Cancel", ""}, + {EYE_MODAL_POINT_SAMPLE, "SAMPLE_SAMPLE", 0, "Sample a point", ""}, + {EYE_MODAL_POINT_CONFIRM, "SAMPLE_CONFIRM", 0, "Confirm Sampling", ""}, + {EYE_MODAL_POINT_RESET, "SAMPLE_RESET", 0, "Reset Sampling", ""}, + {0, NULL, 0, NULL, NULL} + }; + + wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper ColorBand PointSampling Map"); + if (keymap && keymap->modal_items) + return keymap; + + keymap = WM_modalkeymap_add(keyconf, "Eyedropper ColorBand PointSampling Map", modal_items_point); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL); + WM_modalkeymap_add_item(keymap, BACKSPACEKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_REMOVE_LAST); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM); + WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM); + WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM); + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_SAMPLE); + WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_RESET); + + /* assign to operators */ + WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband_point"); + + return keymap; +} + /** \} */ @@ -260,7 +305,7 @@ static void eyedropper_exit(bContext *C, wmOperator *op) * * Special check for image or nodes where we MAY have HDR pixels which don't display. */ -static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int mx, int my, float r_col[3]) +static void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) { /* we could use some clever */ @@ -350,14 +395,14 @@ static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye) static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my) { float col[3]; - eyedropper_color_sample_fl(C, eye, mx, my, col); + eyedropper_color_sample_fl(C, mx, my, col); eyedropper_color_set(C, eye, col); } static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my) { float col[3]; - eyedropper_color_sample_fl(C, eye, mx, my, col); + eyedropper_color_sample_fl(C, mx, my, col); /* delay linear conversion */ add_v3_v3(eye->accum_col, col); eye->accum_tot++; @@ -490,6 +535,284 @@ void UI_OT_eyedropper_color(wmOperatorType *ot) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Eyedropper (RGB Color Band) + * + * Operates by either: + * - Dragging a straight line, sampling pixels formed by the line to extract a gradient. + * - Clicking on points, adding each color to the end of the color-band. + * \{ */ + +typedef struct Colorband_RNAUpdateCb { + PointerRNA ptr; + PropertyRNA *prop; +} Colorband_RNAUpdateCb; + +typedef struct EyedropperColorband { + int last_x, last_y; + /* Alpha is currently fixed at 1.0, may support in future. */ + float (*color_buffer)[4]; + int color_buffer_alloc; + int color_buffer_len; + bool sample_start; + ColorBand init_color_band; + ColorBand *color_band; + PointerRNA ptr; + PropertyRNA *prop; +} EyedropperColorband; + +/* For user-data only. */ +struct EyedropperColorband_Context { + bContext *context; + EyedropperColorband *eye; +}; + +static bool eyedropper_colorband_init(bContext *C, wmOperator *op) +{ + ColorBand *band = NULL; + EyedropperColorband *eye; + + uiBut *but = UI_context_active_but_get(C); + + if (but == NULL) { + /* pass */ + } + else if (but->type == UI_BTYPE_COLORBAND) { + /* When invoked with a hotkey, we can find the band in 'but->poin'. */ + band = (ColorBand *)but->poin; + } + else { + /* When invoked from a button it's in custom_data field. */ + band = (ColorBand *)but->custom_data; + } + + if (!band) + return false; + + op->customdata = eye = MEM_callocN(sizeof(EyedropperColorband), __func__); + eye->color_buffer_alloc = 16; + eye->color_buffer = MEM_mallocN(sizeof(*eye->color_buffer) * eye->color_buffer_alloc, __func__); + eye->color_buffer_len = 0; + eye->color_band = band; + eye->init_color_band = *eye->color_band; + eye->ptr = ((Colorband_RNAUpdateCb *)but->func_argN)->ptr; + eye->prop = ((Colorband_RNAUpdateCb *)but->func_argN)->prop; + + return true; +} + +static void eyedropper_colorband_sample_point(bContext *C, EyedropperColorband *eye, int mx, int my) +{ + if (eye->last_x != mx || eye->last_y != my) { + float col[4]; + col[3] = 1.0f; /* TODO: sample alpha */ + eyedropper_color_sample_fl(C, mx, my, col); + if (eye->color_buffer_len + 1 == eye->color_buffer_alloc) { + eye->color_buffer_alloc *= 2; + eye->color_buffer = MEM_reallocN(eye->color_buffer, sizeof(*eye->color_buffer) * eye->color_buffer_alloc); + } + copy_v4_v4(eye->color_buffer[eye->color_buffer_len], col); + eye->color_buffer_len += 1; + eye->last_x = mx; + eye->last_y = my; + } +} + +static bool eyedropper_colorband_sample_callback(int mx, int my, void *userdata) +{ + struct EyedropperColorband_Context *data = userdata; + bContext *C = data->context; + EyedropperColorband *eye = data->eye; + eyedropper_colorband_sample_point(C, eye, mx, my); + return true; +} + +static void eyedropper_colorband_sample_segment(bContext *C, EyedropperColorband *eye, int mx, int my) +{ + /* Since the mouse tends to move rather rapidly we use #BLI_bitmap_draw_2d_line_v2v2i + * to interpolate between the reported coordinates */ + struct EyedropperColorband_Context userdata = {C, eye}; + int p1[2] = {eye->last_x, eye->last_y}; + int p2[2] = {mx, my}; + BLI_bitmap_draw_2d_line_v2v2i(p1, p2, eyedropper_colorband_sample_callback, &userdata); +} + +static void eyedropper_colorband_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + if (op->customdata) { + EyedropperColorband *eye = op->customdata; + MEM_freeN(eye->color_buffer); + MEM_freeN(eye); + op->customdata = NULL; + } +} + +static void eyedropper_colorband_apply(bContext *C, wmOperator *op) +{ + EyedropperColorband *eye = op->customdata; + BKE_colorband_init_from_table_rgba(eye->color_band, eye->color_buffer, eye->color_buffer_len); + RNA_property_update(C, &eye->ptr, eye->prop); +} + +static void eyedropper_colorband_cancel(bContext *C, wmOperator *op) +{ + EyedropperColorband *eye = op->customdata; + *eye->color_band = eye->init_color_band; + RNA_property_update(C, &eye->ptr, eye->prop); + eyedropper_colorband_exit(C, op); +} + +/* main modal status check */ +static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + EyedropperColorband *eye = op->customdata; + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_CANCEL: + eyedropper_colorband_cancel(C, op); + return OPERATOR_CANCELLED; + case EYE_MODAL_SAMPLE_CONFIRM: + eyedropper_colorband_sample_segment(C, eye, event->x, event->y); + eyedropper_colorband_apply(C, op); + eyedropper_colorband_exit(C, op); + return OPERATOR_FINISHED; + case EYE_MODAL_SAMPLE_BEGIN: + /* enable accum and make first sample */ + eye->sample_start = true; + eyedropper_colorband_sample_point(C, eye, event->x, event->y); + eyedropper_colorband_apply(C, op); + eye->last_x = event->x; + eye->last_y = event->y; + break; + case EYE_MODAL_SAMPLE_RESET: + break; + } + } + else if (event->type == MOUSEMOVE) { + if (eye->sample_start) { + eyedropper_colorband_sample_segment(C, eye, event->x, event->y); + eyedropper_colorband_apply(C, op); + } + } + return OPERATOR_RUNNING_MODAL; +} + +static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + EyedropperColorband *eye = op->customdata; + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_POINT_CANCEL: + eyedropper_colorband_cancel(C, op); + return OPERATOR_CANCELLED; + case EYE_MODAL_POINT_CONFIRM: + eyedropper_colorband_apply(C, op); + eyedropper_colorband_exit(C, op); + return OPERATOR_FINISHED; + case EYE_MODAL_POINT_REMOVE_LAST: + if (eye->color_buffer_len > 0) { + eye->color_buffer_len -= 1; + eyedropper_colorband_apply(C, op); + } + break; + case EYE_MODAL_POINT_SAMPLE: + eyedropper_colorband_sample_point(C, eye, event->x, event->y); + eyedropper_colorband_apply(C, op); + if (eye->color_buffer_len == MAXCOLORBAND ) { + eyedropper_colorband_exit(C, op); + return OPERATOR_FINISHED; + } + break; + case EYE_MODAL_SAMPLE_RESET: + *eye->color_band = eye->init_color_band; + RNA_property_update(C, &eye->ptr, eye->prop); + eye->color_buffer_len = 0; + break; + } + } + return OPERATOR_RUNNING_MODAL; +} + + +/* Modal Operator init */ +static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (eyedropper_colorband_init(C, op)) { + WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + else { + eyedropper_colorband_exit(C, op); + return OPERATOR_CANCELLED; + } +} + +/* Repeat operator */ +static int eyedropper_colorband_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (eyedropper_colorband_init(C, op)) { + + /* do something */ + + /* cleanup */ + eyedropper_colorband_exit(C, op); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void UI_OT_eyedropper_colorband(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper colorband"; + ot->idname = "UI_OT_eyedropper_colorband"; + ot->description = "Sample a color band"; + + /* api callbacks */ + ot->invoke = eyedropper_colorband_invoke; + ot->modal = eyedropper_colorband_modal; + ot->cancel = eyedropper_colorband_cancel; + ot->exec = eyedropper_colorband_exec; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ +} + +void UI_OT_eyedropper_colorband_point(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper colorband (points)"; + ot->idname = "UI_OT_eyedropper_colorband_point"; + ot->description = "Pointsample a color band"; + + /* api callbacks */ + ot->invoke = eyedropper_colorband_invoke; + ot->modal = eyedropper_colorband_point_modal; + ot->cancel = eyedropper_colorband_cancel; + ot->exec = eyedropper_colorband_exec; + + /* flags */ + ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ +} + +/** \} */ /* -------------------------------------------------------------------- */ /* Data Dropper */ diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 638ab01f8ba..6a1a8b5c629 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -753,7 +753,10 @@ void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, fl /* interface_eyedropper.c */ struct wmKeyMap *eyedropper_modal_keymap(struct wmKeyConfig *keyconf); +struct wmKeyMap *eyedropper_colorband_modal_keymap(struct wmKeyConfig *keyconf); void UI_OT_eyedropper_color(struct wmOperatorType *ot); +void UI_OT_eyedropper_colorband(struct wmOperatorType *ot); +void UI_OT_eyedropper_colorband_point(struct wmOperatorType *ot); void UI_OT_eyedropper_id(struct wmOperatorType *ot); void UI_OT_eyedropper_depth(struct wmOperatorType *ot); void UI_OT_eyedropper_driver(struct wmOperatorType *ot); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 47b7e9aa085..9c72942a575 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1128,6 +1128,8 @@ void ED_operatortypes_ui(void) /* external */ WM_operatortype_append(UI_OT_eyedropper_color); + WM_operatortype_append(UI_OT_eyedropper_colorband); + WM_operatortype_append(UI_OT_eyedropper_colorband_point); WM_operatortype_append(UI_OT_eyedropper_id); WM_operatortype_append(UI_OT_eyedropper_depth); WM_operatortype_append(UI_OT_eyedropper_driver); @@ -1144,6 +1146,8 @@ void ED_keymap_ui(wmKeyConfig *keyconf) /* eyedroppers - notice they all have the same shortcut, but pass the event * through until a suitable eyedropper for the active button is found */ WM_keymap_add_item(keymap, "UI_OT_eyedropper_color", EKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband", EKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband_point", EKEY, KM_PRESS , KM_ALT, 0); WM_keymap_add_item(keymap, "UI_OT_eyedropper_id", EKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "UI_OT_eyedropper_depth", EKEY, KM_PRESS, 0, 0); @@ -1166,4 +1170,5 @@ void ED_keymap_ui(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "ANIM_OT_keyingset_button_remove", KKEY, KM_PRESS, KM_ALT, 0); eyedropper_modal_keymap(keyconf); + eyedropper_colorband_modal_keymap(keyconf); } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 1aadeb26103..e113098a769 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1532,6 +1532,11 @@ static void colorband_buttons_layout( bt = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_ARROW_LEFTRIGHT, "", xs + 4.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Flip the color ramp")); UI_but_funcN_set(bt, colorband_flip_cb, MEM_dupallocN(cb), coba); + + bt = uiDefIconButO(block, UI_BTYPE_BUT, "UI_OT_eyedropper_colorband", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, xs + 6.0f * unit, ys + UI_UNIT_Y, UI_UNIT_X, UI_UNIT_Y, NULL); + bt->custom_data = coba; + bt->func_argN = MEM_dupallocN(cb); + UI_block_align_end(block); UI_block_emboss_set(block, UI_EMBOSS); From f7a1a1a700d76a253afdbcb04decb0099be34cc8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 12 Dec 2017 13:14:23 +1100 Subject: [PATCH 6/7] UI: rewrite color-ramp re-sampling Instead of picking evenly spaced pixels color-ramp simplification now works by removing elements with the lowest cost. --- source/blender/blenkernel/intern/colorband.c | 114 +++++++++++++++++-- 1 file changed, 105 insertions(+), 9 deletions(-) diff --git a/source/blender/blenkernel/intern/colorband.c b/source/blender/blenkernel/intern/colorband.c index bd02676015e..e6f3ce575ce 100644 --- a/source/blender/blenkernel/intern/colorband.c +++ b/source/blender/blenkernel/intern/colorband.c @@ -30,6 +30,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_math_color.h" +#include "BLI_heap.h" #include "DNA_key_types.h" #include "DNA_texture_types.h" @@ -112,23 +113,118 @@ static void colorband_init_from_table_rgba_simple( } } +struct ColorResampleElem { + struct ColorResampleElem *next, *prev; + HeapNode *node; + float rgba[4]; + float pos; +}; + +static float color_sample_remove_cost(const struct ColorResampleElem *c) +{ + if (c->next == NULL || c->prev == NULL) { + return -1.0f; + } + float area = 0.0f; +#if 0 + float xy_prev[2], xy_curr[2], xy_next[2]; + xy_prev[0] = c->prev->pos; + xy_curr[0] = c->pos; + xy_next[0] = c->next->pos; + for (int i = 0; i < 4; i++) { + xy_prev[1] = c->prev->rgba[i]; + xy_curr[1] = c->rgba[i]; + xy_next[1] = c->next->rgba[i]; + area += fabsf(cross_tri_v2(xy_prev, xy_curr, xy_next)); + } +#else + /* Above logic, optimized (p: previous, c: current, n: next). */ + const float xpc = c->prev->pos - c->pos; + const float xnc = c->next->pos - c->pos; + for (int i = 0; i < 4; i++) { + const float ycn = c->rgba[i] - c->next->rgba[i]; + const float ypc = c->prev->rgba[i] - c->rgba[i]; + area += fabsf((xpc * ycn) + (ypc * xnc)); + } +#endif + return area; +} + static void colorband_init_from_table_rgba_resample( ColorBand *coba, const float (*array)[4], const int array_len) { - /* TODO: more optimal method of color simplification, - * for now just pick evenly spaced colors. */ BLI_assert(array_len >= MAXCOLORBAND); - float step = array_len / (float)MAXCOLORBAND; - float color_step = 1.0f / (MAXCOLORBAND - 1); - for (int i = 0; i < MAXCOLORBAND; i++) { - int cur_color = (int)(step * i); - copy_v4_v4(&coba->data[i].r, array[cur_color]); - coba->data[i].pos = i * color_step; + /* Use 2x to avoid noise having too much impact, since this is RGBA accumulated. */ + const float eps_2x = ((1.0f / 255.0f) + 1e-6f) * 2.0f; + struct ColorResampleElem *c, *carr = MEM_mallocN(sizeof(*carr) * array_len, __func__); + float color_fac = 1.0f / (float)(array_len - 1); + int carr_len = array_len; + c = carr; + for (int i = 0; i < array_len; i++, c++) { + copy_v4_v4(carr[i].rgba, array[i]); + c->next = c + 1; + c->prev = c - 1; + c->pos = i * color_fac; + } + carr[0].prev = NULL; + carr[array_len - 1].next = NULL; + + /* -2 to remove endpoints. */ + Heap *heap = BLI_heap_new_ex(array_len - 2); + c = carr; + for (int i = 0; i < array_len; i++, c++) { + float cost = color_sample_remove_cost(c); + if (cost != -1.0f) { + c->node = BLI_heap_insert(heap, cost, c); + } + else { + c->node = NULL; + } + } + + while ((carr_len > 1 && !BLI_heap_is_empty(heap)) && + ((carr_len >= MAXCOLORBAND) || (BLI_heap_node_value(BLI_heap_top(heap)) <= eps_2x))) + { + c = BLI_heap_popmin(heap); + struct ColorResampleElem *c_next = c->next, *c_prev = c->prev; + c_prev->next = c_next; + c_next->prev = c_prev; + /* Clear data (not essential, avoid confusion). */ + c->prev = c->next = NULL; + c->node = NULL; + + /* Update adjacent */ + for (int i = 0; i < 2; i++) { + struct ColorResampleElem *c_other = i ? c_next : c_prev; + if (c_other->node != NULL) { + const float cost = color_sample_remove_cost(c_other); + if (cost != -1.0) { + BLI_heap_node_value_update(heap, c_other->node, cost); + } + else { + BLI_heap_remove(heap, c_other->node); + c_other->node = NULL; + } + } + } + carr_len -= 1; + } + BLI_heap_free(heap, NULL); + + BLI_assert(carr_len < MAXCOLORBAND); + int i = 0; + /* fist member is never removed. */ + for (c = carr; c != NULL; c = c->next, i++) { + copy_v4_v4(&coba->data[i].r, c->rgba); + coba->data[i].pos = c->pos; coba->data[i].cur = i; } - coba->tot = MAXCOLORBAND; + BLI_assert(i == carr_len); + coba->tot = i; coba->cur = 0; + + MEM_freeN(carr); } void BKE_colorband_init_from_table_rgba( From 58aa31a9ec0fc5b7dbef02b4308a826b49abf3d8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 12 Dec 2017 13:37:21 +1100 Subject: [PATCH 7/7] Cleanup: minor edits to last commit --- source/blender/blenkernel/intern/colorband.c | 21 +++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/colorband.c b/source/blender/blenkernel/intern/colorband.c index e6f3ce575ce..0655c51f26c 100644 --- a/source/blender/blenkernel/intern/colorband.c +++ b/source/blender/blenkernel/intern/colorband.c @@ -113,6 +113,16 @@ static void colorband_init_from_table_rgba_simple( } } + +/* -------------------------------------------------------------------- */ +/** \name Color Ramp Re-Sample + * + * Local functions for #BKE_colorband_init_from_table_rgba + * \{ */ + +/** + * Used for calculating which samples of a color-band to remove (when simplifying). + */ struct ColorResampleElem { struct ColorResampleElem *next, *prev; HeapNode *node; @@ -120,6 +130,9 @@ struct ColorResampleElem { float pos; }; +/** + * Measure the 'area' of each channel and combine to use as a cost for this samples removal. + */ static float color_sample_remove_cost(const struct ColorResampleElem *c) { if (c->next == NULL || c->prev == NULL) { @@ -158,14 +171,14 @@ static void colorband_init_from_table_rgba_resample( /* Use 2x to avoid noise having too much impact, since this is RGBA accumulated. */ const float eps_2x = ((1.0f / 255.0f) + 1e-6f) * 2.0f; struct ColorResampleElem *c, *carr = MEM_mallocN(sizeof(*carr) * array_len, __func__); - float color_fac = 1.0f / (float)(array_len - 1); int carr_len = array_len; c = carr; + const float step_size = 1.0f / (float)(array_len - 1); for (int i = 0; i < array_len; i++, c++) { copy_v4_v4(carr[i].rgba, array[i]); c->next = c + 1; c->prev = c - 1; - c->pos = i * color_fac; + c->pos = i * step_size; } carr[0].prev = NULL; carr[array_len - 1].next = NULL; @@ -214,7 +227,7 @@ static void colorband_init_from_table_rgba_resample( BLI_assert(carr_len < MAXCOLORBAND); int i = 0; - /* fist member is never removed. */ + /* First member is never removed. */ for (c = carr; c != NULL; c = c->next, i++) { copy_v4_v4(&coba->data[i].r, c->rgba); coba->data[i].pos = c->pos; @@ -241,6 +254,8 @@ void BKE_colorband_init_from_table_rgba( } } +/** \} */ + ColorBand *BKE_colorband_add(bool rangetype) { ColorBand *coba;