Linear gradient fill mode

This commit is contained in:
Bill Kendrick 2021-02-20 21:35:46 -08:00
parent 0dfe96f291
commit 76cb1c5446
4 changed files with 81 additions and 16 deletions

View file

@ -8,7 +8,7 @@ http://www.tuxpaint.org/
$Id$ $Id$
2021.February.21 (0.9.26) 2021.February.20 (0.9.26)
* New Features * New Features
------------ ------------
* Larger UI buttons * Larger UI buttons
@ -20,10 +20,10 @@ $Id$
Pere Pujal i Carabantes <pere@fornol.no-ip.org> Pere Pujal i Carabantes <pere@fornol.no-ip.org>
* Adding sub-tools to the Fill tool: * Adding sub-tools to the Fill tool:
+ Solid -- the classic fill tool, click to fill + Solid -- The classic fill tool; click to fill
+ [WIP] Linear -- A linear gradient, click and drag to adjust, + Linear -- A linear gradient; click and drag to adjust,
release mouse to finish 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 (The gradients transition from the current color to the
background that's being filled.) background that's being filled.)

View file

@ -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 int x1, int y1, int x2, int y2, Uint32 draw_color, Uint8 * touched
) { ) {
Uint32 old_colr, new_colr;
int xx, yy; 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 (yy = y_top; yy <= y_bottom; yy++) {
for (xx = x_left; xx <= x_right; xx++) { for (xx = x_left; xx <= x_right; xx++) {
if (touched[(yy * canvas->w) + xx]) { if (touched[(yy * canvas->w) + xx]) {
/* FIXME */ /* Get the old color, and blend it (with a distance-based ratio) with the target color */
putpixels[canvas->format->BytesPerPixel] (canvas, xx, yy, draw_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);
}
} }
} }
} }

View file

@ -39,7 +39,8 @@
int would_flood_fill(SDL_Surface * canvas, Uint32 cur_colr, Uint32 old_colr); 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 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 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); 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, 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); int x, int y, Uint32 draw_color, Uint8 * touched);

View file

@ -1255,6 +1255,7 @@ static Uint8 canvas_color_r, canvas_color_g, canvas_color_b;
static Uint8 *touched; static Uint8 *touched;
static Uint8 *sim_flood_touched; static Uint8 *sim_flood_touched;
int sim_flood_x1 = 0, sim_flood_y1 = 0, sim_flood_x2 = 0, sim_flood_y2 = 0; 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 last_print_time = 0;
static int shape_radius; static int shape_radius;
@ -4536,6 +4537,9 @@ static void mainloop(void)
color_hexes[cur_color][2]); color_hexes[cur_color][2]);
canv_color = getpixels[canvas->format->BytesPerPixel] (canvas, old_x, old_y); 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)) if (would_flood_fill(canvas, draw_color, canv_color))
{ {
int x1, y1, x2, y2; int x1, y1, x2, y2;
@ -4583,13 +4587,12 @@ static void mainloop(void)
draw_radial_gradient(canvas, sim_flood_x1, sim_flood_y1, sim_flood_x2, sim_flood_y2, 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); old_x, old_y, draw_color, sim_flood_touched);
} }
// else if (cur_fill == FILL_GRADIENT_LINEAR) else if (cur_fill == FILL_GRADIENT_LINEAR)
// { {
// /* Start a linear gradient */ /* Start a linear gradient */
// draw_linear_gradient(canvas, canvas, sim_flood_x1, sim_flood_y1, sim_flood_x2, sim_flood_y2,
// draw_linear_gradient(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);
// old_x, old_y, old_x, old_y + 1, draw_color, sim_flood_touched); }
// }
update_canvas(x1, y1, x2, y2); update_canvas(x1, y1, x2, y2);
} }
@ -5427,7 +5430,6 @@ static void mainloop(void)
do_setcursor(cursor_wand); do_setcursor(cursor_wand);
else if (cur_tool == TOOL_ERASER) else if (cur_tool == TOOL_ERASER)
do_setcursor(cursor_tiny); do_setcursor(cursor_tiny);
} }
else else
{ {
@ -5523,6 +5525,30 @@ static void mainloop(void)
sz = calc_eraser_size(cur_eraser); sz = calc_eraser_size(cur_eraser);
rect_xor(new_x - sz / 2, new_y - sz / 2, new_x + sz / 2, new_y + sz / 2); 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);
}
} }