1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
7 * Authors: Cyril Deguet <asmax@via.ecp.fr>
8 * Olivier Teulière <ipkiss@via.ecp.fr>
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.
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.
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 *****************************************************************************/
29 #include "win32_factory.hpp"
30 #include "win32_graphics.hpp"
31 #include "win32_window.hpp"
32 #include "../src/generic_bitmap.hpp"
35 #define AC_SRC_ALPHA 1
38 Win32Graphics::Win32Graphics( intf_thread_t *pIntf, int width, int height ):
39 OSGraphics( pIntf ), m_width( width ), m_height( height ), m_hDC( NULL )
42 HDC hDC = GetDC( NULL );
43 hBmp = CreateCompatibleBitmap( hDC, m_width, m_height );
44 ReleaseDC( NULL, hDC );
46 m_hDC = CreateCompatibleDC( NULL );
47 SelectObject( m_hDC, hBmp );
51 m_mask = CreateRectRgn( 0, 0, 0, 0 );
55 Win32Graphics::~Win32Graphics()
58 DeleteObject( m_mask );
62 void Win32Graphics::clear( int xDest, int yDest, int width, int height )
64 if( width <= 0 || height <= 0 )
66 // Clear the transparency mask
67 DeleteObject( m_mask );
68 m_mask = CreateRectRgn( 0, 0, 0, 0 );
72 HRGN mask = CreateRectRgn( xDest, yDest,
73 xDest + width, yDest + height );
74 CombineRgn( m_mask, m_mask, mask, RGN_DIFF );
80 void Win32Graphics::drawBitmap( const GenericBitmap &rBitmap,
81 int xSrc, int ySrc, int xDest, int yDest,
82 int width, int height, bool blend )
84 // Get the bitmap size if necessary
87 width = rBitmap.getWidth();
91 height = rBitmap.getHeight();
94 if( xDest + width > m_width || yDest + height > m_height )
96 msg_Err( getIntf(), "Bitmap too large !" );
100 // Get a buffer on the image data
101 uint8_t *pBmpData = rBitmap.getData();
102 if( pBmpData == NULL )
108 void *pBits; // pointer to DIB section
109 // Fill a BITMAPINFO structure
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;
120 // Create a DIB (Device Independent Bitmap) and associate it with
122 HDC hDC = CreateCompatibleDC( m_hDC );
123 HBITMAP hBmp = CreateDIBSection( hDC, &bmpInfo, DIB_RGB_COLORS,
125 SelectObject( hDC, hBmp );
127 // Mask for transparency
128 HRGN mask = CreateRectRgn( 0, 0, 0, 0 );
130 // Skip the first lines of the image
131 pBmpData += 4 * ySrc * rBitmap.getWidth();
133 // Copy the bitmap on the image and compute the mask
134 for( int y = 0; y < height; y++ )
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++ )
144 uint8_t b = *(pBmpData++);
145 uint8_t g = *(pBmpData++);
146 uint8_t r = *(pBmpData++);
147 uint8_t a = *(pBmpData++);
150 ((UINT32 *)pBits)[x + y * width] =
151 (a << 24) | (r << 16) | (g << 8) | b;
158 // Beginning of a visible segment
159 visibleSegmentStart = x;
165 // Pixel is transparent
168 // End of a visible segment: add it to the mask
169 addSegmentInRegion( mask, visibleSegmentStart, x, y );
176 // End of a visible segment: add it to the mask
177 addSegmentInRegion( mask, visibleSegmentStart, width, y );
179 // Skip uninteresting bytes at the end of the line
180 pBmpData += 4 * (rBitmap.getWidth() - width - xSrc);
183 // Apply the mask to the internal DC
184 OffsetRgn( mask, xDest, yDest );
185 SelectClipRgn( m_hDC, mask );
187 BLENDFUNCTION bf; // structure for alpha blending
188 bf.BlendOp = AC_SRC_OVER;
190 bf.SourceConstantAlpha = 0xff; // don't use constant alpha
191 bf.AlphaFormat = AC_SRC_ALPHA;
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;
198 !AlphaBlend( m_hDC, xDest, yDest, width, height, hDC, 0, 0,
199 width, height, bf ) )
201 msg_Err( getIntf(), "AlphaBlend() failed" );
203 else if( !AlphaBlend )
205 // Copy the image onto the internal DC
206 BitBlt( m_hDC, xDest, yDest, width, height, hDC, 0, 0, SRCCOPY );
209 // Add the bitmap mask to the global graphics mask
210 CombineRgn( m_mask, m_mask, mask, RGN_OR );
213 DeleteObject( hBmp );
214 DeleteObject( mask );
219 void Win32Graphics::drawGraphics( const OSGraphics &rGraphics, int xSrc,
220 int ySrc, int xDest, int yDest, int width,
225 width = rGraphics.getWidth();
229 height = rGraphics.getHeight();
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 );
238 HDC srcDC = ((Win32Graphics&)rGraphics).getDC();
239 SelectClipRgn( m_hDC, mask );
240 BitBlt( m_hDC, xDest, yDest, width, height, srcDC, xSrc, ySrc, SRCCOPY );
242 // Add the source mask to the mask of the graphics
243 CombineRgn( m_mask, mask, m_mask, RGN_OR );
244 DeleteObject( mask );
248 void Win32Graphics::fillRect( int left, int top, int width, int height,
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 );
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 ) );
263 // Draw the rectangle
267 r.right = left + width;
268 r.bottom = top + height;
269 FillRect( m_hDC, &r, hBrush );
270 DeleteObject( hBrush );
274 void Win32Graphics::drawRect( int left, int top, int width, int height,
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 );
293 SelectClipRgn( m_hDC, m_mask );
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 );
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 );
310 DeleteObject( hPen );
314 void Win32Graphics::applyMaskToWindow( OSWindow &rWindow )
317 HWND hWnd = ((Win32Window&)rWindow).getHandle();
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 );
327 void Win32Graphics::copyToWindow( OSWindow &rWindow, int xSrc, int ySrc,
328 int width, int height, int xDest, int yDest )
330 // Initialize painting
331 HWND hWnd = ((Win32Window&)rWindow).getHandle();
332 HDC wndDC = GetDC( hWnd );
335 // Draw image on window
336 BitBlt( wndDC, xDest, yDest, width, height, srcDC, xSrc, ySrc, SRCCOPY );
338 // Release window device context
339 ReleaseDC( hWnd, wndDC );
343 bool Win32Graphics::hit( int x, int y ) const
345 return PtInRegion( m_mask, x, y ) != 0;
349 void Win32Graphics::addSegmentInRegion( HRGN &rMask, int start,
352 HRGN buffer = CreateRectRgn( start, line, end, line + 1 );
353 CombineRgn( rMask, buffer, rMask, RGN_OR );
354 DeleteObject( buffer );