added alpha channel support to wxDFB's wxBitmap
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@47205 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -82,6 +82,8 @@ protected:
|
|||||||
virtual wxObjectRefData *CreateRefData() const;
|
virtual wxObjectRefData *CreateRefData() const;
|
||||||
virtual wxObjectRefData *CloneRefData(const wxObjectRefData *data) const;
|
virtual wxObjectRefData *CloneRefData(const wxObjectRefData *data) const;
|
||||||
|
|
||||||
|
bool CreateWithFormat(int width, int height, int dfbFormat);
|
||||||
|
|
||||||
DECLARE_DYNAMIC_CLASS(wxBitmap)
|
DECLARE_DYNAMIC_CLASS(wxBitmap)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -30,18 +30,26 @@
|
|||||||
// helpers
|
// helpers
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// NB: Most of this conversion code is needed because of differences between
|
||||||
|
// wxImage and wxDFB's wxBitmap representations:
|
||||||
|
// (1) wxImage uses RGB order, while DirectFB uses BGR
|
||||||
|
// (2) wxImage has alpha channel in a separate plane, while DirectFB puts
|
||||||
|
// all components into single BGRA plane
|
||||||
|
|
||||||
// pitch = stride = # of bytes between the start of N-th line and (N+1)-th line
|
// pitch = stride = # of bytes between the start of N-th line and (N+1)-th line
|
||||||
|
// {Src,Dst}PixSize = # of bytes used to represent one pixel
|
||||||
|
template<int SrcPixSize, int DstPixSize>
|
||||||
static void CopyPixelsAndSwapRGB(unsigned w, unsigned h,
|
static void CopyPixelsAndSwapRGB(unsigned w, unsigned h,
|
||||||
const unsigned char *src,
|
const unsigned char *src,
|
||||||
unsigned src_pitch,
|
unsigned src_pitch,
|
||||||
unsigned char *dst,
|
unsigned char *dst,
|
||||||
unsigned dst_pitch)
|
unsigned dst_pitch)
|
||||||
{
|
{
|
||||||
unsigned src_advance = src_pitch - 3 * w;
|
unsigned src_advance = src_pitch - SrcPixSize * w;
|
||||||
unsigned dst_advance = dst_pitch - 3 * w;
|
unsigned dst_advance = dst_pitch - DstPixSize * w;
|
||||||
for ( unsigned y = 0; y < h; y++, src += src_advance, dst += dst_advance )
|
for ( unsigned y = 0; y < h; y++, src += src_advance, dst += dst_advance )
|
||||||
{
|
{
|
||||||
for ( unsigned x = 0; x < w; x++, src += 3, dst += 3 )
|
for ( unsigned x = 0; x < w; x++, src += SrcPixSize, dst += DstPixSize )
|
||||||
{
|
{
|
||||||
// copy with RGB -> BGR translation:
|
// copy with RGB -> BGR translation:
|
||||||
dst[0] = src[2];
|
dst[0] = src[2];
|
||||||
@@ -52,31 +60,111 @@ static void CopyPixelsAndSwapRGB(unsigned w, unsigned h,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void CopySurfaceToImage(const wxIDirectFBSurfacePtr& surface,
|
static void CopySurfaceToImage(const wxIDirectFBSurfacePtr& surface,
|
||||||
const wxImage& image)
|
wxImage& image)
|
||||||
{
|
{
|
||||||
wxCHECK_RET( surface->GetPixelFormat() == DSPF_RGB24,
|
|
||||||
_T("unexpected pixel format") );
|
|
||||||
|
|
||||||
wxIDirectFBSurface::Locked locked(surface, DSLF_READ);
|
wxIDirectFBSurface::Locked locked(surface, DSLF_READ);
|
||||||
wxCHECK_RET( locked.ptr, _T("failed to lock surface") );
|
wxCHECK_RET( locked.ptr, _T("failed to lock surface") );
|
||||||
|
|
||||||
CopyPixelsAndSwapRGB(image.GetWidth(), image.GetHeight(),
|
const unsigned width = image.GetWidth();
|
||||||
(unsigned char*)locked.ptr, locked.pitch,
|
const unsigned height = image.GetHeight();
|
||||||
image.GetData(), image.GetWidth() * 3);
|
const DFBSurfacePixelFormat format = surface->GetPixelFormat();
|
||||||
|
|
||||||
|
// copy RGB data from the surface:
|
||||||
|
switch ( format )
|
||||||
|
{
|
||||||
|
case DSPF_RGB24:
|
||||||
|
CopyPixelsAndSwapRGB<3,3>
|
||||||
|
(
|
||||||
|
width, height,
|
||||||
|
(unsigned char*)locked.ptr, locked.pitch,
|
||||||
|
image.GetData(), width * 3
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DSPF_RGB32:
|
||||||
|
case DSPF_ARGB:
|
||||||
|
CopyPixelsAndSwapRGB<4,3>
|
||||||
|
(
|
||||||
|
width, height,
|
||||||
|
(unsigned char*)locked.ptr, locked.pitch,
|
||||||
|
image.GetData(), width * 3
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
wxFAIL_MSG( "unexpected pixel format" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract alpha channel if the bitmap has it:
|
||||||
|
if ( format == DSPF_ARGB )
|
||||||
|
{
|
||||||
|
// create alpha plane:
|
||||||
|
image.SetAlpha();
|
||||||
|
|
||||||
|
// and copy alpha data to it:
|
||||||
|
const unsigned advance = locked.pitch - 4 * width;
|
||||||
|
unsigned char *alpha = image.GetAlpha();
|
||||||
|
// NB: "+3" is to get pointer to alpha component
|
||||||
|
const unsigned char *src = ((unsigned char*)locked.ptr) + 3;
|
||||||
|
|
||||||
|
for ( unsigned y = 0; y < height; y++, src += advance )
|
||||||
|
for ( unsigned x = 0; x < width; x++, src += 4 )
|
||||||
|
*(alpha++) = *src;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CopyImageToSurface(const wxImage& image,
|
static void CopyImageToSurface(const wxImage& image,
|
||||||
const wxIDirectFBSurfacePtr& surface)
|
const wxIDirectFBSurfacePtr& surface)
|
||||||
{
|
{
|
||||||
wxCHECK_RET( surface->GetPixelFormat() == DSPF_RGB24,
|
|
||||||
_T("unexpected pixel format") );
|
|
||||||
|
|
||||||
wxIDirectFBSurface::Locked locked(surface, DSLF_WRITE);
|
wxIDirectFBSurface::Locked locked(surface, DSLF_WRITE);
|
||||||
wxCHECK_RET( locked.ptr, _T("failed to lock surface") );
|
wxCHECK_RET( locked.ptr, "failed to lock surface" );
|
||||||
|
|
||||||
CopyPixelsAndSwapRGB(image.GetWidth(), image.GetHeight(),
|
const unsigned width = image.GetWidth();
|
||||||
image.GetData(), image.GetWidth() * 3,
|
const unsigned height = image.GetHeight();
|
||||||
(unsigned char*)locked.ptr, locked.pitch);
|
const DFBSurfacePixelFormat format = surface->GetPixelFormat();
|
||||||
|
|
||||||
|
// copy RGB data to the surface:
|
||||||
|
switch ( format )
|
||||||
|
{
|
||||||
|
case DSPF_RGB24:
|
||||||
|
CopyPixelsAndSwapRGB<3,3>
|
||||||
|
(
|
||||||
|
width, height,
|
||||||
|
image.GetData(), width * 3,
|
||||||
|
(unsigned char*)locked.ptr, locked.pitch
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DSPF_RGB32:
|
||||||
|
case DSPF_ARGB:
|
||||||
|
CopyPixelsAndSwapRGB<3,4>
|
||||||
|
(
|
||||||
|
width, height,
|
||||||
|
image.GetData(), width * 3,
|
||||||
|
(unsigned char*)locked.ptr, locked.pitch
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
wxFAIL_MSG( "unexpected pixel format" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the image has alpha channel, merge it in:
|
||||||
|
if ( format == DSPF_ARGB )
|
||||||
|
{
|
||||||
|
wxCHECK_RET( image.HasAlpha(), "logic error - ARGB, but no alpha" );
|
||||||
|
|
||||||
|
const unsigned advance = locked.pitch - 4 * width;
|
||||||
|
const unsigned char *alpha = image.GetAlpha();
|
||||||
|
// NB: "+3" is to get pointer to alpha component
|
||||||
|
unsigned char *dest = ((unsigned char*)locked.ptr) + 3;
|
||||||
|
|
||||||
|
for ( unsigned y = 0; y < height; y++, dest += advance )
|
||||||
|
for ( unsigned x = 0; x < width; x++, dest += 4 )
|
||||||
|
*dest = *(alpha++);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a surface that will use wxImage's pixel data (RGB only)
|
// Creates a surface that will use wxImage's pixel data (RGB only)
|
||||||
@@ -167,11 +255,17 @@ bool wxBitmap::Create(const wxIDirectFBSurfacePtr& surface)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool wxBitmap::Create(int width, int height, int depth)
|
bool wxBitmap::Create(int width, int height, int depth)
|
||||||
|
{
|
||||||
|
wxCHECK_MSG( depth == -1, false, wxT("only default depth supported now") );
|
||||||
|
|
||||||
|
return CreateWithFormat(width, height, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wxBitmap::CreateWithFormat(int width, int height, int dfbFormat)
|
||||||
{
|
{
|
||||||
UnRef();
|
UnRef();
|
||||||
|
|
||||||
wxCHECK_MSG( width > 0 && height > 0, false, wxT("invalid bitmap size") );
|
wxCHECK_MSG( width > 0 && height > 0, false, wxT("invalid bitmap size") );
|
||||||
wxCHECK_MSG( depth == -1, false, wxT("only default depth supported now") );
|
|
||||||
|
|
||||||
DFBSurfaceDescription desc;
|
DFBSurfaceDescription desc;
|
||||||
desc.flags = (DFBSurfaceDescriptionFlags)(
|
desc.flags = (DFBSurfaceDescriptionFlags)(
|
||||||
@@ -180,6 +274,13 @@ bool wxBitmap::Create(int width, int height, int depth)
|
|||||||
desc.width = width;
|
desc.width = width;
|
||||||
desc.height = height;
|
desc.height = height;
|
||||||
|
|
||||||
|
if ( dfbFormat != -1 )
|
||||||
|
{
|
||||||
|
desc.flags = (DFBSurfaceDescriptionFlags)(
|
||||||
|
desc.flags | DSDESC_PIXELFORMAT);
|
||||||
|
desc.pixelformat = (DFBSurfacePixelFormat)dfbFormat;
|
||||||
|
}
|
||||||
|
|
||||||
return Create(wxIDirectFB::Get()->CreateSurface(&desc));
|
return Create(wxIDirectFB::Get()->CreateSurface(&desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,29 +288,37 @@ bool wxBitmap::Create(int width, int height, int depth)
|
|||||||
wxBitmap::wxBitmap(const wxImage& image, int depth)
|
wxBitmap::wxBitmap(const wxImage& image, int depth)
|
||||||
{
|
{
|
||||||
wxCHECK_RET( image.Ok(), wxT("invalid image") );
|
wxCHECK_RET( image.Ok(), wxT("invalid image") );
|
||||||
|
wxCHECK_RET( depth == -1, wxT("only default depth supported now") );
|
||||||
|
|
||||||
// create surface in screen's format:
|
// create surface in screen's format (unless we need alpha channel,
|
||||||
if ( !Create(image.GetWidth(), image.GetHeight(), depth) )
|
// in which case use ARGB):
|
||||||
|
if ( !CreateWithFormat(image.GetWidth(), image.GetHeight(),
|
||||||
|
image.HasAlpha() ? DSPF_ARGB : -1) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// then copy the image to it:
|
// then copy the image to it:
|
||||||
wxIDirectFBSurfacePtr dst = M_BITMAP->m_surface;
|
wxIDirectFBSurfacePtr dst = M_BITMAP->m_surface;
|
||||||
|
|
||||||
if ( dst->GetPixelFormat() == DSPF_RGB24 )
|
switch ( dst->GetPixelFormat() )
|
||||||
{
|
{
|
||||||
CopyImageToSurface(image, dst);
|
case DSPF_RGB24:
|
||||||
}
|
case DSPF_RGB32:
|
||||||
else
|
case DSPF_ARGB:
|
||||||
{
|
CopyImageToSurface(image, dst);
|
||||||
// wxBitmap uses different pixel format, so we have to use a temporary
|
break;
|
||||||
// surface and blit to the bitmap via it:
|
|
||||||
wxIDirectFBSurfacePtr src(CreateSurfaceForImage(image));
|
|
||||||
CopyImageToSurface(image, src);
|
|
||||||
|
|
||||||
if ( !dst->SetBlittingFlags(DSBLIT_NOFX) )
|
default:
|
||||||
return;
|
{
|
||||||
if ( !dst->Blit(src->GetRaw(), NULL, 0, 0) )
|
// wxBitmap uses different pixel format, so we have to use a
|
||||||
return;
|
// temporary surface and blit to the bitmap via it:
|
||||||
|
wxIDirectFBSurfacePtr src(CreateSurfaceForImage(image));
|
||||||
|
CopyImageToSurface(image, src);
|
||||||
|
|
||||||
|
if ( !dst->SetBlittingFlags(DSBLIT_NOFX) )
|
||||||
|
return;
|
||||||
|
if ( !dst->Blit(src->GetRaw(), NULL, 0, 0) )
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: implement mask creation from image's mask (or alpha channel?)
|
// FIXME: implement mask creation from image's mask (or alpha channel?)
|
||||||
@@ -223,22 +332,26 @@ wxImage wxBitmap::ConvertToImage() const
|
|||||||
wxImage img(GetWidth(), GetHeight());
|
wxImage img(GetWidth(), GetHeight());
|
||||||
wxIDirectFBSurfacePtr src = M_BITMAP->m_surface;
|
wxIDirectFBSurfacePtr src = M_BITMAP->m_surface;
|
||||||
|
|
||||||
if ( src->GetPixelFormat() == DSPF_RGB24 )
|
switch ( src->GetPixelFormat() )
|
||||||
{
|
{
|
||||||
CopySurfaceToImage(src, img);
|
case DSPF_RGB24:
|
||||||
}
|
case DSPF_RGB32:
|
||||||
else
|
case DSPF_ARGB:
|
||||||
{
|
CopySurfaceToImage(src, img);
|
||||||
// wxBitmap uses different pixel format, so we have to use a temporary
|
break;
|
||||||
// surface and blit to the bitmap via it:
|
default:
|
||||||
wxIDirectFBSurfacePtr dst(CreateSurfaceForImage(img));
|
{
|
||||||
|
// wxBitmap uses different pixel format, so we have to use a
|
||||||
|
// temporary surface and blit to the bitmap via it:
|
||||||
|
wxIDirectFBSurfacePtr dst(CreateSurfaceForImage(img));
|
||||||
|
|
||||||
if ( !dst->SetBlittingFlags(DSBLIT_NOFX) )
|
if ( !dst->SetBlittingFlags(DSBLIT_NOFX) )
|
||||||
return wxNullImage;
|
return wxNullImage;
|
||||||
if ( !dst->Blit(src->GetRaw(), NULL, 0, 0) )
|
if ( !dst->Blit(src->GetRaw(), NULL, 0, 0) )
|
||||||
return wxNullImage;
|
return wxNullImage;
|
||||||
|
|
||||||
CopySurfaceToImage(dst, img);
|
CopySurfaceToImage(dst, img);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: implement mask setting in the image
|
// FIXME: implement mask setting in the image
|
||||||
|
@@ -691,7 +691,10 @@ bool wxDC::DoBlitFromSurface(const wxIDirectFBSurfacePtr& src,
|
|||||||
wxIDirectFBSurfacePtr dst(m_surface);
|
wxIDirectFBSurfacePtr dst(m_surface);
|
||||||
|
|
||||||
// FIXME: this will have to be different in useMask case, see above
|
// FIXME: this will have to be different in useMask case, see above
|
||||||
if ( !dst->SetBlittingFlags(DSBLIT_NOFX) )
|
DFBSurfaceBlittingFlags blitFlag = (src->GetPixelFormat() == DSPF_ARGB)
|
||||||
|
? DSBLIT_BLEND_ALPHACHANNEL
|
||||||
|
: DSBLIT_NOFX;
|
||||||
|
if ( !dst->SetBlittingFlags(blitFlag) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ( srcRect.w != dstRect.w || srcRect.h != dstRect.h )
|
if ( srcRect.w != dstRect.w || srcRect.h != dstRect.h )
|
||||||
|
Reference in New Issue
Block a user