- Implement Floodfill: iterative four neighbors version

- Details for this algorithm are described in the comments
- Nice with the paint clone since the bucket fill tool works now

svn path=/trunk/; revision=42311
This commit is contained in:
Gregor Schneider
2009-07-31 15:41:09 +00:00
parent ace530421a
commit 3e5f2f10f3
4 changed files with 182 additions and 9 deletions
@@ -133,6 +133,7 @@ BOOLEAN DIB_32BPP_ColorFill(SURFOBJ*, RECTL*, ULONG);
BOOLEAN DIB_32BPP_AlphaBlend(SURFOBJ*, SURFOBJ*, RECTL*, RECTL*, CLIPOBJ*, XLATEOBJ*, BLENDOBJ*);
BOOLEAN DIB_XXBPP_StretchBlt(SURFOBJ*,SURFOBJ*,SURFOBJ*,SURFOBJ*,RECTL*,RECTL*,POINTL*,BRUSHOBJ*,POINTL*,XLATEOBJ*,XLATEOBJ*,ROP4);
BOOLEAN DIB_XXBPP_FloodFill(SURFOBJ*, BRUSHOBJ*, RECTL*, POINTL*, XLATEOBJ*, COLORREF, UINT);
extern unsigned char notmask[2];
extern unsigned char altnotmask[2];
@@ -0,0 +1,168 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS win32 subsystem
* PURPOSE: Flood filling support
* FILE: subsystems/win32/win32k/dib/floodfill.c
* PROGRAMMER: Gregor Schneider, <grschneider AT gmail DOT com>
*/
#include <w32k.h>
#define NDEBUG
#include <debug.h>
/*
* This floodfill algorithm is an iterative four neighbors version. It works with an internal stack like data structure.
* The stack is kept in an array, sized for the worst case scenario of having to add all pixels of the surface.
* This avoids having to allocate and free memory blocks all the time. The stack grows from the end of the array towards the start.
* All pixels are checked before being added, against belonging to the fill rule (FLOODFILLBORDER or FLOODFILLSURFACE)
* and the position in respect to the clip region. This guarantees all pixels lying on the stack belong to the filled surface.
* Further optimisations of the algorithm are possible.
*/
/* Floodfil helper structures and functions */
typedef struct _floodItem
{
ULONG x;
ULONG y;
} FLOODITEM;
static ULONG floodLen = 0;
static FLOODITEM *floodStart = NULL, *floodData = NULL;
static __inline BOOL initFlood(RECTL *DstRect)
{
ULONG width = DstRect->right - DstRect->left;
ULONG height = DstRect->bottom - DstRect->top;
floodData = ExAllocatePoolWithTag(NonPagedPool, width * height * sizeof(FLOODITEM), TAG_DIB);
if (floodData == NULL)
{
return FALSE;
}
floodStart = (FLOODITEM*)((PBYTE)floodData + (width * height * sizeof(FLOODITEM)));
return TRUE;
}
static __inline VOID finalizeFlood()
{
ExFreePoolWithTag(floodData, TAG_DIB);
}
static __inline VOID addItemFlood(ULONG x,
ULONG y,
SURFOBJ *DstSurf,
RECTL *DstRect,
XLATEOBJ* ColorTranslation,
COLORREF Color,
BOOL isSurf)
{
if (x >= DstRect->left && x <= DstRect->right &&
y >= DstRect->top && y <= DstRect->bottom)
{
if (isSurf == TRUE && XLATEOBJ_iXlate(ColorTranslation,
DibFunctionsForBitmapFormat[DstSurf->iBitmapFormat].DIB_GetPixel(DstSurf, x, y)) != Color)
{
return;
}
else if (isSurf == FALSE && XLATEOBJ_iXlate(ColorTranslation,
DibFunctionsForBitmapFormat[DstSurf->iBitmapFormat].DIB_GetPixel(DstSurf, x, y)) == Color)
{
return;
}
floodStart--;
floodStart->x = x;
floodStart->y = y;
floodLen++;
}
}
static __inline VOID removeItemFlood()
{
floodStart++;
floodLen--;
}
static __inline BOOL isEmptyFlood()
{
if (floodLen == 0)
{
return TRUE;
}
return FALSE;
}
BOOLEAN DIB_XXBPP_FloodFill(SURFOBJ *DstSurf,
BRUSHOBJ *Brush,
RECTL *DstRect,
POINTL *Origin,
XLATEOBJ *ColorTranslation,
COLORREF Color,
UINT FillType)
{
ULONG x, y;
ULONG BrushColor;
BrushColor = Brush->iSolidColor;
x = Origin->x;
y = Origin->y;
if (FillType == FLOODFILLBORDER)
{
/* Check if the start pixel has the border color */
if (XLATEOBJ_iXlate(ColorTranslation,
DibFunctionsForBitmapFormat[DstSurf->iBitmapFormat].DIB_GetPixel(DstSurf, x, y)) == Color)
{
return FALSE;
}
if (initFlood(DstRect) == FALSE)
{
return FALSE;
}
addItemFlood(x, y, DstSurf, DstRect, ColorTranslation, Color, FALSE);
while (!isEmptyFlood())
{
x = floodStart->x;
y = floodStart->y;
removeItemFlood();
DibFunctionsForBitmapFormat[DstSurf->iBitmapFormat].DIB_PutPixel(DstSurf, x, y, BrushColor);
addItemFlood(x, y + 1, DstSurf, DstRect, ColorTranslation, Color, FALSE);
addItemFlood(x, y - 1, DstSurf, DstRect, ColorTranslation, Color, FALSE);
addItemFlood(x + 1, y, DstSurf, DstRect, ColorTranslation, Color, FALSE);
addItemFlood(x - 1, y, DstSurf, DstRect, ColorTranslation, Color, FALSE);
}
finalizeFlood();
}
else if (FillType == FLOODFILLSURFACE)
{
/* Check if the start pixel has the surface color */
if (XLATEOBJ_iXlate(ColorTranslation,
DibFunctionsForBitmapFormat[DstSurf->iBitmapFormat].DIB_GetPixel(DstSurf, x, y)) != Color)
{
return FALSE;
}
if (initFlood(DstRect) == FALSE)
{
return FALSE;
}
addItemFlood(x, y, DstSurf, DstRect, ColorTranslation, Color, TRUE);
while (!isEmptyFlood())
{
x = floodStart->x;
y = floodStart->y;
removeItemFlood();
DibFunctionsForBitmapFormat[DstSurf->iBitmapFormat].DIB_PutPixel(DstSurf, x, y, BrushColor);
addItemFlood(x, y + 1, DstSurf, DstRect, ColorTranslation, Color, TRUE);
addItemFlood(x, y - 1, DstSurf, DstRect, ColorTranslation, Color, TRUE);
addItemFlood(x + 1, y, DstSurf, DstRect, ColorTranslation, Color, TRUE);
addItemFlood(x - 1, y, DstSurf, DstRect, ColorTranslation, Color, TRUE);
}
finalizeFlood();
}
else
{
DPRINT1("Unsupported FloodFill type!\n");
return FALSE;
}
return TRUE;
}
@@ -1072,13 +1072,12 @@ NtGdiExtFloodFill(
PDC dc;
PDC_ATTR pdcattr;
SURFACE *psurf = NULL;
PBRUSH pbrFill = NULL;
HPALETTE Pal = 0;
XLATEOBJ *XlateObj = NULL;
BOOL Ret = FALSE;
RECTL DestRect;
POINTL Pt;
DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
dc = DC_LockDc(hDC);
if (!dc)
{
@@ -1110,12 +1109,6 @@ NtGdiExtFloodFill(
else
goto cleanup;
pbrFill = dc->dclevel.pbrFill;
if (!pbrFill)
{
Ret = FALSE;
goto cleanup;
}
psurf = dc->dclevel.pSurface;
if (!psurf)
{
@@ -1123,6 +1116,16 @@ NtGdiExtFloodFill(
goto cleanup;
}
Pal = dc->dclevel.pSurface->hDIBPalette;
if (!Pal) Pal = pPrimarySurface->DevInfo.hpalDefault;
XlateObj = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, 0, NULL, Pal);
if (XlateObj != NULL)
{
Ret = DIB_XXBPP_FloodFill(&psurf->SurfObj, &dc->eboFill.BrushObject, &DestRect, &Pt, XlateObj, Color, FillType);
EngDeleteXlate(XlateObj);
}
cleanup:
DC_UnlockDc(dc);
return Ret;
@@ -31,6 +31,7 @@
<file>dib32bpp.c</file>
<file>dibXXbpp.c</file>
<file>dib.c</file>
<file>floodfill.c</file>
<if property="ARCH" value="i386">
<directory name="i386">