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