Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Vazquez <blendergit@gmail.com>2022-02-14 18:30:09 +0300
committerAntonio Vazquez <blendergit@gmail.com>2022-02-25 13:15:42 +0300
commit5fd792c1f6d348411469d5b9744c55106d317375 (patch)
tree2e3880290bb4f514fe15048722a76f319bc9cca0 /source/blender/editors
parent60af7a349614f9ebe88ebb71f4c8fad14a0e274f (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.c155
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. */