tuxpaint-pencil-sharpener/src/floodfill.c

153 lines
3.4 KiB
C

/*
floodfill.c
For Tux Paint
Flood fill functions
Copyright (c) 2002-2006 by Bill Kendrick and others
bill@newbreedsoftware.com
http://www.newbreedsoftware.com/tuxpaint/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
(See COPYING.txt)
June 14, 2002 - February 20, 2006
$Id$
*/
#include "floodfill.h"
#include "pixels.h"
#include "rgblinear.h"
#include "sounds.h"
#include "playsound.h"
#include "progressbar.h"
#include "debug.h"
/* For flood fill... */
static int colors_close(SDL_Surface * canvas, Uint32 c1, Uint32 c2)
{
#ifdef LOW_QUALITY_FLOOD_FILL
return (c1 == c2);
#else
Uint8 r1, g1, b1, r2, g2, b2;
if (c1 == c2)
{
/* Get it over with quick, if possible! */
return 1;
}
else
{
double r, g, b;
SDL_GetRGB(c1, canvas->format, &r1, &g1, &b1);
SDL_GetRGB(c2, canvas->format, &r2, &g2, &b2);
// use distance in linear RGB space
r = sRGB_to_linear_table[r1] - sRGB_to_linear_table[r2];
r *= r;
g = sRGB_to_linear_table[g1] - sRGB_to_linear_table[g2];
g *= g;
b = sRGB_to_linear_table[b1] - sRGB_to_linear_table[b2];
b *= b;
// easy to confuse:
// dark grey, brown, purple
// light grey, tan
// red, orange
return r + g + b < 0.04;
}
#endif
}
/* Flood fill! */
void do_flood_fill(SDL_Surface * screen, SDL_Surface * canvas, int x, int y,
Uint32 cur_colr, Uint32 old_colr)
{
int fillL, fillR, i, in_line;
static unsigned char prog_anim;
Uint32(*getpixel) (SDL_Surface *, int, int) =
getpixels[canvas->format->BytesPerPixel];
void (*putpixel) (SDL_Surface *, int, int, Uint32) =
putpixels[canvas->format->BytesPerPixel];
if (cur_colr == old_colr || colors_close(canvas, cur_colr, old_colr))
return;
fillL = x;
fillR = x;
prog_anim++;
if ((prog_anim % 4) == 0)
{
show_progress_bar(screen);
playsound(screen, 0, SND_BUBBLE, 0, x, SNDDIST_NEAR);
}
/* Find left side, filling along the way */
in_line = 1;
while (in_line)
{
putpixel(canvas, fillL, y, cur_colr);
fillL--;
in_line =
(fillL < 0) ? 0 : colors_close(canvas, getpixel(canvas, fillL, y),
old_colr);
}
fillL++;
/* Find right side, filling along the way */
in_line = 1;
while (in_line)
{
putpixel(canvas, fillR, y, cur_colr);
fillR++;
in_line = (fillR >= canvas->w) ? 0 : colors_close(canvas, getpixel(canvas,
fillR,
y),
old_colr);
}
fillR--;
/* Search top and bottom */
for (i = fillL; i <= fillR; i++)
{
if (y > 0 && colors_close(canvas, getpixel(canvas, i, y - 1), old_colr))
do_flood_fill(screen, canvas, i, y - 1, cur_colr, old_colr);
if (y < canvas->h
&& colors_close(canvas, getpixel(canvas, i, y + 1), old_colr))
do_flood_fill(screen, canvas, i, y + 1, cur_colr, old_colr);
}
}