paint: cleanup floodfill

This commit is contained in:
cinap_lenrek 2012-07-23 08:10:17 +02:00
parent b3d7231013
commit 03806e9c17

View file

@ -269,20 +269,27 @@ restore(int n)
typedef struct { typedef struct {
Rectangle r; Rectangle r;
Rectangle r0; Rectangle r0;
Image *iscan; Image* dst;
uchar *bscan;
uchar *bmask; int yscan; /* current scanline */
int wmask; int wscan; /* bscan width in bytes */
int wscan; Image* iscan; /* scanline image */
int yscan; uchar* bscan; /* scanline buffer */
uchar color[4];
} Floodfill; int nmask; /* size of bmask in bytes */
int wmask; /* width of bmask in bytes */
Image* imask; /* mask image */
uchar* bmask; /* mask buffer */
int ncmp;
uchar bcmp[4];
} Filldata;
void void
floodscan(Floodfill *f, Point p0) fillscan(Filldata *f, Point p0)
{ {
uchar *b;
int x, y; int x, y;
uchar *b;
x = p0.x; x = p0.x;
y = p0.y; y = p0.y;
@ -291,18 +298,19 @@ floodscan(Floodfill *f, Point p0)
return; return;
if(f->yscan != y){ if(f->yscan != y){
draw(f->iscan, f->iscan->r, f->dst, nil, Pt(f->r.min.x, f->r.min.y+y));
if(unloadimage(f->iscan, f->iscan->r, f->bscan, f->wscan) < 0)
return;
f->yscan = y; f->yscan = y;
draw(f->iscan, f->iscan->r, canvas, nil, Pt(f->r.min.x, f->r.min.y+y));
unloadimage(f->iscan, f->iscan->r, f->bscan, f->wscan);
} }
for(x = p0.x; x >= 0; x--){ for(x = p0.x; x >= 0; x--){
if(memcmp(f->bscan + x*3, f->color, 3)) if(memcmp(f->bscan + x*f->ncmp, f->bcmp, f->ncmp))
break; break;
b[x/8] |= 0x80>>(x%8); b[x/8] |= 0x80>>(x%8);
} }
for(x = p0.x+1; x < f->r0.max.x; x++){ for(x = p0.x+1; x < f->r0.max.x; x++){
if(memcmp(f->bscan + x*3, f->color, 3)) if(memcmp(f->bscan + x*f->ncmp, f->bcmp, f->ncmp))
break; break;
b[x/8] |= 0x80>>(x%8); b[x/8] |= 0x80>>(x%8);
} }
@ -312,12 +320,12 @@ floodscan(Floodfill *f, Point p0)
for(x = p0.x; x >= 0; x--){ for(x = p0.x; x >= 0; x--){
if((b[x/8] & 0x80>>(x%8)) == 0) if((b[x/8] & 0x80>>(x%8)) == 0)
break; break;
floodscan(f, Pt(x, y)); fillscan(f, Pt(x, y));
} }
for(x = p0.x+1; x < f->r0.max.x; x++){ for(x = p0.x+1; x < f->r0.max.x; x++){
if((b[x/8] & 0x80>>(x%8)) == 0) if((b[x/8] & 0x80>>(x%8)) == 0)
break; break;
floodscan(f, Pt(x, y)); fillscan(f, Pt(x, y));
} }
} }
@ -326,54 +334,62 @@ floodscan(Floodfill *f, Point p0)
for(x = p0.x; x >= 0; x--){ for(x = p0.x; x >= 0; x--){
if((b[x/8] & 0x80>>(x%8)) == 0) if((b[x/8] & 0x80>>(x%8)) == 0)
break; break;
floodscan(f, Pt(x, y)); fillscan(f, Pt(x, y));
} }
for(x = p0.x+1; x < f->r0.max.x; x++){ for(x = p0.x+1; x < f->r0.max.x; x++){
if((b[x/8] & 0x80>>(x%8)) == 0) if((b[x/8] & 0x80>>(x%8)) == 0)
break; break;
floodscan(f, Pt(x, y)); fillscan(f, Pt(x, y));
} }
} }
} }
void void
floodfill(Point p, Image *fill) floodfill(Image *dst, Rectangle r, Point p, Image *src)
{ {
Floodfill f; Filldata f;
Image *imask;
int nmask;
f.r = canvas->r; if(!rectclip(&r, dst->r))
f.r0 = rectsubpt(f.r, f.r.min); return;
if(!ptinrect(p, r))
return;
memset(&f, 0, sizeof(f));
f.dst = dst;
f.r = r;
f.r0 = rectsubpt(r, r.min);
f.wmask = bytesperline(f.r0, 1); f.wmask = bytesperline(f.r0, 1);
nmask = f.wmask*f.r0.max.y; f.nmask = f.wmask*f.r0.max.y;
if((f.bmask = mallocz(nmask, 1)) == nil) if((f.bmask = mallocz(f.nmask, 1)) == nil)
return; goto out;
if((f.iscan = allocimage(display, Rect(0, 0, f.r0.max.x, 1), RGB24, 0, DNofill)) == nil){ if((f.imask = allocimage(display, f.r0, GREY1, 0, DNofill)) == nil)
free(f.bmask); goto out;
return;
} r = f.r0;
r.max.y = 1;
if((f.iscan = allocimage(display, r, RGB24, 0, DNofill)) == nil)
goto out;
f.yscan = -1; f.yscan = -1;
f.wscan = bytesperline(f.iscan->r, 24); f.wscan = bytesperline(f.iscan->r, f.iscan->depth);
if((f.bscan = mallocz(f.wscan, 1)) == nil){ if((f.bscan = mallocz(f.wscan, 0)) == nil)
freeimage(f.iscan); goto out;
free(f.bmask);
return; r = Rect(0,0,1,1);
} f.ncmp = (f.iscan->depth+7) / 8;
memset(f.color, 0, sizeof(f.color)); draw(f.iscan, r, dst, nil, p);
draw(f.iscan, Rect(0,0,1,1), canvas, nil, p); if(unloadimage(f.iscan, r, f.bcmp, sizeof(f.bcmp)) < 0)
unloadimage(f.iscan, Rect(0,0,1,1), f.color, sizeof(f.color)); goto out;
floodscan(&f, subpt(p, f.r.min));
freeimage(f.iscan); fillscan(&f, subpt(p, f.r.min));
free(f.bscan);
if((imask = allocimage(display, f.r0, GREY1, 0, DNofill)) == nil){ loadimage(f.imask, f.imask->r, f.bmask, f.nmask);
free(f.bmask); draw(f.dst, f.r, src, f.imask, f.imask->r.min);
return; out:
}
loadimage(imask, imask->r, f.bmask, nmask);
free(f.bmask); free(f.bmask);
draw(canvas, canvas->r, fill, imask, imask->r.min); free(f.bscan);
freeimage(imask); if(f.iscan)
freeimage(f.iscan);
if(f.imask)
freeimage(f.imask);
} }
void void
@ -606,9 +622,11 @@ main(int argc, char *argv[])
update(nil); update(nil);
break; break;
} }
save(canvas->r, 1); r = canvas->r;
floodfill(p, img); save(r, 1);
update(nil); floodfill(canvas, r, p, img);
update(&r);
/* wait for mouse release */ /* wait for mouse release */
while(event(&e) == Emouse && (e.mouse.buttons & 7) != 0) while(event(&e) == Emouse && (e.mouse.buttons & 7) != 0)
; ;