Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

win32_graphics.cpp

00001 /*****************************************************************************
00002  * win32_graphics.cpp
00003  *****************************************************************************
00004  * Copyright (C) 2003 the VideoLAN team
00005  * $Id: win32_graphics.cpp 12041 2005-08-06 15:08:37Z asmax $
00006  *
00007  * Authors: Cyril Deguet     <[email protected]>
00008  *          Olivier Teulière <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 #ifdef WIN32_SKINS
00026 
00027 #define WINVER 0x500
00028 
00029 #include "win32_factory.hpp"
00030 #include "win32_graphics.hpp"
00031 #include "win32_window.hpp"
00032 #include "../src/generic_bitmap.hpp"
00033 
00034 #ifndef AC_SRC_ALPHA
00035 #define AC_SRC_ALPHA 1
00036 #endif
00037 
00038 Win32Graphics::Win32Graphics( intf_thread_t *pIntf, int width, int height ):
00039     OSGraphics( pIntf ), m_width( width ), m_height( height ), m_hDC( NULL )
00040 {
00041     HBITMAP hBmp;
00042     HDC hDC = GetDC( NULL );
00043     hBmp = CreateCompatibleBitmap( hDC, m_width, m_height );
00044     ReleaseDC( NULL, hDC );
00045 
00046     m_hDC = CreateCompatibleDC( NULL );
00047     SelectObject( m_hDC, hBmp );
00048     DeleteObject( hBmp );
00049 
00050     // Create the mask
00051     m_mask = CreateRectRgn( 0, 0, 0, 0 );
00052 }
00053 
00054 
00055 Win32Graphics::~Win32Graphics()
00056 {
00057     DeleteDC( m_hDC );
00058     DeleteObject( m_mask );
00059 }
00060 
00061 
00062 void Win32Graphics::clear()
00063 {
00064     // Clear the transparency mask
00065     DeleteObject( m_mask );
00066     m_mask = CreateRectRgn( 0, 0, 0, 0 );
00067 }
00068 
00069 
00070 void Win32Graphics::drawBitmap( const GenericBitmap &rBitmap,
00071                                 int xSrc, int ySrc, int xDest, int yDest,
00072                                 int width, int height, bool blend )
00073 {
00074     // Get the bitmap size if necessary
00075     if( width == -1 )
00076     {
00077         width = rBitmap.getWidth();
00078     }
00079     if( height == -1 )
00080     {
00081         height = rBitmap.getHeight();
00082     }
00083 
00084     if( xDest + width > m_width || yDest + height > m_height )
00085     {
00086         msg_Err( getIntf(), "Bitmap too large !" );
00087         return;
00088     }
00089 
00090     // Get a buffer on the image data
00091     uint8_t *pBmpData = rBitmap.getData();
00092     if( pBmpData == NULL )
00093     {
00094         // Nothing to draw
00095         return;
00096     }
00097 
00098     void *pBits;     // pointer to DIB section
00099     // Fill a BITMAPINFO structure
00100     BITMAPINFO bmpInfo;
00101     memset( &bmpInfo, 0, sizeof( bmpInfo ) );
00102     bmpInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
00103     bmpInfo.bmiHeader.biWidth = width;
00104     bmpInfo.bmiHeader.biHeight = -height;
00105     bmpInfo.bmiHeader.biPlanes = 1;
00106     bmpInfo.bmiHeader.biBitCount = 32;
00107     bmpInfo.bmiHeader.biCompression = BI_RGB;
00108     bmpInfo.bmiHeader.biSizeImage = width * height * 4;
00109 
00110     // Create a DIB (Device Independant Bitmap) and associate it with
00111     // a temporary DC
00112     HDC hDC = CreateCompatibleDC( m_hDC );
00113     HBITMAP hBmp = CreateDIBSection( hDC, &bmpInfo, DIB_RGB_COLORS,
00114                                      &pBits, NULL, 0 );
00115     SelectObject( hDC, hBmp );
00116 
00117     // Mask for transparency
00118     HRGN mask = CreateRectRgn( 0, 0, 0, 0 );
00119 
00120     // Skip the first lines of the image
00121     pBmpData += 4 * ySrc * rBitmap.getWidth();
00122 
00123     // Copy the bitmap on the image and compute the mask
00124     for( int y = 0; y < height; y++ )
00125     {
00126         // Skip uninteresting bytes at the beginning of the line
00127         pBmpData += 4 * xSrc;
00128         // Flag to say whether the previous pixel on the line was visible
00129         bool wasVisible = false;
00130         // Beginning of the current visible segment on the line
00131         int visibleSegmentStart = 0;
00132         for( int x = 0; x < width; x++ )
00133         {
00134             uint8_t b = *(pBmpData++);
00135             uint8_t g = *(pBmpData++);
00136             uint8_t r = *(pBmpData++);
00137             uint8_t a = *(pBmpData++);
00138 
00139             // Draw the pixel
00140             ((UINT32 *)pBits)[x + y * width] =
00141                 (a << 24) | (r << 16) | (g << 8) | b;
00142 
00143             if( a > 0 )
00144             {
00145                 // Pixel is visible
00146                 if( ! wasVisible )
00147                 {
00148                     // Beginning of a visible segment
00149                     visibleSegmentStart = x;
00150                 }
00151                 wasVisible = true;
00152             }
00153             else
00154             {
00155                 // Pixel is transparent
00156                 if( wasVisible )
00157                 {
00158                     // End of a visible segment: add it to the mask
00159                     addSegmentInRegion( mask, visibleSegmentStart, x, y );
00160                 }
00161                 wasVisible = false;
00162             }
00163         }
00164         if( wasVisible )
00165         {
00166             // End of a visible segment: add it to the mask
00167             addSegmentInRegion( mask, visibleSegmentStart, width, y );
00168         }
00169         // Skip uninteresting bytes at the end of the line
00170         pBmpData += 4 * (rBitmap.getWidth() - width - xSrc);
00171     }
00172 
00173     // Apply the mask to the internal DC
00174     OffsetRgn( mask, xDest, yDest );
00175     SelectClipRgn( m_hDC, mask );
00176 
00177     BLENDFUNCTION bf;      // structure for alpha blending
00178     bf.BlendOp = AC_SRC_OVER;
00179     bf.BlendFlags = 0;
00180     bf.SourceConstantAlpha = 0xff;  // don't use constant alpha
00181     bf.AlphaFormat = AC_SRC_ALPHA;
00182 
00183     // Blend the image onto the internal DC
00184     BOOL (WINAPI *AlphaBlend)( HDC, int, int, int, int, HDC, int, int,
00185                                int, int, BLENDFUNCTION );
00186     AlphaBlend = ((Win32Factory*)OSFactory::instance( getIntf() ))->AlphaBlend;
00187     if( AlphaBlend &&
00188         !AlphaBlend( m_hDC, xDest, yDest, width, height, hDC, 0, 0,
00189                      width, height, bf ) )
00190     {
00191         msg_Err( getIntf(), "AlphaBlend() failed" );
00192     }
00193     else if( !AlphaBlend )
00194     {
00195         // Copy the image onto the internal DC
00196         BitBlt( m_hDC, xDest, yDest, width, height, hDC, 0, 0, SRCCOPY );
00197     }
00198 
00199     // Add the bitmap mask to the global graphics mask
00200     CombineRgn( m_mask, m_mask, mask, RGN_OR );
00201 
00202     // Do cleanup
00203     DeleteObject( hBmp );
00204     DeleteObject( mask );
00205     DeleteDC( hDC );
00206 }
00207 
00208 
00209 void Win32Graphics::drawGraphics( const OSGraphics &rGraphics, int xSrc,
00210                                   int ySrc, int xDest, int yDest, int width,
00211                                   int height )
00212 {
00213     if( width == -1 )
00214     {
00215         width = rGraphics.getWidth();
00216     }
00217     if( height == -1 )
00218     {
00219         height = rGraphics.getHeight();
00220     }
00221 
00222     // Create the mask for transparency
00223     HRGN mask = CreateRectRgn( xSrc, ySrc, xSrc + width, ySrc + height );
00224     CombineRgn( mask, ((Win32Graphics&)rGraphics).getMask(), mask, RGN_AND );
00225     OffsetRgn( mask, xDest - xSrc, yDest - ySrc );
00226 
00227     // Copy the image
00228     HDC srcDC = ((Win32Graphics&)rGraphics).getDC();
00229     SelectClipRgn( m_hDC, mask );
00230     BitBlt( m_hDC, xDest, yDest, width, height, srcDC, xSrc, ySrc, SRCCOPY );
00231 
00232     // Add the source mask to the mask of the graphics
00233     CombineRgn( m_mask, mask, m_mask, RGN_OR );
00234     DeleteObject( mask );
00235 }
00236 
00237 
00238 void Win32Graphics::fillRect( int left, int top, int width, int height,
00239                               uint32_t color )
00240 {
00241     // Update the mask with the rectangle area
00242     HRGN newMask = CreateRectRgn( left, top, left + width, top + height );
00243     CombineRgn( m_mask, m_mask, newMask, RGN_OR );
00244     SelectClipRgn( m_hDC, m_mask );
00245     DeleteObject( newMask );
00246 
00247     // Create a brush with the color
00248     int red = (color & 0xff0000) >> 16;
00249     int green = (color & 0xff00) >> 8;
00250     int blue = color & 0xff;
00251     HBRUSH hBrush = CreateSolidBrush( RGB( red, green, blue ) );
00252 
00253     // Draw the rectangle
00254     RECT r;
00255     r.left = left;
00256     r.top = top;
00257     r.right = left + width;
00258     r.bottom = top + height;
00259     FillRect( m_hDC, &r, hBrush );
00260     DeleteObject( hBrush );
00261 }
00262 
00263 
00264 void Win32Graphics::drawRect( int left, int top, int width, int height,
00265                               uint32_t color )
00266 {
00267     // Update the mask with the rectangle
00268     HRGN l1 = CreateRectRgn( left, top, left + width, top + 1 );
00269     HRGN l2 = CreateRectRgn( left + width - 1, top,
00270                              left + width, top + height );
00271     HRGN l3 = CreateRectRgn( left, top + height - 1,
00272                              left + width, top + height );
00273     HRGN l4 = CreateRectRgn( left, top, left + 1, top + height );
00274     CombineRgn( m_mask, m_mask, l1, RGN_OR );
00275     CombineRgn( m_mask, m_mask, l2, RGN_OR );
00276     CombineRgn( m_mask, m_mask, l3, RGN_OR );
00277     CombineRgn( m_mask, m_mask, l4, RGN_OR );
00278     DeleteObject( l1 );
00279     DeleteObject( l2 );
00280     DeleteObject( l3 );
00281     DeleteObject( l4 );
00282 
00283     SelectClipRgn( m_hDC, m_mask );
00284 
00285     // Create a pen with the color
00286     int red = (color & 0xff0000) >> 16;
00287     int green = (color & 0xff00) >> 8;
00288     int blue = color & 0xff;
00289     HPEN hPen = CreatePen( PS_SOLID, 0, RGB( red, green, blue ) );
00290     SelectObject( m_hDC, hPen );
00291 
00292     // Draw the rectangle
00293     MoveToEx( m_hDC, left, top, NULL );
00294     LineTo( m_hDC, left + width - 1, top );
00295     LineTo( m_hDC, left + width - 1, top + height - 1 );
00296     LineTo( m_hDC, left, top + height - 1 );
00297     LineTo( m_hDC, left, top );
00298 
00299     // Delete the pen
00300     DeleteObject( hPen );
00301 }
00302 
00303 
00304 void Win32Graphics::applyMaskToWindow( OSWindow &rWindow )
00305 {
00306     // Get window handle
00307     HWND hWnd = ((Win32Window&)rWindow).getHandle();
00308 
00309     // Apply the mask
00310     // We need to copy the mask, because SetWindowRgn modifies it in our back
00311     HRGN mask = CreateRectRgn( 0, 0, 0, 0 );
00312     CombineRgn( mask, m_mask, NULL, RGN_COPY );
00313     SetWindowRgn( hWnd, mask, TRUE );
00314 }
00315 
00316 
00317 void Win32Graphics::copyToWindow( OSWindow &rWindow, int xSrc, int ySrc,
00318                                   int width, int height, int xDest, int yDest )
00319 {
00320     // Initialize painting
00321     HWND hWnd = ((Win32Window&)rWindow).getHandle();
00322     HDC wndDC = GetWindowDC( hWnd );
00323     HDC srcDC = m_hDC;
00324 
00325     // Draw image on window
00326     BitBlt( wndDC, xDest, yDest, width, height, srcDC, xSrc, ySrc, SRCCOPY );
00327 
00328     // Release window device context
00329     ReleaseDC( hWnd, wndDC );
00330 }
00331 
00332 
00333 bool Win32Graphics::hit( int x, int y ) const
00334 {
00335     return PtInRegion( m_mask, x, y ) != 0;
00336 }
00337 
00338 
00339 void Win32Graphics::addSegmentInRegion( HRGN &rMask, int start,
00340                                         int end, int line )
00341 {
00342     HRGN buffer = CreateRectRgn( start, line, end, line + 1 );
00343     CombineRgn( rMask, buffer, rMask, RGN_OR );
00344     DeleteObject( buffer );
00345 }
00346 
00347 #endif

Generated on Tue Dec 20 10:14:44 2005 for vlc-0.8.4a by  doxygen 1.4.2