diff options
author | Antonio Vazquez <blendergit@gmail.com> | 2022-02-14 18:30:09 +0300 |
---|---|---|
committer | Antonio Vazquez <blendergit@gmail.com> | 2022-02-25 13:15:42 +0300 |
commit | 5fd792c1f6d348411469d5b9744c55106d317375 (patch) | |
tree | 2e3880290bb4f514fe15048722a76f319bc9cca0 /source/blender/editors | |
parent | 60af7a349614f9ebe88ebb71f4c8fad14a0e274f (diff) |
GPencil: Fill Dilate using negative values contract the fill area
This is requested by artist for some animation styles where is necessary to fill the area, but create a gap between fill and stroke.
Also some code cleanup and fix a bug in dilate for top area.
Reviewed By: pepeland, mendio
Differential Revision: https://developer.blender.org/D14082
Note: This was committed only in master (3.2) by error.
Diffstat (limited to 'source/blender/editors')
-rw-r--r-- | source/blender/editors/gpencil/gpencil_fill.c | 155 |
1 files changed, 128 insertions, 27 deletions
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 541b6673cb6..9b4f4470356 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1020,7 +1020,6 @@ static void gpencil_invert_image(tGPDfill *tgpf) ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock); const int maxpixel = (ibuf->x * ibuf->y) - 1; - const int center = ibuf->x / 2; for (int v = maxpixel; v != 0; v--) { float color[4]; @@ -1032,15 +1031,6 @@ static void gpencil_invert_image(tGPDfill *tgpf) /* Red->Green */ else if (color[0] == 1.0f) { set_pixel(ibuf, v, fill_col[1]); - /* Add thickness of 2 pixels to avoid too thin lines, but avoid extremes of the pixel line. - */ - int row = v / ibuf->x; - int lowpix = row * ibuf->x; - int highpix = lowpix + ibuf->x - 1; - if ((v > lowpix) && (v < highpix)) { - int offset = (v % ibuf->x < center) ? 1 : -1; - set_pixel(ibuf, v + offset, fill_col[1]); - } } else { /* Set to Transparent. */ @@ -1136,11 +1126,14 @@ static void gpencil_erase_processed_area(tGPDfill *tgpf) */ static bool dilate_shape(ImBuf *ibuf) { +#define IS_RED (color[0] == 1.0f) +#define IS_GREEN (color[1] == 1.0f) + bool done = false; BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__); const float green[4] = {0.0f, 1.0f, 0.0f, 1.0f}; - // const int maxpixel = (ibuf->x * ibuf->y) - 1; + const int max_size = (ibuf->x * ibuf->y) - 1; /* detect pixels and expand into red areas */ for (int row = 0; row < ibuf->y; row++) { if (!is_row_filled(ibuf, row)) { @@ -1153,7 +1146,7 @@ static bool dilate_shape(ImBuf *ibuf) float color[4]; int index; get_pixel(ibuf, v, color); - if (color[1] == 1.0f) { + if (IS_GREEN) { int tp = 0; int bm = 0; int lt = 0; @@ -1163,7 +1156,7 @@ static bool dilate_shape(ImBuf *ibuf) if (v - 1 >= 0) { index = v - 1; get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { + if (IS_RED) { BLI_stack_push(stack, &index); lt = index; } @@ -1172,25 +1165,25 @@ static bool dilate_shape(ImBuf *ibuf) if (v + 1 <= maxpixel) { index = v + 1; get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { + if (IS_RED) { BLI_stack_push(stack, &index); rt = index; } } /* pixel top */ - if (v + (ibuf->x * 1) <= maxpixel) { - index = v + (ibuf->x * 1); + if (v + ibuf->x <= max_size) { + index = v + ibuf->x; get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { + if (IS_RED) { BLI_stack_push(stack, &index); tp = index; } } /* pixel bottom */ - if (v - (ibuf->x * 1) >= 0) { - index = v - (ibuf->x * 1); + if (v - ibuf->x >= 0) { + index = v - ibuf->x; get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { + if (IS_RED) { BLI_stack_push(stack, &index); bm = index; } @@ -1199,7 +1192,7 @@ static bool dilate_shape(ImBuf *ibuf) if (tp && lt) { index = tp - 1; get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { + if (IS_RED) { BLI_stack_push(stack, &index); } } @@ -1207,7 +1200,7 @@ static bool dilate_shape(ImBuf *ibuf) if (tp && rt) { index = tp + 1; get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { + if (IS_RED) { BLI_stack_push(stack, &index); } } @@ -1215,7 +1208,7 @@ static bool dilate_shape(ImBuf *ibuf) if (bm && lt) { index = bm - 1; get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { + if (IS_RED) { BLI_stack_push(stack, &index); } } @@ -1223,7 +1216,7 @@ static bool dilate_shape(ImBuf *ibuf) if (bm && rt) { index = bm + 1; get_pixel(ibuf, index, color); - if (color[0] == 1.0f) { + if (IS_RED) { BLI_stack_push(stack, &index); } } @@ -1240,6 +1233,88 @@ static bool dilate_shape(ImBuf *ibuf) BLI_stack_free(stack); return done; + +#undef IS_RED +#undef IS_GREEN +} + +/** + * Contract + * + * Contract green areas to scale down the size. + * Using stack prevents creep when replacing colors directly. + */ +static bool contract_shape(ImBuf *ibuf) +{ +#define IS_GREEN (color[1] == 1.0f) +#define IS_NOT_GREEN (color[1] != 1.0f) + + bool done = false; + + BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__); + const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + const int max_size = (ibuf->x * ibuf->y) - 1; + + /* detect pixels and expand into red areas */ + for (int row = 0; row < ibuf->y; row++) { + if (!is_row_filled(ibuf, row)) { + continue; + } + int maxpixel = (ibuf->x * (row + 1)) - 1; + int minpixel = ibuf->x * row; + + for (int v = maxpixel; v != minpixel; v--) { + float color[4]; + get_pixel(ibuf, v, color); + if (IS_GREEN) { + /* pixel left */ + if (v - 1 >= 0) { + get_pixel(ibuf, v - 1, color); + if (IS_NOT_GREEN) { + BLI_stack_push(stack, &v); + continue; + } + } + /* pixel right */ + if (v + 1 <= maxpixel) { + get_pixel(ibuf, v + 1, color); + if (IS_NOT_GREEN) { + BLI_stack_push(stack, &v); + continue; + } + } + /* pixel top */ + if (v + ibuf->x <= max_size) { + get_pixel(ibuf, v + ibuf->x, color); + if (IS_NOT_GREEN) { + BLI_stack_push(stack, &v); + continue; + } + } + /* pixel bottom */ + if (v - ibuf->x >= 0) { + get_pixel(ibuf, v - ibuf->x, color); + if (IS_NOT_GREEN) { + BLI_stack_push(stack, &v); + continue; + } + } + } + } + } + /* Clear pixels. */ + while (!BLI_stack_is_empty(stack)) { + int v; + BLI_stack_pop(stack, &v); + set_pixel(ibuf, v, clear); + done = true; + } + BLI_stack_free(stack); + + return done; + +#undef IS_GREEN +#undef IS_NOT_GREEN } /* Get the outline points of a shape using Moore Neighborhood algorithm @@ -1281,10 +1356,15 @@ static void gpencil_get_outline_points(tGPDfill *tgpf, const bool dilate) ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock); int imagesize = ibuf->x * ibuf->y; - /* Dilate. */ + /* Dilate or contract. */ if (dilate) { - for (int i = 0; i < brush->gpencil_settings->dilate_pixels; i++) { - dilate_shape(ibuf); + for (int i = 0; i < abs(brush->gpencil_settings->dilate_pixels); i++) { + if (brush->gpencil_settings->dilate_pixels > 0) { + dilate_shape(ibuf); + } + else { + contract_shape(ibuf); + } } } @@ -1991,6 +2071,24 @@ static void gpencil_zoom_level_set(tGPDfill *tgpf) } } +static bool gpencil_find_and_mark_empty_areas(tGPDfill *tgpf) +{ + ImBuf *ibuf; + void *lock; + const float blue_col[4] = {0.0f, 0.0f, 1.0f, 1.0f}; + ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock); + const int maxpixel = (ibuf->x * ibuf->y) - 1; + float rgba[4]; + for (int i = 0; i < maxpixel; i++) { + get_pixel(ibuf, i, rgba); + if (rgba[3] == 0.0f) { + set_pixel(ibuf, i, blue_col); + return true; + } + } + return false; +} + static bool gpencil_do_frame_fill(tGPDfill *tgpf, const bool is_inverted) { wmWindow *win = CTX_wm_window(tgpf->C); @@ -2011,6 +2109,9 @@ static bool gpencil_do_frame_fill(tGPDfill *tgpf, const bool is_inverted) /* Invert direction if press Ctrl. */ if (is_inverted) { gpencil_invert_image(tgpf); + while (gpencil_find_and_mark_empty_areas(tgpf)) { + gpencil_boundaryfill_area(tgpf); + } } /* Clean borders to avoid infinite loops. */ |