/* check_flood_line: * Checks a line segment, using the scratch buffer is to store a list of * segments which have already been drawn in order to minimise the required * number of tests. */ static int check_flood_line(Image* image, int y, int left, int right, const gfx::Rect& bounds, int src_color, int tolerance, void *data, AlgoHLine proc) { int c; FLOODED_LINE *p; int ret = false; while (left <= right) { c = y; for (;;) { p = FLOOD_LINE(c); if ((left >= p->lpos) && (left <= p->rpos)) { left = p->rpos+2; break; } c = p->next; if (!c) { left = flooder(image, left, y, bounds, src_color, tolerance, data, proc); ret = true; break; } } } return ret; }
/* check_flood_line: * Checks a line segment, using the scratch buffer is to store a list of * segments which have already been drawn in order to minimise the required * number of tests. */ static BOOL check_flood_line (FLOODER_INFO* fi, int y, int left, int right) { int c; FLOODED_LINE *p; int ret = FALSE; while (left <= right) { c = y - fi->dst_rc->top; for (;;) { p = FLOOD_LINE_P(c); if ((left >= p->lpos) && (left <= p->rpos)) { left = p->rpos+2; break; } c = p->next; if (!c) { left = flooder(fi, left, y); ret = TRUE; break; } } } return ret; }
/* floodfill: * Fills an enclosed area (starting at point x, y) with the specified color. */ void algo_floodfill(Image* image, int x, int y, const gfx::Rect& bounds, int tolerance, bool contiguous, void* data, AlgoHLine proc) { // Make sure we have a valid starting point if ((x < 0) || (x >= image->width()) || (y < 0) || (y >= image->height())) return; // What color to replace? color_t src_color = get_pixel(image, x, y); // Non-contiguous case, we replace colors in the whole image. if (!contiguous) { switch (image->pixelFormat()) { case IMAGE_RGB: replace_color<RgbTraits>(image, bounds, src_color, tolerance, data, proc); break; case IMAGE_GRAYSCALE: replace_color<GrayscaleTraits>(image, bounds, src_color, tolerance, data, proc); break; case IMAGE_INDEXED: replace_color<IndexedTraits>(image, bounds, src_color, tolerance, data, proc); break; } return; } /* set up the list of flooded segments */ flood_buf.resize(image->height()); flood_count = image->height(); FLOODED_LINE* p = (FLOODED_LINE*)&flood_buf[0]; for (int c=0; c<flood_count; c++) { p[c].flags = 0; p[c].lpos = SHRT_MAX; p[c].rpos = SHRT_MIN; p[c].y = y; p[c].next = 0; } // Start up the flood algorithm flooder(image, x, y, bounds, src_color, tolerance, data, proc); // Continue as long as there are some segments still to test bool done; do { done = true; // For each line on the screen for (int c=0; c<flood_count; c++) { p = FLOOD_LINE(c); // Check below the segment? if (p->flags & FLOOD_TODO_BELOW) { p->flags &= ~FLOOD_TODO_BELOW; if (check_flood_line(image, p->y+1, p->lpos, p->rpos, bounds, src_color, tolerance, data, proc)) { done = false; p = FLOOD_LINE(c); } } // Check above the segment? if (p->flags & FLOOD_TODO_ABOVE) { p->flags &= ~FLOOD_TODO_ABOVE; if (check_flood_line(image, p->y-1, p->lpos, p->rpos, bounds, src_color, tolerance, data, proc)) { done = false; // Special case shortcut for going backwards if ((c > bounds.y) && (c < bounds.y2())) c -= 2; } } } } while (!done); }
/* floodfill: * Fills an enclosed area (starting at point x, y) with the specified color. */ void algo_floodfill(Image* image, int x, int y, int tolerance, void *data, AlgoHLine proc) { int src_color; int c, done; FLOODED_LINE *p; /* make sure we have a valid starting point */ if ((x < 0) || (x >= image->w) || (y < 0) || (y >= image->h)) return; /* what color to replace? */ src_color = image_getpixel (image, x, y); /* set up the list of flooded segments */ _grow_scratch_mem(sizeof(FLOODED_LINE) * image->h); flood_count = image->h; p = (FLOODED_LINE*)_scratch_mem; for (c=0; c<flood_count; c++) { p[c].flags = 0; p[c].lpos = SHRT_MAX; p[c].rpos = SHRT_MIN; p[c].y = y; p[c].next = 0; } /* start up the flood algorithm */ flooder(image, x, y, src_color, tolerance, data, proc); /* continue as long as there are some segments still to test */ do { done = true; /* for each line on the screen */ for (c=0; c<flood_count; c++) { p = FLOOD_LINE(c); /* check below the segment? */ if (p->flags & FLOOD_TODO_BELOW) { p->flags &= ~FLOOD_TODO_BELOW; if (check_flood_line(image, p->y+1, p->lpos, p->rpos, src_color, tolerance, data, proc)) { done = false; p = FLOOD_LINE(c); } } /* check above the segment? */ if (p->flags & FLOOD_TODO_ABOVE) { p->flags &= ~FLOOD_TODO_ABOVE; if (check_flood_line(image, p->y-1, p->lpos, p->rpos, src_color, tolerance, data, proc)) { done = false; /* special case shortcut for going backwards */ if ((c < image->h) && (c > 0)) c -= 2; } } } } while (!done); }
/* * FloodFillGenerator: */ BOOL GUIAPI FloodFillGenerator (void* context, const RECT* dst_rc, int x, int y, CB_EQUAL_PIXEL cb_equal_pixel, CB_FLOOD_FILL cb_flood_fill) { FLOODER_INFO fi; int c, done; FLOODED_LINE *p; /* make sure we have a valid starting point */ if ((x < dst_rc->left) || (x >= dst_rc->right) || (y < dst_rc->top) || (y >= dst_rc->bottom)) { return TRUE; } /* set up the list of flooded segments */ fi.flood_count = RECTHP (dst_rc); fi.flooded_lines = (FLOODED_LINE*) malloc (sizeof(FLOODED_LINE) * fi.flood_count); if (!(p = fi.flooded_lines)) { return FALSE; } fi.context = context; fi.dst_rc = dst_rc; fi.cb_equal_pixel = cb_equal_pixel; fi.cb_flood_fill = cb_flood_fill; for (c = 0; c < fi.flood_count; c++) { p[c].flags = 0; p[c].lpos = SHRT_MAX; p[c].rpos = SHRT_MIN; p[c].y = y; p[c].next = 0; } /* start up the flood algorithm */ flooder (&fi, x, y); /* continue as long as there are some segments still to test */ do { done = TRUE; /* for each line on the screen */ for (c = 0; c < fi.flood_count; c++) { p = FLOOD_LINE (c); /* check below the segment? */ if (p->flags & FLOOD_TODO_BELOW) { p->flags &= ~FLOOD_TODO_BELOW; if (check_flood_line (&fi, p->y+1, p->lpos, p->rpos)) { done = FALSE; p = FLOOD_LINE (c); } } /* check above the segment? */ if (p->flags & FLOOD_TODO_ABOVE) { p->flags &= ~FLOOD_TODO_ABOVE; if (check_flood_line (&fi, p->y-1, p->lpos, p->rpos)) { done = FALSE; /* special case shortcut for going backwards */ if ((c < RECTHP (dst_rc)) && (c > 0)) c -= 2; } } } } while (!done); free (fi.flooded_lines); return TRUE; }