- Performance improvement on BitmapToRegion function.
This commit is contained in:
spx 2011-10-22 20:28:15 +00:00
parent 3e7de9c573
commit e166e34948
3 changed files with 74 additions and 65 deletions

View File

@ -46,11 +46,9 @@ void FinalizeLitestep()
DeleteCriticalSection(&g_CsLogDelay); DeleteCriticalSection(&g_CsLogDelay);
} }
HRGN BitmapToRegion(HBITMAP hbm, COLORREF clrTransp, COLORREF clrTolerance, int xoffset, int yoffset) HRGN BitmapToRegion(HBITMAP hbm, COLORREF clrTransp, COLORREF clrTolerance)
{ {
// start with a completely transparent rgn HRGN hRgn = NULL;
// this is more correct as no bmp, should render a transparent background
HRGN hRgn = CreateRectRgn(0, 0, 0, 0);
if (hbm) if (hbm)
{ {
@ -58,26 +56,25 @@ HRGN BitmapToRegion(HBITMAP hbm, COLORREF clrTransp, COLORREF clrTolerance, int
HDC hdcMem = CreateCompatibleDC(NULL); HDC hdcMem = CreateCompatibleDC(NULL);
if (hdcMem) if (hdcMem)
{ {
VOID *pbits32;
HBITMAP hbm32;
BITMAP bm;
// get the size // get the size
BITMAP bm;
GetObject(hbm, sizeof(BITMAP), &bm); GetObject(hbm, sizeof(BITMAP), &bm);
BITMAPINFOHEADER bmpInfo32; BITMAPINFOHEADER bmpInfo32;
bmpInfo32.biSize = sizeof(BITMAPINFOHEADER); bmpInfo32.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo32.biWidth = bm.bmWidth; bmpInfo32.biWidth = bm.bmWidth;
bmpInfo32.biHeight = bm.bmHeight; bmpInfo32.biHeight = bm.bmHeight;
bmpInfo32.biPlanes = 1; bmpInfo32.biPlanes = 1;
bmpInfo32.biBitCount = 32; bmpInfo32.biBitCount = 32;
bmpInfo32.biCompression = BI_RGB; bmpInfo32.biCompression = BI_RGB;
bmpInfo32.biSizeImage = 0; bmpInfo32.biSizeImage = 0;
bmpInfo32.biXPelsPerMeter = 0; bmpInfo32.biXPelsPerMeter = 0;
bmpInfo32.biYPelsPerMeter = 0; bmpInfo32.biYPelsPerMeter = 0;
bmpInfo32.biClrUsed = 0; bmpInfo32.biClrUsed = 0;
bmpInfo32.biClrImportant = 0; bmpInfo32.biClrImportant = 0;
hbm32 = CreateDIBSection(hdcMem, (BITMAPINFO *) & bmpInfo32, DIB_RGB_COLORS, &pbits32, NULL, 0); VOID* pbits32;
HBITMAP hbm32 = CreateDIBSection(hdcMem, (BITMAPINFO *) & bmpInfo32, DIB_RGB_COLORS, &pbits32, NULL, 0);
if (hbm32) if (hbm32)
{ {
HBITMAP hbmOld32 = (HBITMAP)SelectObject(hdcMem, hbm32); HBITMAP hbmOld32 = (HBITMAP)SelectObject(hdcMem, hbm32);
@ -87,11 +84,14 @@ HRGN BitmapToRegion(HBITMAP hbm, COLORREF clrTransp, COLORREF clrTolerance, int
if (hdcTmp) if (hdcTmp)
{ {
// Get how many bytes per row we have for the bitmap bits (rounded up to 32 bits // Get how many bytes per row we have for the bitmap bits (rounded up to 32 bits
int y = 0;
BITMAP bm32; BITMAP bm32;
GetObject(hbm32, sizeof(bm32), &bm32); GetObject(hbm32, sizeof(bm32), &bm32);
while (bm32.bmWidthBytes % 4) while (bm32.bmWidthBytes % 4)
bm32.bmWidthBytes++; ++bm32.bmWidthBytes;
// Copy the bitmap into the memory D
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcTmp, hbm);
BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcTmp, 0, 0, SRCCOPY);
// get the limits for the colors // get the limits for the colors
BYTE clrHiR = ( 0xff - GetRValue( clrTolerance ) > GetRValue( clrTransp ) ) ? GetRValue( clrTransp ) + GetRValue( clrTolerance ) : 0xff; BYTE clrHiR = ( 0xff - GetRValue( clrTolerance ) > GetRValue( clrTransp ) ) ? GetRValue( clrTransp ) + GetRValue( clrTolerance ) : 0xff;
@ -101,68 +101,67 @@ HRGN BitmapToRegion(HBITMAP hbm, COLORREF clrTransp, COLORREF clrTolerance, int
BYTE clrLoG = ( GetGValue( clrTolerance ) < GetGValue( clrTransp ) ) ? GetGValue( clrTransp ) - GetGValue( clrTolerance ) : 0x00; BYTE clrLoG = ( GetGValue( clrTolerance ) < GetGValue( clrTransp ) ) ? GetGValue( clrTransp ) - GetGValue( clrTolerance ) : 0x00;
BYTE clrLoB = ( GetBValue( clrTolerance ) < GetBValue( clrTransp ) ) ? GetBValue( clrTransp ) - GetBValue( clrTolerance ) : 0x00; BYTE clrLoB = ( GetBValue( clrTolerance ) < GetBValue( clrTransp ) ) ? GetBValue( clrTransp ) - GetBValue( clrTolerance ) : 0x00;
// Copy the bitmap into the memory D // Allocate initial RGNDATA buffer
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcTmp, hbm); #define ALLOC_UNIT 100
DWORD maxRects = ALLOC_UNIT;
BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcTmp, 0, 0, SRCCOPY); HANDLE hRgnData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects));
RGNDATA* pRgnData = (RGNDATA*)GlobalLock(hRgnData);
pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER);
pRgnData->rdh.iType = RDH_RECTANGLES;
pRgnData->rdh.nCount = pRgnData->rdh.nRgnSize = 0;
SetRect(&pRgnData->rdh.rcBound, 0, 0, bm.bmWidth, bm.bmHeight);
// Scan each bitmap row from bottom to top (the bitmap is inverted vertically // Scan each bitmap row from bottom to top (the bitmap is inverted vertically
BYTE *p; BYTE* p32 = (BYTE*)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes;
BYTE *p32 = (BYTE *)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes; for (int y = 0; y < bm.bmHeight; ++y)
while (y < bm.bmHeight)
{ {
int x = 0; for (int x = 0; x < bm.bmWidth; ++x)
while ( x < bm.bmWidth )
{ {
int x0 = 0; int x0 = x;
// loop through all transparent pixels...
while ( x < bm.bmWidth )
{
p = p32 + 4 * x;
// if the pixel is non-transparent
if (*p < clrLoB || *p > clrHiB)
break;
p++;
if (*p < clrLoG || *p > clrHiG)
break;
p++;
if (*p < clrLoR || *p > clrHiR)
break;
x++;
}
// set first non transparent pixel
x0 = x;
// loop through all non transparent pixels // loop through all non transparent pixels
while ( x < bm.bmWidth ) while (x < bm.bmWidth)
{ {
p = p32 + 4 * x; BYTE* p = p32 + 4 * x;
// if the pixel is transparent, then break // if the pixel is transparent, then break
if (*p >= clrLoB && *p <= clrHiB) if (*p >= clrLoB && *p <= clrHiB)
{ {
p++; ++p;
if (*p >= clrLoG && *p <= clrHiG) if (*p >= clrLoG && *p <= clrHiG)
{ {
p++; ++p;
if (*p >= clrLoR && *p <= clrHiR) if (*p >= clrLoR && *p <= clrHiR)
break; break;
} }
} }
x++; ++x;
} }
// if found one or more non-transparent pixels in a row, add them to the rgn... // if found one or more non-transparent pixels in a row, add them to the rgn...
if (x != x0) if (x > x0)
{ {
HRGN hTempRgn = CreateRectRgn(x0 + xoffset, y + yoffset, x + xoffset, y + 1 + yoffset); if (pRgnData->rdh.nCount >= maxRects)
CombineRgn(hRgn, hRgn, hTempRgn, RGN_OR); {
DeleteObject(hTempRgn); // Reallocate RGNDATA buffer
GlobalUnlock(hRgnData);
maxRects += ALLOC_UNIT;
hRgnData = GlobalReAlloc(hRgnData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), GMEM_MOVEABLE);
pRgnData = (RGNDATA*)GlobalLock(hRgnData);
}
SetRect(((RECT*)pRgnData->Buffer) + pRgnData->rdh.nCount, x0, y, x, y + 1);
++pRgnData->rdh.nCount;
} }
x++;
} }
y++;
p32 -= bm32.bmWidthBytes; p32 -= bm32.bmWidthBytes;
} }
// Create the region with the collected rectangles
hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pRgnData);
// Clean up // Clean up
GlobalUnlock(hRgnData);
GlobalFree(hRgnData);
SelectObject(hdcTmp, hbmOld); SelectObject(hdcTmp, hbmOld);
DeleteDC(hdcTmp); DeleteDC(hdcTmp);
} }

View File

@ -30,7 +30,7 @@ void FinalizeLitestep();
void ResetLoggingFlag(); void ResetLoggingFlag();
HRGN BitmapToRegion(HBITMAP hBmp, COLORREF cTransparentColor, COLORREF cTolerance, int xoffset, int yoffset); HRGN BitmapToRegion(HBITMAP hBmp, COLORREF cTransparentColor, COLORREF cTolerance);
std::string ConvertToAscii(LPCTSTR str); std::string ConvertToAscii(LPCTSTR str);
std::wstring ConvertToWide(LPCSTR str); std::wstring ConvertToWide(LPCSTR str);

View File

@ -399,8 +399,8 @@ void CMeterWindow::Refresh(bool init, bool all)
// Set the window region // Set the window region
CreateRegion(true); // Clear the region CreateRegion(true); // Clear the region
if (init) ShowWindow(m_Window, SW_SHOWNOACTIVATE);
Update(false); Update(false);
CreateRegion(false);
if (m_KeepOnScreen) if (m_KeepOnScreen)
{ {
@ -2652,10 +2652,18 @@ void CMeterWindow::CreateRegion(bool clear)
m_DoubleBuffer->GetHBITMAP(Color(255,0,255), &background); m_DoubleBuffer->GetHBITMAP(Color(255,0,255), &background);
if (background) if (background)
{ {
HRGN region = BitmapToRegion(background, RGB(255,0,255), 0x101010, 0, 0); HRGN region = BitmapToRegion(background, RGB(255,0,255), 0x101010);
SetWindowRgn(m_Window, region, TRUE); SetWindowRgn(m_Window, region, TRUE);
DeleteObject(background); DeleteObject(background);
} }
else
{
SetWindowRgn(m_Window, NULL, TRUE);
}
}
else
{
SetWindowRgn(m_Window, NULL, TRUE);
} }
} }
} }
@ -2672,7 +2680,6 @@ void CMeterWindow::Redraw()
if (m_ResetRegion) if (m_ResetRegion)
{ {
ResizeWindow(false); ResizeWindow(false);
CreateRegion(true);
} }
// Create or clear the doublebuffer // Create or clear the doublebuffer
@ -2768,8 +2775,11 @@ void CMeterWindow::Redraw()
} }
} }
if (m_ResetRegion) CreateRegion(false); if (m_ResetRegion || !m_BackgroundName.empty())
m_ResetRegion = false; {
CreateRegion(false);
m_ResetRegion = false;
}
UpdateTransparency(m_TransparencyValue, false); UpdateTransparency(m_TransparencyValue, false);