diff options
author | Tobias Weimer <wishmaster51@googlemail.com> | 2015-07-12 14:10:16 +0000 |
---|---|---|
committer | Tobias Weimer <wishmaster51@googlemail.com> | 2015-07-12 14:10:16 +0000 |
commit | f4ce2b5c214cce406dbd7a73dc7f35ae409546ad (patch) | |
tree | 533cc821ffc9c5664c075930be6a40fde9593aba /plugins/Clist_ng/INCLUDE/gfx.h | |
parent | 71a88c6d8c4578ca24e02a5c6f4860c206e7c6da (diff) |
Clist NG:
Commit of CList NG by silvercircle from https://github.com/silvercircle/miranda-ng
This is based on clist_nicer and Anti-Grain Geometry: http://www.antigrain.com/
This is the first version that actually compiles.
Do NOT use it in production environment!
git-svn-id: http://svn.miranda-ng.org/main/trunk@14543 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/Clist_ng/INCLUDE/gfx.h')
-rw-r--r-- | plugins/Clist_ng/INCLUDE/gfx.h | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/plugins/Clist_ng/INCLUDE/gfx.h b/plugins/Clist_ng/INCLUDE/gfx.h new file mode 100644 index 0000000000..10b4da7e19 --- /dev/null +++ b/plugins/Clist_ng/INCLUDE/gfx.h @@ -0,0 +1,501 @@ +/* +* 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.h 137 2010-10-16 21:03:23Z silvercircle $ +* +* low level painting functions - manage DCs, render skin image glyphs, +* text and backbuffer drawing. +* +* provide wrappers for AGG render pipelines +* +*/ + +#ifndef __GFX_H_ +#define __GFX_H_ + +#define M_PI 3.14159265358979323846 + +BYTE __forceinline percent_to_byte(UINT32 percent) +{ + return(BYTE) ((FLOAT) (((FLOAT) percent) / 100) * 255); +} + +class AGGBaseContext +{ +public: + /** + * CTOR - construct AGGBaseContext and attach it to a bitmap + * @param hdc device context (not really needed) + * @param hbm bitmap handle + * @return + */ + AGGBaseContext(HDC hdc, HBITMAP hbm) + { + m_hdc= hdc; + attach(hbm); + } + + /** + * construct AGGBaseContext and attach it to a in-memory bitmap used + * by a BufferedPaint operation + * @param hdc device context (not really required) + * @param rgbq RGBQUAD* memory buffer with bitmap bits in BGRA32 format + * @param width bitmap width (can be larger than the actual painting rectangle) + * @param height bitmap height + * @return + */ + AGGBaseContext(HDC hdc, RGBQUAD* rgbq, LONG width, LONG height) + { + m_hdc = hdc; + attach(rgbq, width, height); + } + + /** + * construct an empty AGGBase context and assign the optional HDC + * must be attached to a memory bitmap later by using one of the + * attach() methods. + * @param hdc device context + * @return + */ + AGGBaseContext(HDC hdc) { m_hdc = hdc; } + + /** + * attach the AGG rendering buffer to a memory bitmap, selected into a HDC for + * off-screen drawing. + * @param hbm bitmap to use for rendering. + */ + void attach(HBITMAP hbm) + { + BITMAP bm; + ::GetObject(hbm, sizeof(bm), &bm); + + m_rbuf.attach((unsigned char*)bm.bmBits, bm.bmWidth, bm.bmHeight, bm.bmWidthBytes); + } + + /** + * attach the AGG rendering buffer to a RGBQUAD array (as returned by + * GetBufferedPaintBits() API + * + * @param rgbq pointer to memory buffer holding the bitmap bits + * @param width width (in pixels, always properly aligned) + * @param height height (in pixels) + */ + void attach(RGBQUAD* rgbq, LONG width, LONG height) + { + m_rbuf.attach((unsigned char *)rgbq, width, height, width * 4); + } + + HDC m_hdc; + agg::rendering_buffer m_rbuf; + + ~AGGBaseContext() {} +}; + +class AGGContext +{ +public: + AGGContext(HBITMAP hbm) + { + BITMAP bm; + ::GetObject(hbm, sizeof(bm), &bm); + + m_rbuf.attach((unsigned char*)bm.bmBits, bm.bmWidth, bm.bmHeight, bm.bmWidthBytes); + initPipeline(); + }; + + AGGContext(RGBQUAD* rgbq, LONG width, LONG height) + { + m_rbuf.attach((unsigned char *)rgbq, width, height, width * 4); + initPipeline(); + } + + AGGContext() {} + + void initPipeline() + { + m_pixfmt.attach(m_rbuf); + m_rbase.attach(m_pixfmt); + m_solid_renderer.attach(m_rbase); + m_span_interpolator = agg::span_interpolator_linear<>(m_gradient_trans); + m_span_gradient = span_gradient_t(m_span_interpolator, m_gradient_func, m_color_array, 0, 200); + m_gradient_renderer.attach(m_rbase, m_span_allocator, m_span_gradient); + } + + void attach(HBITMAP hbm) + { + BITMAP bm; + ::GetObject(hbm, sizeof(bm), &bm); + + m_rbuf.attach((unsigned char*)bm.bmBits, bm.bmWidth, bm.bmHeight, bm.bmWidthBytes); + initPipeline(); + } + + void attach(RGBQUAD* rgbq, LONG width, LONG height, LONG stride) + { + m_rbuf.attach((unsigned char *)rgbq, width, height, stride); + initPipeline(); + } + + /* + * fill the color array we need for the gradient with + */ + template<class Array> static void fill_color_array(Array& arr, agg::rgba8& begin, agg::rgba8& end) + { + unsigned size = arr.size(); + + for(unsigned i = 0; i < size; ++i) + arr[i] = begin.gradient(end, i / double(size)); + } + +public: + agg::rendering_buffer m_rbuf; + agg::pixfmt_bgra32 m_pixfmt; + agg::renderer_base<agg::pixfmt_bgra32> m_rbase; + + agg::renderer_scanline_aa_solid<agg::renderer_base<agg::pixfmt_bgra32> > m_solid_renderer; + typedef agg::span_gradient<agg::rgba8, agg::span_interpolator_linear<>, agg::gradient_x, agg::pod_auto_array<agg::rgba8, 256> > span_gradient_t; + typedef agg::span_allocator<agg::rgba8> span_allocator_t; + + agg::renderer_scanline_aa<agg::renderer_base<agg::pixfmt_bgra32>, span_allocator_t, span_gradient_t> m_gradient_renderer; + + span_allocator_t m_span_allocator; + span_gradient_t m_span_gradient; + agg::span_interpolator_linear<> m_span_interpolator; + agg::gradient_x m_gradient_func; + agg::pod_auto_array<agg::rgba8, 256> m_color_array; + agg::trans_affine m_gradient_trans; +}; + +class AGGPaintHelper +{ +public: + AGGPaintHelper(HDC hdc) + { + hdcMem = hdc; + aggctx = new AGGBaseContext(hdcMem); + } + + ~AGGPaintHelper() + { + delete aggctx; + }; + +public: + agg::rounded_rect* current_shape; + AGGBaseContext* aggctx; + HDC hdcMem; +}; + +class CLCPaintHelper : public AGGPaintHelper +{ +public: + CLCPaintHelper(const HWND hwndCLC, ClcData* clcdat, DWORD windowstyle, RECT* rc, int yFirst, int fontShift, int idx) : AGGPaintHelper(0) + { + hwnd = hwndCLC; + indent = 0; + dat = clcdat; + style = windowstyle; + clRect = rc; + y = yFirst; + index = idx; + bFirstNGdrawn = false; + groupCountsFontTopShift = fontShift; + isContactFloater = false; + } + + void setHDC(const HDC hdc) + { + hdcMem = hdc; + } + + virtual ~CLCPaintHelper() {}; + + void setFloater () { isContactFloater = true; } + void Paint (ClcGroup* group, ClcContact* contact, int rowHeight); + int drawAvatar (RECT *rc, ClcContact *contact, int y, WORD cstatus, int rowHeight); + HFONT changeToFont (const unsigned int id); + void setHotTrackColour (); + + int indent; + int y; + int index; + int fSelected; + HANDLE hTheme, hbp; + bool fAvatar, fSecondLine; + TDspOverride* dsp; + + HWND hwnd; + ClcData* dat; + DWORD style; + RECT* clRect; + bool bFirstNGdrawn; + int groupCountsFontTopShift; + bool isContactFloater; + + TStatusItem *sevencontact_pos, *soddcontact_pos, *sfirstitem, + *ssingleitem, *slastitem, *sfirstitem_NG, *ssingleitem_NG, *slastitem_NG; + +private: + int m_fontHeight; +}; + +class Gfx +{ +public: +#ifdef _USE_D2D + static ID2D1Factory* pD2DFactory; +#endif + static COLORREF txtColor; + //static ULONG_PTR gdiPlusToken; + //static Gdiplus::GdiplusStartupInput gdiPlusStartupInput; + +public: + static inline HANDLE initiateBufferedPaint (const HDC hdcSrc, RECT& rc, HDC& hdcOut); + static inline void finalizeBufferedPaint (HANDLE hbp, RECT *rc, BYTE alpha = 0); + static HBITMAP createRGBABitmap (const LONG cx, const LONG cy); + static inline void drawBGFromSurface (const HWND hwnd, const RECT& rc, HDC hdc); + static inline void renderSkinItem (HDC hdc, RECT* rc, TImageItem* item); + static inline void renderSkinItem (AGGPaintHelper *ph, TStatusItem *item, RECT* rc); + + static void setBitmapAlpha (HBITMAP hBitmap, BYTE bAlpha); + static void deSaturate (HBITMAP hBitmap, bool fReduceContrast = false); + static void preMultiply (HBITMAP hBitmap, int mode); + static void __fastcall renderImageItem (HDC hdc, TImageItem *item, RECT *rc); + static void colorizeGlyph (TImageItem *item, const COLORREF clr, float H, float S, float V); + + static inline void hsvTransformPixel (BYTE *p, float value, float vsu, float vsw, BYTE alpha); + static inline void rgbTransformPixel (BYTE *p, float r, float g, float b, BYTE alpha); + + static void D2D_Init (); + static void D2D_Release (); + + static inline void setTextColor (const COLORREF clr); + static inline COLORREF getTextColor (); + static int renderText (HDC hdc, HANDLE hTheme, const TCHAR *szText, RECT *rc, DWORD dtFlags, const int iGlowSize = 0, int length = -1, bool fForceAero = false); + static void shutDown() { if (m_p) free(m_p); } + + /** + * load a png image using miranda image load service. + * + * @param szFilename full path and filename of the image + * + * @return HBITMAP of the image loaded + */ + template<class T> static HBITMAP loadPNG(const T* szFilename) + { + HBITMAP hBitmap = 0; + DWORD dwFlags = 0; + + if(sizeof(T) > 1) + dwFlags = IMGL_WCHAR; + + hBitmap = (HBITMAP)CallService(MS_IMG_LOAD, (WPARAM)szFilename, dwFlags); + if(CALLSERVICE_NOTFOUND == (INT_PTR)hBitmap) { + hBitmap = 0; + throw(CRTException("Critical error while loading a skin", L"The image service plugin is not available")); + } + return(hBitmap); + } + + /* + * a generic buffer used by various things in the class Will only be realloc'd and grow when + * needed. Free'd on shutdown. It's primarily used by bitmap operations as temporary buffer + */ + static BYTE* m_p; + static size_t m_sAllocated; +}; + +/* + * some inlined functions + */ + +/** + * Initiate a buffered paint operation + * + * @param hdcSrc The source device context (usually obtained by BeginPaint()) + * @param rc RECT&: the target rectangle that receives the painting + * @param hdcOut HDC& (out) receives the buffered device context handle + * + * @return (HANDLE) buffered paint handle + */ +inline HANDLE Gfx::initiateBufferedPaint(const HDC hdcSrc, RECT& rc, HDC& hdcOut) +{ + HANDLE hbp = Api::pfnBeginBufferedPaint(hdcSrc, &rc, BPBF_TOPDOWNDIB, NULL, &hdcOut); + return(hbp); +} + +/** + * finalize buffered paint cycle and apply (if applicable) the global alpha value + * + * @param hbp HANDLE: handle of the buffered paint context + * @param rc RECT*: target rectangly where alpha value should be applied + */ +inline void Gfx::finalizeBufferedPaint(HANDLE hbp, RECT *rc, BYTE alpha) +{ + if(alpha > 0) + Api::pfnBufferedPaintSetAlpha(hbp, rc, alpha); + Api::pfnEndBufferedPaint(hbp, TRUE); +} + +/** + * blit the background from the back buffer surface (cfg::dat.hdcBg) to the + * client area of the child frame. + * @param hwnd child window handle + * @param rcCl child window client area + * @param hdc painting DC + */ +inline void Gfx::drawBGFromSurface(const HWND hwnd, const RECT& rcCl, HDC hdc) +{ + RECT rcMapped = rcCl; + + MapWindowPoints(hwnd, pcli->hwndContactList, (POINT *)&rcMapped, 2); + BitBlt(hdc, rcCl.left, rcCl.top, rcCl.right - rcCl.left, rcCl.bottom - rcCl.top, cfg::dat.hdcBg, + rcMapped.left, rcMapped.top, SRCCOPY); +} + +/** + * render a simply skin item (image item only, do not render the underlays) + * @param hdc device context + * @param rc target rectangle + * @param imageItem image item to render + */ +inline void Gfx::renderSkinItem(HDC hdc, RECT* rc, TImageItem *imageItem) +{ + if(imageItem) + renderImageItem(hdc, imageItem, rc); +} + +/** + * render a skin item with a possible underlay (gradient and corner + * shape) + * @param ph CLCPaintHelper* (clc painting context with AGG base context) + * @param item TStatusItem* (item to render) + * @param rc target rectangle + */ +inline void Gfx::renderSkinItem(AGGPaintHelper *ph, TStatusItem *item, RECT* rc) +{ + TImageItem *imageItem = item->imageItem; + + if (CLC::fInPaint && CLC::iHottrackItem) { + item = &Skin::statusItems[ID_EXTBKHOTTRACK]; + if (item->IGNORED == 0) + imageItem = item->imageItem; + CLC::fHottrackDone = true; + } + + if(!(item->dwFlags & S_ITEM_SKIP_UNDERLAY)) { + /* + * attach the item rendering pipeline to the AGG context rendering buffer + */ + item->pixfmt->attach(ph->aggctx->m_rbuf); + item->rbase->attach(*(item->pixfmt)); + if(item->dwFlags & AGG_USE_GRADIENT_X_RENDERER) { + item->span_gradient_x->d1(rc->left); + item->span_gradient_x->d2(rc->right); + } + else { + item->span_gradient_y->d1(rc->top); + item->span_gradient_y->d2(rc->bottom); + } + + /* + * for each rendering cycle, the first shape defines the final shape for this item + * this allows items like "first item of a group" or "last item of a group" define + * their own shapes - overlays like a selection or hottrack item will use the + * original shape and only render their own color(s). + */ + if(0 == ph->current_shape) + ph->current_shape = item->rect; + + ph->current_shape->rect(rc->left, rc->top, rc->right, rc->bottom); + + agg::rasterizer_scanline_aa<> r; + r.add_path(*(ph->current_shape)); + agg::scanline_p8 sl; + + if(item->dwFlags & AGG_USE_GRADIENT_X_RENDERER) + agg::render_scanlines(r, sl, *(item->gradient_renderer_x)); + else if(item->dwFlags & AGG_USE_GRADIENT_Y_RENDERER) + agg::render_scanlines(r, sl, *(item->gradient_renderer_y)); + else + agg::render_scanlines(r, sl, *(item->solid_renderer)); + } + if(imageItem && !(item->dwFlags & S_ITEM_SKIP_IMAGE)) + renderImageItem(ph->hdcMem, imageItem, rc); +} + +/** + * set our text color for Gfx::RenderText() - replaces GDI SetTextColor() for all + * cases where we are using DrawThemeTextEx() for full 32bit text rendering. + * @param clr new text color to use + */ +inline void Gfx::setTextColor(const COLORREF clr) +{ + txtColor = clr; +} + +inline COLORREF Gfx::getTextColor() +{ + return(txtColor); +} + +inline void Gfx::hsvTransformPixel(BYTE *p, float value, float v_s_u, float v_s_w, BYTE alpha) +{ + // ain't matrices beautiful? :) + + float r = (.299 * value +.701 * v_s_u +.168 * v_s_w) * p[2] + (.587 * value -.587 * v_s_u +.330 * v_s_w) * p[1] + (.114 * value -.114 * v_s_u -.497 * v_s_w) * p[0]; + float g = (.299 * value -.299 * v_s_u -.328 * v_s_w) * p[2] + (.587 * value +.413 * v_s_u +.035 * v_s_w) * p[1] + (.114 * value -.114 * v_s_u +.292 * v_s_w) * p[0]; + float b = (.299 * value -.3 * v_s_u +1.25 * v_s_w) * p[2]+ (.587* value -.588 * v_s_u -1.05 * v_s_w) * p[1] + (.114 * value +.886 * v_s_u -.203 * v_s_w) * p[0]; + + /* + * premultiply + */ + p[0] = (int)b * alpha/255; + p[1] = (int)g * alpha/255; + p[2] = (int)r * alpha/255; +} + +inline void Gfx::rgbTransformPixel(BYTE *p, float r, float g, float b, BYTE alpha) +{ + p[0] = (int)(p[0] + b) > 255 ? 255 : p[0] + b; + p[1] = (int)(p[1] + g) > 255 ? 255 : p[1] + g; + p[2] = (int)(p[2] + r) > 255 ? 255 : p[2] + r; + + p[0] = p[0] * alpha/255; + p[1] = p[1] * alpha/255; + p[2] = p[2] * alpha/255; +} + +#ifndef _XP_SUPPORT +#define INIT_PAINT(a, b, c) (hbp = Gfx::initiateBufferedPaint((a), (b), (c))) +#define FINALIZE_PAINT(a, b, c) Gfx::finalizeBufferedPaint((a), (b), (c)) +#else +#endif + +#endif /*__GFX_H_*/ + |