diff --git a/docs/CHANGES.txt b/docs/CHANGES.txt index 26b0bf050..7c2b28ab6 100644 --- a/docs/CHANGES.txt +++ b/docs/CHANGES.txt @@ -8,7 +8,7 @@ http://www.tuxpaint.org/ $Id$ -2021.February.21 (0.9.26) +2021.February.20 (0.9.26) * New Features ------------ * Larger UI buttons @@ -20,10 +20,10 @@ $Id$ Pere Pujal i Carabantes * Adding sub-tools to the Fill tool: - + Solid -- the classic fill tool, click to fill - + [WIP] Linear -- A linear gradient, click and drag to adjust, + + Solid -- The classic fill tool; click to fill + + Linear -- A linear gradient; click and drag to adjust, release mouse to finish - + Radial -- A radial gradient, click to fill + + Radial -- A radial gradient; click to fill (The gradients transition from the current color to the background that's being filled.) diff --git a/src/fill.c b/src/fill.c index 6164fec16..5886bb90c 100644 --- a/src/fill.c +++ b/src/fill.c @@ -188,16 +188,54 @@ void simulate_flood_fill(SDL_Surface * canvas, int x, int y, Uint32 cur_colr, Ui } -void draw_linear_gradient(SDL_Surface * canvas, int x_left, int y_top, int x_right, int y_bottom, +void draw_linear_gradient(SDL_Surface * canvas, SDL_Surface * last, + int x_left, int y_top, int x_right, int y_bottom, int x1, int y1, int x2, int y2, Uint32 draw_color, Uint8 * touched ) { + Uint32 old_colr, new_colr; int xx, yy; + float xd, yd; + Uint8 draw_r, draw_g, draw_b, old_r, old_g, old_b, new_r, new_g, new_b; + float A, B, C, C1, C2, ratio; + + /* Get our target color */ + SDL_GetRGB(draw_color, canvas->format, &draw_r, &draw_g, &draw_b); + + A = (x2 - x1); + B = (y2 - y1); + C1 = (A * x1) + (B * y1); + C2 = (A * x2) + (B * y2); + /* FIXME: C2 should be larger than C1? */ for (yy = y_top; yy <= y_bottom; yy++) { for (xx = x_left; xx <= x_right; xx++) { if (touched[(yy * canvas->w) + xx]) { - /* FIXME */ - putpixels[canvas->format->BytesPerPixel] (canvas, xx, yy, draw_color); + /* Get the old color, and blend it (with a distance-based ratio) with the target color */ + old_colr = getpixels[last->format->BytesPerPixel] (last, xx, yy); + SDL_GetRGB(old_colr, last->format, &old_r, &old_g, &old_b); + + /* (h/t David Z on StackOverflow for how to quickly compute this: + https://stackoverflow.com/questions/521493/creating-a-linear-gradient-in-2d-array) */ + C = (A * xx) + (B * yy); + + if (C < C1) { + /* At/beyond the click spot (opposite direction of mouse); solid color */ + putpixels[canvas->format->BytesPerPixel] (canvas, xx, yy, draw_color); + } else if (C >= C2) { + /* At/beyond the mouse; completely faded out */ + putpixels[canvas->format->BytesPerPixel] (canvas, xx, yy, old_colr); + } else { + /* The actual gradient... */ + + ratio = (C - C1) / (C2 - C1); + + new_r = (Uint8) (((float) old_r) * ratio + ((float) draw_r * (1.00 - ratio))); + new_g = (Uint8) (((float) old_g) * ratio + ((float) draw_g * (1.00 - ratio))); + new_b = (Uint8) (((float) old_b) * ratio + ((float) draw_b * (1.00 - ratio))); + + new_colr = SDL_MapRGB(canvas->format, new_r, new_g, new_b); + putpixels[canvas->format->BytesPerPixel] (canvas, xx, yy, new_colr); + } } } } diff --git a/src/fill.h b/src/fill.h index a039fb831..100c54702 100644 --- a/src/fill.h +++ b/src/fill.h @@ -39,7 +39,8 @@ int would_flood_fill(SDL_Surface * canvas, Uint32 cur_colr, Uint32 old_colr); void do_flood_fill(SDL_Surface * canvas, int x, int y, Uint32 cur_colr, Uint32 old_colr, int * x1, int * y1, int * x2, int * y2); void simulate_flood_fill(SDL_Surface * canvas, int x, int y, Uint32 cur_colr, Uint32 old_colr, int * x1, int * y1, int * x2, int * y2, Uint8 * touched); -void draw_linear_gradient(SDL_Surface * canvas, int x_left, int y_top, int x_right, int y_bottom, +void draw_linear_gradient(SDL_Surface * canvas, SDL_Surface * last, + int x_left, int y_top, int x_right, int y_bottom, int x1, int y1, int x2, int y2, Uint32 draw_color, Uint8 * touched); void draw_radial_gradient(SDL_Surface * canvas, int x_left, int y_top, int x_right, int y_bottom, int x, int y, Uint32 draw_color, Uint8 * touched); diff --git a/src/tuxpaint.c b/src/tuxpaint.c index f9804cc9d..ae692a406 100644 --- a/src/tuxpaint.c +++ b/src/tuxpaint.c @@ -1255,6 +1255,7 @@ static Uint8 canvas_color_r, canvas_color_g, canvas_color_b; static Uint8 *touched; static Uint8 *sim_flood_touched; int sim_flood_x1 = 0, sim_flood_y1 = 0, sim_flood_x2 = 0, sim_flood_y2 = 0; +int fill_x, fill_y; static int last_print_time = 0; static int shape_radius; @@ -4535,6 +4536,9 @@ static void mainloop(void) color_hexes[cur_color][1], color_hexes[cur_color][2]); canv_color = getpixels[canvas->format->BytesPerPixel] (canvas, old_x, old_y); + + fill_x = old_x; + fill_y = old_y; if (would_flood_fill(canvas, draw_color, canv_color)) { @@ -4583,13 +4587,12 @@ static void mainloop(void) draw_radial_gradient(canvas, sim_flood_x1, sim_flood_y1, sim_flood_x2, sim_flood_y2, old_x, old_y, draw_color, sim_flood_touched); } -// else if (cur_fill == FILL_GRADIENT_LINEAR) -// { -// /* Start a linear gradient */ -// -// draw_linear_gradient(canvas, sim_flood_x1, sim_flood_y1, sim_flood_x2, sim_flood_y2, -// old_x, old_y, old_x, old_y + 1, draw_color, sim_flood_touched); -// } + else if (cur_fill == FILL_GRADIENT_LINEAR) + { + /* Start a linear gradient */ + draw_linear_gradient(canvas, canvas, sim_flood_x1, sim_flood_y1, sim_flood_x2, sim_flood_y2, + fill_x, fill_y, old_x, old_y + 1, draw_color, sim_flood_touched); + } update_canvas(x1, y1, x2, y2); } @@ -5427,7 +5430,6 @@ static void mainloop(void) do_setcursor(cursor_wand); else if (cur_tool == TOOL_ERASER) do_setcursor(cursor_tiny); - } else { @@ -5523,6 +5525,30 @@ static void mainloop(void) sz = calc_eraser_size(cur_eraser); rect_xor(new_x - sz / 2, new_y - sz / 2, new_x + sz / 2, new_y + sz / 2); } + else if (cur_tool == TOOL_FILL && cur_fill == FILL_GRADIENT_LINEAR) + { + Uint32 draw_color, canv_color; + int undo_ctr; + SDL_Surface * last; + + if (cur_undo > 0) + undo_ctr = cur_undo - 1; + else + undo_ctr = NUM_UNDO_BUFS - 1; + + last = undo_bufs[undo_ctr]; + + /* Pushing button and moving: Update the gradient: */ + + draw_color = SDL_MapRGB(canvas->format, + color_hexes[cur_color][0], + color_hexes[cur_color][1], + color_hexes[cur_color][2]); + draw_linear_gradient(canvas, last, sim_flood_x1, sim_flood_y1, sim_flood_x2, sim_flood_y2, + fill_x, fill_y, new_x, new_y, draw_color, sim_flood_touched); + + update_canvas(sim_flood_x1, sim_flood_y1, sim_flood_x2, sim_flood_y2); + } }