]> git.sesse.net Git - vlc/blob - modules/gui/skins2/win32/win32_graphics.cpp
9e2cbe517bcc38f7f0b720e3b4895430a9171d70
[vlc] / modules / gui / skins2 / win32 / win32_graphics.cpp
1 /*****************************************************************************
2  * win32_graphics.cpp
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id$
6  *
7  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
8  *          Olivier Teulière <ipkiss@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 #ifdef WIN32_SKINS
26
27 #define WINVER 0x500
28 #ifndef AC_SRC_ALPHA
29 #define AC_SRC_ALPHA 1
30 #endif
31
32 #include "win32_factory.hpp"
33 #include "win32_graphics.hpp"
34 #include "win32_window.hpp"
35 #include "../src/generic_bitmap.hpp"
36
37 Win32Graphics::Win32Graphics( intf_thread_t *pIntf, int width, int height ):
38     OSGraphics( pIntf ), m_width( width ), m_height( height ), m_hDC( NULL )
39 {
40     HBITMAP hBmp;
41     HDC hDC = GetDC( NULL );
42     hBmp = CreateCompatibleBitmap( hDC, m_width, m_height );
43     ReleaseDC( NULL, hDC );
44
45     m_hDC = CreateCompatibleDC( NULL );
46     SelectObject( m_hDC, hBmp );
47     DeleteObject( hBmp );
48
49     // Create the mask
50     m_mask = CreateRectRgn( 0, 0, 0, 0 );
51 }
52
53
54 Win32Graphics::~Win32Graphics()
55 {
56     DeleteDC( m_hDC );
57     DeleteObject( m_mask );
58 }
59
60
61 void Win32Graphics::clear()
62 {
63     // Clear the transparency mask
64     DeleteObject( m_mask );
65     m_mask = CreateRectRgn( 0, 0, 0, 0 );
66 }
67
68
69 void Win32Graphics::drawBitmap( const GenericBitmap &rBitmap,
70                                 int xSrc, int ySrc, int xDest, int yDest,
71                                 int width, int height )
72 {
73     // Get the bitmap size if necessary
74     if( width == -1 )
75     {
76         width = rBitmap.getWidth();
77     }
78     if( height == -1 )
79     {
80         height = rBitmap.getHeight();
81     }
82
83     if( xDest + width > m_width || yDest + height > m_height )
84     {
85         msg_Err( getIntf(), "Bitmap too large !" );
86         return;
87     }
88
89     // Get a buffer on the image data
90     uint8_t *pBmpData = rBitmap.getData();
91     if( pBmpData == NULL )
92     {
93         // Nothing to draw
94         return;
95     }
96
97     void *pBits;     // pointer to DIB section
98     // Fill a BITMAPINFO structure
99     BITMAPINFO bmpInfo;
100     memset( &bmpInfo, 0, sizeof( bmpInfo ) );
101     bmpInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
102     bmpInfo.bmiHeader.biWidth = width;
103     bmpInfo.bmiHeader.biHeight = -height;
104     bmpInfo.bmiHeader.biPlanes = 1;
105     bmpInfo.bmiHeader.biBitCount = 32;
106     bmpInfo.bmiHeader.biCompression = BI_RGB;
107     bmpInfo.bmiHeader.biSizeImage = width * height * 4;
108
109     // Create a DIB (Device Independant Bitmap) and associate it with
110     // a temporary DC
111     HDC hDC = CreateCompatibleDC( m_hDC );
112     HBITMAP hBmp = CreateDIBSection( hDC, &bmpInfo, DIB_RGB_COLORS,
113                                      &pBits, NULL, 0 );
114     SelectObject( hDC, hBmp );
115
116     // Mask for transparency
117     HRGN mask = CreateRectRgn( 0, 0, 0, 0 );
118
119     // Skip the first lines of the image
120     pBmpData += 4 * ySrc * rBitmap.getWidth();
121
122     // Copy the bitmap on the image and compute the mask
123     for( int y = 0; y < height; y++ )
124     {
125         // Skip uninteresting bytes at the beginning of the line
126         pBmpData += 4 * xSrc;
127         // Flag to say whether the previous pixel on the line was visible
128         bool wasVisible = false;
129         // Beginning of the current visible segment on the line
130         int visibleSegmentStart = 0;
131         for( int x = 0; x < width; x++ )
132         {
133             uint8_t b = *(pBmpData++);
134             uint8_t g = *(pBmpData++);
135             uint8_t r = *(pBmpData++);
136             uint8_t a = *(pBmpData++);
137
138             // Draw the pixel
139             // Note: the colours are multiplied by a/255, because of the
140             // algorithm used by Windows for the AlphaBlending
141             ((UINT32 *)pBits)[x + y * width] =
142                 (a << 24) | (((r * a) >> 8) << 16) |
143                             (((g * a) >> 8) << 8) |
144                              ((b * a) >> 8);
145
146             if( a > 0 )
147             {
148                 // Pixel is visible
149                 if( ! wasVisible )
150                 {
151                     // Beginning of a visible segment
152                     visibleSegmentStart = x;
153                 }
154                 wasVisible = true;
155             }
156             else
157             {
158                 // Pixel is transparent
159                 if( wasVisible )
160                 {
161                     // End of a visible segment: add it to the mask
162                     addSegmentInRegion( mask, visibleSegmentStart, x, y );
163                 }
164                 wasVisible = false;
165             }
166         }
167         if( wasVisible )
168         {
169             // End of a visible segment: add it to the mask
170             addSegmentInRegion( mask, visibleSegmentStart, width, y );
171         }
172         // Skip uninteresting bytes at the end of the line
173         pBmpData += 4 * (rBitmap.getWidth() - width - xSrc);
174     }
175
176     // Apply the mask to the internal DC
177     OffsetRgn( mask, xDest, yDest );
178     SelectClipRgn( m_hDC, mask );
179
180     BLENDFUNCTION bf;      // structure for alpha blending
181     bf.BlendOp = AC_SRC_OVER;
182     bf.BlendFlags = 0;
183     bf.SourceConstantAlpha = 0xff;  // don't use constant alpha
184     bf.AlphaFormat = AC_SRC_ALPHA;
185
186     // Blend the image onto the internal DC
187     BOOL (WINAPI *AlphaBlend)( HDC, int, int, int, int, HDC, int, int,
188                                int, int, BLENDFUNCTION );
189     AlphaBlend = ((Win32Factory*)OSFactory::instance( getIntf() ))->AlphaBlend;
190     if( AlphaBlend &&
191         !AlphaBlend( m_hDC, xDest, yDest, width, height, hDC, 0, 0,
192                      width, height, bf ) )
193     {
194         msg_Err( getIntf(), "AlphaBlend() failed" );
195     }
196     else if( !AlphaBlend )
197     {
198         // Copy the image onto the internal DC
199         BitBlt( m_hDC, xDest, yDest, width, height, hDC, 0, 0, SRCCOPY );
200     }
201
202     // Add the bitmap mask to the global graphics mask
203     CombineRgn( m_mask, m_mask, mask, RGN_OR );
204
205     // Do cleanup
206     DeleteObject( hBmp );
207     DeleteObject( mask );
208     DeleteDC( hDC );
209 }
210
211
212 void Win32Graphics::drawGraphics( const OSGraphics &rGraphics, int xSrc,
213                                   int ySrc, int xDest, int yDest, int width,
214                                   int height )
215 {
216     if( width == -1 )
217     {
218         width = rGraphics.getWidth();
219     }
220     if( height == -1 )
221     {
222         height = rGraphics.getHeight();
223     }
224
225     // Create the mask for transparency
226     HRGN mask = CreateRectRgn( xSrc, ySrc, xSrc + width, ySrc + height );
227     CombineRgn( mask, ((Win32Graphics&)rGraphics).getMask(), mask, RGN_AND );
228     OffsetRgn( mask, xDest - xSrc, yDest - ySrc );
229
230     // Copy the image
231     HDC srcDC = ((Win32Graphics&)rGraphics).getDC();
232     SelectClipRgn( m_hDC, mask );
233     BitBlt( m_hDC, xDest, yDest, width, height, srcDC, xSrc, ySrc, SRCCOPY );
234
235     // Add the source mask to the mask of the graphics
236     CombineRgn( m_mask, mask, m_mask, RGN_OR );
237     DeleteObject( mask );
238 }
239
240
241 void Win32Graphics::fillRect( int left, int top, int width, int height,
242                               uint32_t color )
243 {
244     // Update the mask with the rectangle area
245     HRGN newMask = CreateRectRgn( left, top, left + width, top + height );
246     CombineRgn( m_mask, m_mask, newMask, RGN_OR );
247     SelectClipRgn( m_hDC, m_mask );
248     DeleteObject( newMask );
249
250     // Create a brush with the color
251     int red = (color & 0xff0000) >> 16;
252     int green = (color & 0xff00) >> 8;
253     int blue = color & 0xff;
254     HBRUSH hBrush = CreateSolidBrush( RGB( red, green, blue ) );
255
256     // Draw the rectangle
257     RECT r;
258     r.left = left;
259     r.top = top;
260     r.right = left + width;
261     r.bottom = top + height;
262     FillRect( m_hDC, &r, hBrush );
263     DeleteObject( hBrush );
264 }
265
266
267 void Win32Graphics::drawRect( int left, int top, int width, int height,
268                               uint32_t color )
269 {
270     // Update the mask with the rectangle
271     HRGN l1 = CreateRectRgn( left, top, left + width, top + 1 );
272     HRGN l2 = CreateRectRgn( left + width - 1, top,
273                              left + width, top + height );
274     HRGN l3 = CreateRectRgn( left, top + height - 1,
275                              left + width, top + height );
276     HRGN l4 = CreateRectRgn( left, top, left + 1, top + height );
277     CombineRgn( m_mask, m_mask, l1, RGN_OR );
278     CombineRgn( m_mask, m_mask, l2, RGN_OR );
279     CombineRgn( m_mask, m_mask, l3, RGN_OR );
280     CombineRgn( m_mask, m_mask, l4, RGN_OR );
281     DeleteObject( l1 );
282     DeleteObject( l2 );
283     DeleteObject( l3 );
284     DeleteObject( l4 );
285
286     SelectClipRgn( m_hDC, m_mask );
287
288     // Create a pen with the color
289     int red = (color & 0xff0000) >> 16;
290     int green = (color & 0xff00) >> 8;
291     int blue = color & 0xff;
292     HPEN hPen = CreatePen( PS_SOLID, 0, RGB( red, green, blue ) );
293     SelectObject( m_hDC, hPen );
294
295     // Draw the rectangle
296     MoveToEx( m_hDC, left, top, NULL );
297     LineTo( m_hDC, left + width - 1, top );
298     LineTo( m_hDC, left + width - 1, top + height - 1 );
299     LineTo( m_hDC, left, top + height - 1 );
300     LineTo( m_hDC, left, top );
301
302     // Delete the pen
303     DeleteObject( hPen );
304 }
305
306
307 void Win32Graphics::applyMaskToWindow( OSWindow &rWindow )
308 {
309     // Get window handle
310     HWND hWnd = ((Win32Window&)rWindow).getHandle();
311
312     // Apply the mask
313     // We need to copy the mask, because SetWindowRgn modifies it in our back
314     HRGN mask = CreateRectRgn( 0, 0, 0, 0 );
315     CombineRgn( mask, m_mask, NULL, RGN_COPY );
316     SetWindowRgn( hWnd, mask, TRUE );
317 }
318
319
320 void Win32Graphics::copyToWindow( OSWindow &rWindow, int xSrc, int ySrc,
321                                   int width, int height, int xDest, int yDest )
322 {
323     // Initialize painting
324     HWND hWnd = ((Win32Window&)rWindow).getHandle();
325     HDC wndDC = GetWindowDC( hWnd );
326     HDC srcDC = m_hDC;
327
328     // Draw image on window
329     BitBlt( wndDC, xDest, yDest, width, height, srcDC, xSrc, ySrc, SRCCOPY );
330
331     // Release window device context
332     ReleaseDC( hWnd, wndDC );
333 }
334
335
336 bool Win32Graphics::hit( int x, int y ) const
337 {
338     return PtInRegion( m_mask, x, y );
339 }
340
341
342 void Win32Graphics::addSegmentInRegion( HRGN &rMask, int start,
343                                         int end, int line )
344 {
345     HRGN buffer = CreateRectRgn( start, line, end, line + 1 );
346     CombineRgn( rMask, buffer, rMask, RGN_OR );
347     DeleteObject( buffer );
348 }
349
350 #endif