+// 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
+// {Src,Dst}PixSize = # of bytes used to represent one pixel
+template<int SrcPixSize, int DstPixSize>
+static void CopyPixelsAndSwapRGB(unsigned w, unsigned h,
+ const unsigned char *src,
+ unsigned src_pitch,
+ unsigned char *dst,
+ unsigned dst_pitch)
+{
+ unsigned src_advance = src_pitch - SrcPixSize * w;
+ unsigned dst_advance = dst_pitch - DstPixSize * w;
+ for ( unsigned y = 0; y < h; y++, src += src_advance, dst += dst_advance )
+ {
+ for ( unsigned x = 0; x < w; x++, src += SrcPixSize, dst += DstPixSize )
+ {
+ // copy with RGB -> BGR translation:
+ dst[0] = src[2];
+ dst[1] = src[1];
+ dst[2] = src[0];
+ }
+ }
+}
+
+static void CopySurfaceToImage(const wxIDirectFBSurfacePtr& surface,
+ wxImage& image)
+{
+ wxIDirectFBSurface::Locked locked(surface, DSLF_READ);
+ wxCHECK_RET( locked.ptr, _T("failed to lock surface") );
+
+ const unsigned width = image.GetWidth();
+ const unsigned height = image.GetHeight();
+ 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,
+ const wxIDirectFBSurfacePtr& surface)
+{
+ wxIDirectFBSurface::Locked locked(surface, DSLF_WRITE);
+ wxCHECK_RET( locked.ptr, "failed to lock surface" );
+
+ const unsigned width = image.GetWidth();
+ const unsigned height = image.GetHeight();
+ 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++);
+ }
+}
+
+static wxIDirectFBSurfacePtr
+CreateSurfaceWithFormat(int w, int h, DFBSurfacePixelFormat format)
+{
+ DFBSurfaceDescription desc;
+ desc.flags = (DFBSurfaceDescriptionFlags)
+ (DSDESC_CAPS | DSDESC_WIDTH | DSDESC_HEIGHT);
+ desc.caps = DSCAPS_NONE;
+ desc.width = w;
+ desc.height = h;
+
+ if ( format != DSPF_UNKNOWN )
+ {
+ desc.flags = (DFBSurfaceDescriptionFlags)(
+ desc.flags | DSDESC_PIXELFORMAT);
+ desc.pixelformat = format;
+ }
+
+ return wxIDirectFB::Get()->CreateSurface(&desc);
+}
+