/*****************************************************************************
* win32_graphics.cpp
*****************************************************************************
* Copyright (C) 2003 the VideoLAN team
*
* Authors: Cyril Deguet <asmax@via.ecp.fr>
* Olivier Teulière <ipkiss@via.ecp.fr>
*
* 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef WIN32_SKINS
#include "win32_factory.hpp"
#include "win32_graphics.hpp"
#include "win32_window.hpp"
#include "../src/generic_bitmap.hpp"
#ifndef AC_SRC_ALPHA
#define AC_SRC_ALPHA 1
#endif
Win32Graphics::Win32Graphics( intf_thread_t *pIntf, int width, int height ):
OSGraphics( pIntf ), m_width( width ), m_height( height ), m_hDC( NULL )
{
HBITMAP hBmp;
HDC hDC = GetDC( NULL );
hBmp = CreateCompatibleBitmap( hDC, m_width, m_height );
ReleaseDC( NULL, hDC );
m_hDC = CreateCompatibleDC( NULL );
SelectObject( m_hDC, hBmp );
DeleteObject( hBmp );
// Create the mask
m_mask = CreateRectRgn( 0, 0, 0, 0 );
}
Win32Graphics::~Win32Graphics()
{
DeleteDC( m_hDC );
DeleteObject( m_mask );
}
void Win32Graphics::clear( int xDest, int yDest, int width, int height )
{
if( width <= 0 || height <= 0 )
{
// Clear the transparency mask
DeleteObject( m_mask );
m_mask = CreateRectRgn( 0, 0, 0, 0 );
}
else
{
HRGN mask = CreateRectRgn( xDest, yDest,
xDest + width, yDest + height );
CombineRgn( m_mask, m_mask, mask, RGN_DIFF );
DeleteObject( mask );
}
}
void Win32Graphics::drawBitmap( const GenericBitmap &rBitmap,
int xSrc, int ySrc, int xDest, int yDest,
int width, int height, bool blend )
{
(void)blend;
// check and adapt to source if needed
if( !checkBoundaries( 0, 0, rBitmap.getWidth(), rBitmap.getHeight(),
xSrc, ySrc, width, height ) )
{
msg_Err( getIntf(), "empty source! pls, debug your skin" );
return;
}
// check destination
if( !checkBoundaries( 0, 0, m_width, m_height,
xDest, yDest, width, height ) )
{
msg_Err( getIntf(), "out of reach destination! pls, debug your skin" );
return;
}
// Get a buffer on the image data
uint8_t *pBmpData = rBitmap.getData();
if( pBmpData == NULL )
{
// Nothing to draw
return;
}
void *pBits; // pointer to DIB section
// Fill a BITMAPINFO structure
BITMAPINFO bmpInfo;
memset( &bmpInfo, 0, sizeof( bmpInfo ) );
bmpInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
bmpInfo.bmiHeader.biWidth = width;
bmpInfo.bmiHeader.biHeight = -height;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 32;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biSizeImage = width * height * 4;
// Create a DIB (Device Independent Bitmap) and associate it with
// a temporary DC
HDC hDC = CreateCompatibleDC( m_hDC );
HBITMAP hBmp = CreateDIBSection( hDC, &bmpInfo, DIB_RGB_COLORS,
&pBits, NULL, 0 );
SelectObject( hDC, hBmp );
// Mask for transparency
HRGN mask = CreateRectRgn( 0, 0, 0, 0 );
// Skip the first lines of the image
pBmpData += 4 * ySrc * rBitmap.getWidth();
// Copy the bitmap on the image and compute the mask
for( int y = 0; y < height; y++ )
{
// Skip uninteresting bytes at the beginning of the line
pBmpData += 4 * xSrc;
// Flag to say whether the previous pixel on the line was visible
bool wasVisible = false;
// Beginning of the current visible segment on the line
int visibleSegmentStart = 0;
for( int x = 0; x < width; x++ )
{
uint8_t b = *(pBmpData++);
uint8_t g = *(pBmpData++);
uint8_t r = *(pBmpData++);
uint8_t a = *(pBmpData++);
// Draw the pixel
((UINT32 *)pBits)[x + y * width] =
(a << 24) | (r << 16) | (g << 8) | b;
if( a > 0 )
{
// Pixel is visible
if( ! wasVisible )
{
// Beginning of a visible segment
visibleSegmentStart = x;
}
wasVisible = true;
}
else
{
// Pixel is transparent
if( wasVisible )
{
// End of a visible segment: add it to the mask
addSegmentInRegion( mask, visibleSegmentStart, x, y );
}
wasVisible = false;
}
}
if( wasVisible )
{
// End of a visible segment: add it to the mask
addSegmentInRegion( mask, visibleSegmentStart, width, y );
}
// Skip uninteresting bytes at the end of the line
pBmpData += 4 * (rBitmap.getWidth() - width - xSrc);
}
// Apply the mask to the internal DC
OffsetRgn( mask, xDest, yDest );
SelectClipRgn( m_hDC, mask );
BLENDFUNCTION bf; // structure for alpha blending
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 0xff; // don't use constant alpha
bf.AlphaFormat = AC_SRC_ALPHA;
// Blend the image onto the internal DC
if( !AlphaBlend( m_hDC, xDest, yDest, width, height, hDC, 0, 0,
width, height, bf ) )
{
msg_Err( getIntf(), "AlphaBlend() failed" );
}
// Add the bitmap mask to the global graphics mask
CombineRgn( m_mask, m_mask, mask, RGN_OR );
// Do cleanup
DeleteObject( hBmp );
DeleteObject( mask );
DeleteDC( hDC );
}
void Win32Graphics::drawGraphics( const OSGraphics &rGraphics, int xSrc,
int ySrc, int xDest, int yDest, int width,
int height )
{
// check and adapt to source if needed
if( !checkBoundaries( 0, 0, rGraphics.getWidth(), rGraphics.getHeight(),
xSrc, ySrc, width, height ) )
{
msg_Err( getIntf(), "nothing to draw from graphics source" );
return;
}
// check destination
if( !checkBoundaries( 0, 0, m_width, m_height,
xDest, yDest, width, height ) )
{
msg_Err( getIntf(), "out of reach destination! pls, debug your skin" );
return;
}
// Create the mask for transparency
HRGN mask = CreateRectRgn( xSrc, ySrc, xSrc + width, ySrc + height );
CombineRgn( mask, ((Win32Graphics&)rGraphics).getMask(), mask, RGN_AND );
OffsetRgn( mask, xDest - xSrc, yDest - ySrc );
// Copy the image
HDC srcDC = ((Win32Graphics&)rGraphics).getDC();
SelectClipRgn( m_hDC, mask );
BitBlt( m_hDC, xDest, yDest, width, height, srcDC, xSrc, ySrc, SRCCOPY );
// Add the source mask to the mask of the graphics
CombineRgn( m_mask, mask, m_mask, RGN_OR );
DeleteObject( mask );
}
void Win32Graphics::fillRect( int left, int top, int width, int height,
uint32_t color )
{
// Update the mask with the rectangle area
HRGN newMask = CreateRectRgn( left, top, left + width, top + height );
CombineRgn( m_mask, m_mask, newMask, RGN_OR );
SelectClipRgn( m_hDC, m_mask );
DeleteObject( newMask );
// Create a brush with the color
int red = (color & 0xff0000) >> 16;
int green = (color & 0xff00) >> 8;
int blue = color & 0xff;
HBRUSH hBrush = CreateSolidBrush( RGB( red, green, blue ) );
// Draw the rectangle
RECT r;
r.left = left;
r.top = top;
r.right = left + width;
r.bottom = top + height;
FillRect( m_hDC, &r, hBrush );
DeleteObject( hBrush );
}
void Win32Graphics::drawRect( int left, int top, int width, int height,
uint32_t color )
{
// Update the mask with the rectangle
HRGN l1 = CreateRectRgn( left, top, left + width, top + 1 );
HRGN l2 = CreateRectRgn( left + width - 1, top,
left + width, top + height );
HRGN l3 = CreateRectRgn( left, top + height - 1,
left + width, top + height );
HRGN l4 = CreateRectRgn( left, top, left + 1, top + height );
CombineRgn( m_mask, m_mask, l1, RGN_OR );
CombineRgn( m_mask, m_mask, l2, RGN_OR );
CombineRgn( m_mask, m_mask, l3, RGN_OR );
CombineRgn( m_mask, m_mask, l4, RGN_OR );
DeleteObject( l1 );
DeleteObject( l2 );
DeleteObject( l3 );
DeleteObject( l4 );
SelectClipRgn( m_hDC, m_mask );
// Create a pen with the color
int red = (color & 0xff0000) >> 16;
int green = (color & 0xff00) >> 8;
int blue = color & 0xff;
HPEN hPen = CreatePen( PS_SOLID, 0, RGB( red, green, blue ) );
SelectObject( m_hDC, hPen );
// Draw the rectangle
MoveToEx( m_hDC, left, top, NULL );
LineTo( m_hDC, left + width - 1, top );
LineTo( m_hDC, left + width - 1, top + height - 1 );
LineTo( m_hDC, left, top + height - 1 );
LineTo( m_hDC, left, top );
// Delete the pen
DeleteObject( hPen );
}
void Win32Graphics::applyMaskToWindow( OSWindow &rWindow )
{
// Get window handle
HWND hWnd = ((Win32Window&)rWindow).getHandle();
// Apply the mask
// We need to copy the mask, because SetWindowRgn modifies it in our back
HRGN mask = CreateRectRgn( 0, 0, 0, 0 );
CombineRgn( mask, m_mask, NULL, RGN_COPY );
SetWindowRgn( hWnd, mask, TRUE );
}
void Win32Graphics::copyToWindow( OSWindow &rWindow, int xSrc, int ySrc,
int width, int height, int xDest, int yDest )
{
// Initialize painting
HWND hWnd = ((Win32Window&)rWindow).getHandle();
HDC wndDC = GetDC( hWnd );
HDC srcDC = m_hDC;
// Draw image on window
BitBlt( wndDC, xDest, yDest, width, height, srcDC, xSrc, ySrc, SRCCOPY );
// Release window device context
ReleaseDC( hWnd, wndDC );
}
bool Win32Graphics::hit( int x, int y ) const
{
return PtInRegion( m_mask, x, y ) != 0;
}
void Win32Graphics::addSegmentInRegion( HRGN &rMask, int start,
int end, int line )
{
HRGN buffer = CreateRectRgn( start, line, end, line + 1 );
CombineRgn( rMask, buffer, rMask, RGN_OR );
DeleteObject( buffer );
}
bool Win32Graphics::checkBoundaries( int x_src, int y_src,
int w_src, int h_src,
int& x_target, int& y_target,
int& w_target, int& h_target )
{
// set valid width and height
w_target = (w_target > 0) ? w_target : w_src;
h_target = (h_target > 0) ? h_target : h_src;
// clip source if needed
rect srcRegion( x_src, y_src, w_src, h_src );
rect targetRegion( x_target, y_target, w_target, h_target );
rect inter;
if( rect::intersect( srcRegion, targetRegion, &inter ) )
{
x_target = inter.x;
y_target = inter.y;
w_target = inter.width;
h_target = inter.height;
return true;
}
return false;
}
#endif
¤ Dauer der Verarbeitung: 0.6 Sekunden
¤
*© Formatika GbR, Deutschland
|
|