summaryrefslogtreecommitdiff
path: root/plugins/Clist_ng/SRC/gfx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/Clist_ng/SRC/gfx.cpp')
-rw-r--r--plugins/Clist_ng/SRC/gfx.cpp441
1 files changed, 441 insertions, 0 deletions
diff --git a/plugins/Clist_ng/SRC/gfx.cpp b/plugins/Clist_ng/SRC/gfx.cpp
new file mode 100644
index 0000000000..3055ff8ef7
--- /dev/null
+++ b/plugins/Clist_ng/SRC/gfx.cpp
@@ -0,0 +1,441 @@
+/*
+* astyle --force-indent=tab=4 --brackets=linux --indent-switches
+* --pad=oper --one-line=keep-blocks --unpad=paren
+*
+* Miranda IM: the free IM client for Microsoft* Windows*
+*
+* Copyright 2000-2010 Miranda ICQ/IM project,
+* all portions of this codebase are copyrighted to the people
+* listed in contributors.txt.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* you should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* part of clist_ng plugin for Miranda.
+*
+* (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+*
+* $Id: gfx.cpp 134 2010-10-01 10:23:10Z silvercircle $
+*
+* clist_ng low level graphics code
+*/
+
+#include <commonheaders.h>
+#include <math.h>
+
+#ifdef _USE_D2D
+ ID2D1Factory* Gfx::pD2DFactory = 0;
+#endif
+COLORREF Gfx::txtColor = 0;
+//Gdiplus::GdiplusStartupInput Gfx::gdiPlusStartupInput;
+//ULONG_PTR Gfx::gdiPlusToken;
+
+/**
+ * Create a 32bit RGBA bitmap, compatible for rendering with alpha channel.
+ * Required by anything which would render on a transparent aero surface.
+ * the image is a "bottom up" bitmap, as it has a negative
+ * height. This is a requirement for some UxTheme APIs (e.g.
+ * DrawThemeTextEx).
+ *
+ * @param rc RECT &: the rectangle describing the target area.
+ * @param dc The device context for which the bitmap should be created.
+ *
+ * @return HBITMAP: handle to the bitmap created.
+ */
+
+BYTE* Gfx::m_p = nullptr;
+size_t Gfx::m_sAllocated = 0;
+
+HBITMAP Gfx::createRGBABitmap(const LONG cx, const LONG cy)
+{
+ BITMAPINFO dib = {0};
+
+ dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ dib.bmiHeader.biWidth = cx;
+ dib.bmiHeader.biHeight = -cy; // use a "topdown" bitmap (0,0 = left, top corner)
+ dib.bmiHeader.biPlanes = 1;
+ dib.bmiHeader.biBitCount = 32;
+ dib.bmiHeader.biCompression = BI_RGB;
+ return(CreateDIBSection(0, &dib, DIB_RGB_COLORS, NULL, NULL, 0 ));
+}
+
+/**
+ * initialize Direct2D, create the factory
+ */
+void Gfx::D2D_Init()
+{
+#ifdef _USE_D2D
+ HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
+#endif
+}
+
+void Gfx::D2D_Release()
+{
+#ifdef _USE_D2D
+ pD2DFactory->Release();
+#endif
+}
+
+void Gfx::deSaturate(HBITMAP hBitmap, bool fReduceContrast)
+{
+ BITMAP bmp;
+ DWORD dwLen;
+ BYTE bMin = 255, bMax = 0, bRamp = 0, bMaxAdjust, bMinAdjust;
+
+ int x, y;
+
+ GetObject(hBitmap, sizeof(bmp), &bmp);
+
+ if (bmp.bmBitsPixel != 32)
+ return;
+
+ dwLen = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8);
+ if (dwLen > m_sAllocated) {
+ m_p = (BYTE *)realloc(m_p, dwLen);
+ m_sAllocated = dwLen;
+ }
+ memset(m_p, 0, dwLen);
+
+ GetBitmapBits(hBitmap, dwLen, m_p);
+
+ if(fReduceContrast) {
+ for (y = 0; y < bmp.bmHeight; ++y) {
+ BYTE *px = m_p + bmp.bmWidth * 4 * y;
+
+ for (x = 0; x < bmp.bmWidth; ++x) {
+ BYTE avg = (px[0] + px[1] + px[2]) / 3;
+ bMin = min(avg, bMin);
+ bMax = max(avg, bMax);
+ px += 4;
+ }
+ }
+ bRamp = (bMax + bMin) / 2;
+ bMaxAdjust = (bMax - bRamp) / 2;
+ bMinAdjust = (bRamp - bMin) / 2;
+ }
+ for (y = 0; y < bmp.bmHeight; ++y) {
+ BYTE *px = m_p + bmp.bmWidth * 4 * y;
+
+ for (x = 0; x < bmp.bmWidth; ++x) {
+ BYTE avg = (px[0] + px[1] + px[2]) / 3;
+ //if(fReduceContrast)
+ // avg = (avg < bRamp ? avg + bMinAdjust : avg - bMaxAdjust);
+ px[0] = px[1] = px[2] = avg;
+ px += 4;
+ }
+ }
+ SetBitmapBits(hBitmap, bmp.bmWidth * bmp.bmHeight * 4, m_p);
+}
+
+void Gfx::setBitmapAlpha(HBITMAP hBitmap, BYTE bAlpha)
+{
+ BITMAP bmp;
+ DWORD dwLen;
+ int x, y;
+
+ GetObject(hBitmap, sizeof(bmp), &bmp);
+
+ if (bmp.bmBitsPixel != 32)
+ return;
+
+ dwLen = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8);
+ if (dwLen > m_sAllocated) {
+ m_p = (BYTE *)realloc(m_p, dwLen);
+ m_sAllocated = dwLen;
+ }
+ memset(m_p, 0, dwLen);
+
+ GetBitmapBits(hBitmap, dwLen, m_p);
+
+ for (y = 0; y < bmp.bmHeight; ++y) {
+ BYTE *px = m_p + bmp.bmWidth * 4 * y;
+
+ for (x = 0; x < bmp.bmWidth; ++x) {
+ px[3] = bAlpha;
+ px += 4;
+ }
+ }
+ SetBitmapBits(hBitmap, bmp.bmWidth * bmp.bmHeight * 4, m_p);
+}
+
+/**
+ * render text using UxTheme (vista+) DrawTextEx() API
+ * @param hdc device context
+ * @param hTheme a valid theme handle
+ * @param szText text to draw
+ * @param rc rectangle where to draw
+ * @param dtFlags flags (same as DrawText())
+ * @param iGlowSize glow size if we want glow, if 0 use solid color
+ * @param clr color to use
+ * @param fForceAero force using composited text with glow
+ * @return return value of DrawText()
+ */
+int Gfx::renderText(HDC hdc, HANDLE hTheme, const TCHAR *szText, RECT *rc, DWORD dtFlags, const int iGlowSize, int length, bool fForceAero)
+{
+ if(hTheme || fForceAero) {
+ DTTOPTS dto = {0};
+ dto.dwSize = sizeof(dto);
+ if(iGlowSize && (cfg::isAero || fForceAero)) {
+ dto.iGlowSize = iGlowSize;
+ dto.dwFlags = DTT_COMPOSITED|DTT_GLOWSIZE;
+ }
+ else {
+ dto.dwFlags = DTT_TEXTCOLOR|DTT_COMPOSITED;//|DTT_SHADOWTYPE|DTT_SHADOWOFFSET|DTT_SHADOWCOLOR|DTT_BORDERSIZE|DTT_BORDERCOLOR;
+ dto.crText = txtColor;
+ }
+ dto.iBorderSize = 10;
+ return(Api::pfnDrawThemeTextEx(hTheme, hdc, BP_PUSHBUTTON, PBS_NORMAL, szText, length, dtFlags, rc, &dto));
+ }
+ else {
+ ::SetTextColor(hdc, txtColor);
+ return(::DrawText(hdc, szText, -1, rc, dtFlags));
+ }
+}
+
+void Gfx::preMultiply(HBITMAP hBitmap, int mode)
+{
+ DWORD dwLen;
+ int width, height, x, y;
+ BITMAP bmp;
+ BYTE alpha;
+
+ GetObject(hBitmap, sizeof(bmp), &bmp);
+ width = bmp.bmWidth;
+ height = bmp.bmHeight;
+ dwLen = width * height * 4;
+ if (dwLen > m_sAllocated) {
+ m_p = (BYTE *)realloc(m_p, dwLen);
+ m_sAllocated = dwLen;
+ }
+ if(m_p) {
+ GetBitmapBits(hBitmap, dwLen, m_p);
+ for (y = 0; y < height; ++y) {
+ BYTE *px = m_p + width * 4 * y;
+
+ for (x = 0; x < width; ++x) {
+ if(mode) {
+ alpha = px[3];
+ px[0] = px[0] * alpha/255;
+ px[1] = px[1] * alpha/255;
+ px[2] = px[2] * alpha/255;
+ }
+ else
+ px[3] = 255;
+ px += 4;
+ }
+ }
+ dwLen = SetBitmapBits(hBitmap, dwLen, m_p);
+ }
+}
+
+/**
+ * render a image item on the given target surface.
+ *
+ * @param hdc target HDC
+ * @param item image item
+ * @param rc target rectangle (client coordinates)
+ */
+void __fastcall Gfx::renderImageItem(HDC hdc, TImageItem *item, RECT *rc)
+{
+ BYTE l = item->bLeft, r = item->bRight, t = item->bTop, b = item->bBottom;
+ LONG width = rc->right - rc->left;
+ LONG height = rc->bottom - rc->top;
+ BOOL isGlyph = (item->dwFlags & IMAGE_GLYPH) && Skin::glyphItem;
+ HDC hdcSrc = isGlyph ? Skin::glyphItem->hdc : item->hdc;
+ LONG srcOrigX = isGlyph ? item->glyphMetrics[0] : 0;
+ LONG srcOrigY = isGlyph ? item->glyphMetrics[1] : 0;
+
+ if(item->dwFlags & IMAGE_FLAG_DIVIDED) {
+ // top 3 items
+
+ Api::pfnAlphaBlend(hdc, rc->left, rc->top, l, t, hdcSrc, srcOrigX, srcOrigY, l, t, item->bf);
+ Api::pfnAlphaBlend(hdc, rc->left + l, rc->top, width - l - r, t, hdcSrc, srcOrigX + l, srcOrigY, item->inner_width, t, item->bf);
+ Api::pfnAlphaBlend(hdc, rc->right - r, rc->top, r, t, hdcSrc, srcOrigX + (item->width - r), srcOrigY, r, t, item->bf);
+ // middle 3 items
+
+ Api::pfnAlphaBlend(hdc, rc->left, rc->top + t, l, height - t - b, hdcSrc, srcOrigX, srcOrigY + t, l, item->inner_height, item->bf);
+
+ if(item->dwFlags & IMAGE_FILLSOLID && item->fillBrush) {
+ RECT rcFill;
+ rcFill.left = rc->left + l; rcFill.top = rc->top +t;
+ rcFill.right = rc->right - r; rcFill.bottom = rc->bottom - b;
+ FillRect(hdc, &rcFill, item->fillBrush);
+ }
+ else
+ Api::pfnAlphaBlend(hdc, rc->left + l, rc->top + t, width - l - r, height - t - b, hdcSrc, srcOrigX + l, srcOrigY + t, item->inner_width, item->inner_height, item->bf);
+
+ Api::pfnAlphaBlend(hdc, rc->right - r, rc->top + t, r, height - t - b, hdcSrc, srcOrigX + (item->width - r), srcOrigY + t, r, item->inner_height, item->bf);
+
+ // bottom 3 items
+
+ Api::pfnAlphaBlend(hdc, rc->left, rc->bottom - b, l, b, hdcSrc, srcOrigX, srcOrigY + (item->height - b), l, b, item->bf);
+ Api::pfnAlphaBlend(hdc, rc->left + l, rc->bottom - b, width - l - r, b, hdcSrc, srcOrigX + l, srcOrigY + (item->height - b), item->inner_width, b, item->bf);
+ Api::pfnAlphaBlend(hdc, rc->right - r, rc->bottom - b, r, b, hdcSrc, srcOrigX + (item->width - r), srcOrigY + (item->height - b), r, b, item->bf);
+ }
+ else {
+ switch(item->bStretch) {
+ case IMAGE_STRETCH_H:
+ // tile image vertically, stretch to width
+ {
+ LONG top = rc->top;
+
+ do {
+ if(top + item->height <= rc->bottom) {
+ Api::pfnAlphaBlend(hdc, rc->left, top, width, item->height, hdcSrc, srcOrigX, srcOrigY, item->width, item->height, item->bf);
+ top += item->height;
+ }
+ else {
+ Api::pfnAlphaBlend(hdc, rc->left, top, width, rc->bottom - top, hdcSrc, srcOrigX, srcOrigY, item->width, rc->bottom - top, item->bf);
+ break;
+ }
+ } while (TRUE);
+ break;
+ }
+ case IMAGE_STRETCH_V:
+ // tile horizontally, stretch to height
+ {
+ LONG left = rc->left;
+
+ do {
+ if(left + item->width <= rc->right) {
+ Api::pfnAlphaBlend(hdc, left, rc->top, item->width, height, hdcSrc, srcOrigX, srcOrigY, item->width, item->height, item->bf);
+ left += item->width;
+ }
+ else {
+ Api::pfnAlphaBlend(hdc, left, rc->top, rc->right - left, height, hdcSrc, srcOrigX, srcOrigY, rc->right - left, item->height, item->bf);
+ break;
+ }
+ } while (TRUE);
+ break;
+ }
+ case IMAGE_STRETCH_B:
+ // stretch the image in both directions...
+ Api::pfnAlphaBlend(hdc, rc->left, rc->top, width, height, hdcSrc, srcOrigX, srcOrigY, item->width, item->height, item->bf);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * colorize an image item (both standalone items with their own bitmap and glyph items).
+ *
+ * @param item image item to colorize
+ * @param clr color to use (note: BGRA format required, although, alpha is ignored)
+ * @param hue hue adjustment (in degrees, -180 .. +180
+ * @param saturation scalar value (0.0 ... 1.0)
+ * @param value scalar value (0.0 ... 1.0)
+ *
+ * note: this isn't performance critical as it only runs at skin loading time or when
+ * the user changes colorization options, never during rendering.
+ *
+ * if clr == 0, hsv transformation will be applied, otherwise it's rgb colorization.
+ */
+void Gfx::colorizeGlyph(TImageItem *item, const COLORREF clr, float hue, float saturation, float value)
+{
+ LONG stride = 0, line, pixel;
+ HBITMAP hBitmap = 0;
+ LONG x, y, x1, y1;
+ BITMAP bmp = {0};
+ DWORD dwLen;
+ BYTE* pOrig, *pLine, alpha;
+ float v_s_u = 0, v_s_w = 0, r = 0, g = 0, b = 0;
+
+ if(0 == clr) { // do hsv transformation
+ v_s_u = value * saturation * cos(hue * M_PI/180);
+ v_s_w = value * saturation * sin(hue * M_PI/180);
+ }
+ else { // rgb colorization
+ BYTE rValue = GetRValue(clr);
+ BYTE gValue = GetGValue(clr);
+ BYTE bValue = GetBValue(clr);
+
+ r = (float)rValue / 2.55;
+ g = (float)gValue / 2.55;
+ b = (float)bValue / 2.55;
+ }
+ if(item) {
+ /*
+ * colorize a rectangular glyph
+ */
+ if(item->dwFlags & IMAGE_GLYPH) {
+ hBitmap = Skin::glyphItem->hbm;
+ x = item->glyphMetrics[0];
+ y = item->glyphMetrics[1];
+ x1 = x + item->glyphMetrics[2] - 1;
+ y1 = y + item->glyphMetrics[3] - 1;
+
+ GetObject(hBitmap, sizeof(bmp), &bmp);
+
+ if (bmp.bmBitsPixel != 32)
+ return;
+
+ dwLen = bmp.bmWidth * bmp.bmHeight * 4;
+ if (dwLen > m_sAllocated) {
+ m_p = (BYTE *)realloc(m_p, dwLen);
+ dwLen = (DWORD)m_sAllocated;
+ }
+ memset(m_p, 0, dwLen);
+ pOrig = m_p;
+ GetBitmapBits(hBitmap, dwLen, m_p);
+
+ stride = bmp.bmWidthBytes;
+
+ m_p += ((y * stride) + (4 * x));
+
+ for(line = y; line <= y1; line++) {
+ pLine = m_p;
+ for(pixel = x; pixel <= x1; pixel++) {
+ alpha = m_p[3];
+ if(alpha > 0) {
+ if(0 == clr)
+ hsvTransformPixel(m_p, value, v_s_u, v_s_w, alpha);
+ else
+ rgbTransformPixel(m_p, r, g, b, alpha);
+ }
+ m_p += 4;
+ }
+ m_p = pLine + stride;
+ }
+ SetBitmapBits(hBitmap, dwLen, pOrig);
+ }
+ else if (item->hbm) {
+ GetObject(item->hbm, sizeof(bmp), &bmp);
+ if (bmp.bmBitsPixel != 32)
+ return;
+
+ dwLen = bmp.bmWidth * bmp.bmHeight * 4;
+ if (dwLen > m_sAllocated) {
+ m_p = (BYTE *)realloc(m_p, dwLen);
+ m_sAllocated = dwLen;
+ }
+ memset(m_p, 0, dwLen);
+ pOrig = m_p;
+ GetBitmapBits(item->hbm, dwLen, m_p);
+
+ for(pixel = 0; pixel < (bmp.bmWidth * bmp.bmHeight); pixel++) {
+ alpha = m_p[3];
+ if(alpha > 0) {
+ if(0 == clr)
+ hsvTransformPixel(m_p, value, v_s_u, v_s_w, alpha);
+ else
+ rgbTransformPixel(m_p, r, g, b, alpha);
+ }
+ m_p += 4;
+ }
+ SetBitmapBits(item->hbm, dwLen, pOrig);
+ }
+ }
+}