windows-nt/Source/XPSP1/NT/shell/comctl32/v6/blur.cpp

306 lines
8.4 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*
** CUTILS.C
**
** Common utilities for common controls
**
*/
#include "ctlspriv.h"
#include <shfusion.h>
#define ARGB(a,r,g,b) ((COLORREF)(( \
((BYTE)(r)) | \
((WORD) ((BYTE)(g))<< 8)) | \
(((DWORD)((BYTE)(b))<<16)) | \
(((DWORD)((BYTE)(a))<<24))))
#define PREMULTIPLY(c, alpha) ((( ((c) * (alpha)) + 128) >> 8) + 1)
typedef struct tagCCBUFFER
{
HDC hdc;
HBITMAP hbmp;
HBITMAP hbmpOld;
RGBQUAD* prgb;
} CCBUFFER;
BOOL Buffer_CreateBuffer(HDC hdc, int cx, int cy, CCBUFFER* pbuf)
{
BOOL fRet = FALSE;
BITMAPINFO bi = {0};
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = cx;
bi.bmiHeader.biHeight = cy;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
pbuf->hdc = CreateCompatibleDC(hdc);
if (pbuf->hdc)
{
pbuf->hbmp = CreateDIBSection(pbuf->hdc, &bi, DIB_RGB_COLORS, (VOID**)&pbuf->prgb, NULL, 0);
if (!pbuf->hbmp)
{
DeleteDC(pbuf->hdc);
ZeroMemory(pbuf, sizeof(CCBUFFER));
}
else
{
pbuf->hbmpOld = (HBITMAP)SelectObject(pbuf->hdc, pbuf->hbmp);
fRet = TRUE;
}
}
return fRet;
}
void Buffer_DestroyBuffer(CCBUFFER* pbuf)
{
if (pbuf->hdc)
{
SelectObject(pbuf->hdc, pbuf->hbmpOld);
DeleteDC(pbuf->hdc);
DeleteObject(pbuf->hbmp);
}
}
void BlurBitmapNormal(ULONG* prgb, int cx, int cy, COLORREF crFill)
{
BYTE r = GetRValue(crFill);
BYTE g = GetGValue(crFill);
BYTE b = GetBValue(crFill);
int cxMax = cx - 5;
int cyMax = cy - 5;
int iOffset;
int y;
for (y=0, iOffset = 0; y < cy; y++, iOffset += cx)
{
ULONG* p = &prgb[iOffset];
int Accum = ((*p)) +
((*(p + 1))) +
((*(p + 2))) +
((*(p + 3)));
for (int x=0; x< cxMax; x++)
{
Accum = Accum - ((*p)) + ((*(p + 4)));
*p++ = (Accum >> 2);
}
}
int cx2 = cx << 1;
int cx3 = cx + cx + cx;
int cx4 = cx << 2;
for (iOffset = 0, y=0; y < cyMax; y++, iOffset += cx)
{
ULONG* p = &prgb[iOffset];
for (int x=0; x < cx; x++)
{
DWORD Alpha = (((*p) ) +
(*(p + cx) ) +
(*(p + cx2) ) +
(*(p + cx3) ) +
(*(p + cx4) )) >> 2;
if (Alpha > 255)
Alpha = 255;
*p = (ULONG)ARGB(Alpha, PREMULTIPLY(r, Alpha), PREMULTIPLY(g, Alpha), PREMULTIPLY(b, Alpha));
p++;
}
}
}
#ifdef _X86_
QWORD qw128 = 0x0000008000800080;
QWORD qw1 = 0x0000000100010001;
void BlurBitmapMMX(ULONG* prgb, int cx, int cy, COLORREF crFill)
{
RGBQUAD rgbFill; // ColorRef is opposite of RGBQUAD
rgbFill.rgbRed = GetRValue(crFill);
rgbFill.rgbGreen = GetGValue(crFill);
rgbFill.rgbBlue = GetBValue(crFill);
int cxMax = cx - 5;
int cyMax = cy - 5;
int iOffset;
int y;
for (y=0, iOffset = 0; y < cy; y++, iOffset += cx)
{
ULONG* p = &prgb[iOffset];
int Accum = ((*p)) +
((*(p + 1))) +
((*(p + 2))) +
((*(p + 3)));
for (int x=0; x< cxMax; x++)
{
Accum = Accum - ((*p)) + ((*(p + 4)));
*p++ = (Accum >> 2);
}
}
int cx2 = cx << 1;
int cx3 = cx + cx + cx;
int cx4 = cx << 2;
_asm
{
pxor mm0, mm0
pxor mm1, mm1
pxor mm5, mm5
movd mm4, dword ptr [rgbFill]
movq mm6, qw128 // mm6 is filled with 128
movq mm7, qw1 // mm7 is filled with 1
}
for (iOffset = 0, y=0; y < cyMax; y++, iOffset += cx)
{
ULONG* p = &prgb[iOffset];
for (int x=0; x < cx; x++)
{
DWORD Alpha = (((*p) ) +
(*(p + cx) ) +
(*(p + cx2) ) +
(*(p + cx3) ) +
(*(p + cx4) )) >> 2;
if (Alpha > 255)
Alpha = 255;
*p = ((BYTE)Alpha);
_asm
{
mov edx, dword ptr [p]
mov ebx, dword ptr [edx]
mov eax, ebx // a -> b
or eax, eax
jz EarlyOut
shl ebx, 8 // b << 8
or eax, ebx // a |= b
shl ebx, 8 // b << 8
or eax, ebx // a |= b
shl ebx, 8 // b << 8
// Note high byte of alpha is zero.
movd mm0, eax // a -> mm0
movq mm1, mm4 // Load the pixel
punpcklbw mm0,mm5 // mm0 -> Expands <- mm0 Contains the Alpha channel for this multiply
punpcklbw mm1, mm5 // Unpack the pixel
pmullw mm1, mm0 // Multiply by the alpha channel <- mm1 contains c * alpha
paddusw mm1, mm6 // perform the (c * alpha) + 128
psrlw mm1, 8 // Divide by 255
paddusw mm1, mm7 // Add 1 to finish the divide by 255
packuswb mm1, mm5
movd eax, mm1
or eax, ebx // Transfer alpha channel
EarlyOut:
mov dword ptr [edx], eax
}
p++;
}
}
_asm emms
}
void BlurBitmap(ULONG* plBitmapBits, int cx, int cy, COLORREF crFill)
{
if (IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE))
BlurBitmapMMX(plBitmapBits, cx, cy, crFill);
else
BlurBitmapNormal(plBitmapBits, cx, cy, crFill);
}
#else
void BlurBitmap(ULONG* plBitmapBits, int cx, int cy, COLORREF crFill)
{
BlurBitmapNormal(plBitmapBits, cx, cy, crFill);
}
#endif
int DrawShadowText(HDC hdc, LPCTSTR pszText, UINT cch, RECT* prc, DWORD dwFlags, COLORREF crText,
COLORREF crShadow, int ixOffset, int iyOffset)
{
int iRet = -1;
if (dwFlags & DT_CALCRECT)
{
iRet = DrawText(hdc, pszText, cch, prc, dwFlags | DT_CALCRECT);
}
else
{
if (GetLayout(hdc) == LAYOUT_RTL)
{
COLORREF crTextSave = SetTextColor(hdc, crShadow);
int iMode = SetBkMode(hdc, TRANSPARENT);
RECT rc = *prc;
OffsetRect(&rc, ixOffset, iyOffset);
DrawText(hdc, pszText, cch, &rc, dwFlags);
SetBkMode(hdc, iMode);
SetTextColor(hdc, crTextSave);
}
else
{
RECT rc = *prc;
CCBUFFER buf;
int cx = RECTWIDTH(rc) + 10;
int cy = RECTHEIGHT(rc) + 10;
if (Buffer_CreateBuffer(hdc, cx, cy, &buf))
{
OffsetRect(&rc, 5, 5);
RECT rcMem = {5, 5, RECTWIDTH(rc) + 5, RECTHEIGHT(rc) + 5};
HFONT hFontOldhdc = (HFONT)SelectObject(hdc, GetStockObject(SYSTEM_FONT));
HFONT hFontOldhdcMem = (HFONT)SelectObject(buf.hdc, hFontOldhdc);
SetTextColor(buf.hdc, crText);
SetBkColor(buf.hdc, crShadow);
SetBkMode(buf.hdc, TRANSPARENT);
DrawText(buf.hdc, pszText, cch, &rcMem, dwFlags);
int Total = cx * cy;
for (int z = 0; z < Total; z++)
{
if (((PULONG)buf.prgb)[z] != 0)
((PULONG)buf.prgb)[z] = 0x000000ff;
}
BlurBitmap((ULONG*)buf.prgb, cx, cy, crShadow);
BLENDFUNCTION bf = {0};
bf.BlendOp = AC_SRC_OVER;
bf.SourceConstantAlpha = 255;
bf.AlphaFormat = AC_SRC_ALPHA;
GdiAlphaBlend(hdc, prc->left - 4 + ixOffset, prc->top - 8 + iyOffset, cx, cy, buf.hdc, 0, 0, cx, cy, bf);
SelectObject(buf.hdc, hFontOldhdcMem);
SelectObject(hdc, hFontOldhdc);
Buffer_DestroyBuffer(&buf);
}
}
int iMode = SetBkMode(hdc, TRANSPARENT);
COLORREF crTextSave = SetTextColor(hdc, crText);
iRet = DrawText(hdc, pszText, cch, prc, dwFlags);
SetTextColor(hdc, crTextSave);
SetBkMode(hdc, iMode);
}
return iRet;
}