1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/dfb/bitmap.cpp
3 // Purpose: wxBitmap implementation
4 // Author: Vaclav Slavik
7 // Copyright: (c) 2006 REA Elektronik GmbH
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
23 #include "wx/bitmap.h"
24 #include "wx/colour.h"
26 #include "wx/rawbmp.h"
28 #include "wx/dfb/private.h"
30 //-----------------------------------------------------------------------------
32 //-----------------------------------------------------------------------------
34 // NB: Most of this conversion code is needed because of differences between
35 // wxImage and wxDFB's wxBitmap representations:
36 // (1) wxImage uses RGB order, while DirectFB uses BGR
37 // (2) wxImage has alpha channel in a separate plane, while DirectFB puts
38 // all components into single BGRA plane
40 // pitch = stride = # of bytes between the start of N-th line and (N+1)-th line
41 // {Src,Dst}PixSize = # of bytes used to represent one pixel
42 template<int SrcPixSize
, int DstPixSize
>
43 static void CopyPixelsAndSwapRGB(unsigned w
, unsigned h
,
44 const unsigned char *src
,
49 unsigned src_advance
= src_pitch
- SrcPixSize
* w
;
50 unsigned dst_advance
= dst_pitch
- DstPixSize
* w
;
51 for ( unsigned y
= 0; y
< h
; y
++, src
+= src_advance
, dst
+= dst_advance
)
53 for ( unsigned x
= 0; x
< w
; x
++, src
+= SrcPixSize
, dst
+= DstPixSize
)
55 // copy with RGB -> BGR translation:
63 static void CopySurfaceToImage(const wxIDirectFBSurfacePtr
& surface
,
66 wxIDirectFBSurface::Locked
locked(surface
, DSLF_READ
);
67 wxCHECK_RET( locked
.ptr
, "failed to lock surface" );
69 const unsigned width
= image
.GetWidth();
70 const unsigned height
= image
.GetHeight();
71 const DFBSurfacePixelFormat format
= surface
->GetPixelFormat();
73 // copy RGB data from the surface:
77 CopyPixelsAndSwapRGB
<3,3>
80 (unsigned char*)locked
.ptr
, locked
.pitch
,
81 image
.GetData(), width
* 3
87 CopyPixelsAndSwapRGB
<4,3>
90 (unsigned char*)locked
.ptr
, locked
.pitch
,
91 image
.GetData(), width
* 3
96 wxFAIL_MSG( "unexpected pixel format" );
100 // extract alpha channel if the bitmap has it:
101 if ( format
== DSPF_ARGB
)
103 // create alpha plane:
106 // and copy alpha data to it:
107 const unsigned advance
= locked
.pitch
- 4 * width
;
108 unsigned char *alpha
= image
.GetAlpha();
109 // NB: "+3" is to get pointer to alpha component
110 const unsigned char *src
= ((unsigned char*)locked
.ptr
) + 3;
112 for ( unsigned y
= 0; y
< height
; y
++, src
+= advance
)
113 for ( unsigned x
= 0; x
< width
; x
++, src
+= 4 )
118 static void CopyImageToSurface(const wxImage
& image
,
119 const wxIDirectFBSurfacePtr
& surface
)
121 wxIDirectFBSurface::Locked
locked(surface
, DSLF_WRITE
);
122 wxCHECK_RET( locked
.ptr
, "failed to lock surface" );
124 const unsigned width
= image
.GetWidth();
125 const unsigned height
= image
.GetHeight();
126 const DFBSurfacePixelFormat format
= surface
->GetPixelFormat();
128 // copy RGB data to the surface:
132 CopyPixelsAndSwapRGB
<3,3>
135 image
.GetData(), width
* 3,
136 (unsigned char*)locked
.ptr
, locked
.pitch
142 CopyPixelsAndSwapRGB
<3,4>
145 image
.GetData(), width
* 3,
146 (unsigned char*)locked
.ptr
, locked
.pitch
151 wxFAIL_MSG( "unexpected pixel format" );
155 // if the image has alpha channel, merge it in:
156 if ( format
== DSPF_ARGB
)
158 wxCHECK_RET( image
.HasAlpha(), "logic error - ARGB, but no alpha" );
160 const unsigned advance
= locked
.pitch
- 4 * width
;
161 const unsigned char *alpha
= image
.GetAlpha();
162 // NB: "+3" is to get pointer to alpha component
163 unsigned char *dest
= ((unsigned char*)locked
.ptr
) + 3;
165 for ( unsigned y
= 0; y
< height
; y
++, dest
+= advance
)
166 for ( unsigned x
= 0; x
< width
; x
++, dest
+= 4 )
171 static wxIDirectFBSurfacePtr
172 CreateSurfaceWithFormat(int w
, int h
, DFBSurfacePixelFormat format
)
174 DFBSurfaceDescription desc
;
175 desc
.flags
= (DFBSurfaceDescriptionFlags
)
176 (DSDESC_CAPS
| DSDESC_WIDTH
| DSDESC_HEIGHT
);
177 desc
.caps
= DSCAPS_NONE
;
181 if ( format
!= DSPF_UNKNOWN
)
183 desc
.flags
= (DFBSurfaceDescriptionFlags
)(
184 desc
.flags
| DSDESC_PIXELFORMAT
);
185 desc
.pixelformat
= format
;
188 return wxIDirectFB::Get()->CreateSurface(&desc
);
191 // Creates a surface that will use wxImage's pixel data (RGB only)
192 static wxIDirectFBSurfacePtr
CreateSurfaceForImage(const wxImage
& image
)
194 wxCHECK_MSG( image
.Ok(), NULL
, "invalid image" );
195 // FIXME_DFB: implement alpha handling by merging alpha buffer with RGB
196 // into a temporary RGBA surface
197 wxCHECK_MSG( !image
.HasAlpha(), NULL
, "alpha channel not supported" );
199 // NB: wxImage uses RGB order of bytes while DirectFB uses BGR, so we
200 // cannot use preallocated surface that shares data with wxImage, we
201 // have to copy the data to temporary surface instead
202 return CreateSurfaceWithFormat(image
.GetWidth(), image
.GetHeight(),
206 static bool ConvertSurfaceToFormat(wxIDirectFBSurfacePtr
& surface
,
207 DFBSurfacePixelFormat format
)
209 if ( surface
->GetPixelFormat() == format
)
213 surface
->GetSize(&w
, &h
);
214 wxIDirectFBSurfacePtr s
= CreateSurfaceWithFormat(w
, h
, format
);
218 if ( !s
->SetBlittingFlags(DSBLIT_NOFX
) )
220 if ( !s
->Blit(surface
->GetRaw(), NULL
, 0, 0) )
227 static DFBSurfacePixelFormat
DepthToFormat(int depth
)
234 // NB: we treat depth=32 as requesting ARGB for consistency with
238 wxFAIL_MSG( "unsupported depth requested" );
245 //-----------------------------------------------------------------------------
247 //-----------------------------------------------------------------------------
249 class wxBitmapRefData
: public wxGDIRefData
260 wxBitmapRefData(const wxBitmapRefData
& data
)
262 m_surface
= data
.m_surface
? data
.m_surface
->Clone() : NULL
;
264 m_mask
= data
.m_mask
? new wxMask(*data
.m_mask
) : NULL
;
266 m_palette
= data
.m_palette
? new wxPalette(*data
.m_palette
) : NULL
;
270 virtual ~wxBitmapRefData()
278 virtual bool IsOk() const { return m_surface
; }
280 wxIDirectFBSurfacePtr m_surface
;
283 wxPalette
*m_palette
;
287 #define M_BITMAP ((wxBitmapRefData *)m_refData)
289 //-----------------------------------------------------------------------------
291 //-----------------------------------------------------------------------------
293 IMPLEMENT_ABSTRACT_CLASS(wxBitmapHandler
, wxBitmapHandlerBase
)
294 IMPLEMENT_DYNAMIC_CLASS(wxBitmap
, wxBitmapBase
)
296 wxBitmap::wxBitmap(int width
, int height
, int depth
)
298 Create(width
, height
, depth
);
301 bool wxBitmap::Create(const wxIDirectFBSurfacePtr
& surface
)
305 wxCHECK_MSG( surface
, false, "invalid surface" );
307 m_refData
= new wxBitmapRefData();
308 M_BITMAP
->m_surface
= surface
;
312 bool wxBitmap::Create(int width
, int height
, int depth
)
314 return CreateWithFormat(width
, height
, DepthToFormat(depth
));
317 bool wxBitmap::CreateWithFormat(int width
, int height
, int dfbFormat
)
321 wxCHECK_MSG( width
> 0 && height
> 0, false, wxT("invalid bitmap size") );
323 return Create(CreateSurfaceWithFormat(width
, height
,
324 DFBSurfacePixelFormat(dfbFormat
)));
328 wxBitmap::wxBitmap(const wxImage
& imageOrig
, int depth
)
330 wxCHECK_RET( imageOrig
.Ok(), wxT("invalid image") );
332 wxImage
image(imageOrig
);
334 // convert mask to alpha channel, because wxMask isn't implemented yet
335 // FIXME: don't do this, implement proper wxMask support
336 if ( image
.HasMask() )
339 DFBSurfacePixelFormat format
= DepthToFormat(depth
);
340 if ( format
== DSPF_UNKNOWN
&& image
.HasAlpha() )
343 // create surface in screen's format (unless we need alpha channel,
344 // in which case use ARGB):
345 if ( !CreateWithFormat(image
.GetWidth(), image
.GetHeight(), format
) )
348 // then copy the image to it:
349 wxIDirectFBSurfacePtr dst
= M_BITMAP
->m_surface
;
351 switch ( dst
->GetPixelFormat() )
356 CopyImageToSurface(image
, dst
);
361 // wxBitmap uses different pixel format, so we have to use a
362 // temporary surface and blit to the bitmap via it:
363 wxIDirectFBSurfacePtr
src(CreateSurfaceForImage(image
));
364 CopyImageToSurface(image
, src
);
366 if ( !dst
->SetBlittingFlags(DSBLIT_NOFX
) )
368 if ( !dst
->Blit(src
->GetRaw(), NULL
, 0, 0) )
374 wxImage
wxBitmap::ConvertToImage() const
376 wxCHECK_MSG( Ok(), wxNullImage
, wxT("invalid bitmap") );
378 wxImage
img(GetWidth(), GetHeight());
379 wxIDirectFBSurfacePtr src
= M_BITMAP
->m_surface
;
381 switch ( src
->GetPixelFormat() )
386 CopySurfaceToImage(src
, img
);
390 // wxBitmap uses different pixel format, so we have to use a
391 // temporary surface and blit to the bitmap via it:
392 wxIDirectFBSurfacePtr
dst(CreateSurfaceForImage(img
));
394 if ( !dst
->SetBlittingFlags(DSBLIT_NOFX
) )
396 if ( !dst
->Blit(src
->GetRaw(), NULL
, 0, 0) )
399 CopySurfaceToImage(dst
, img
);
403 // FIXME: implement mask setting in the image
404 wxASSERT_MSG( GetMask() == NULL
, "bitmap masks are ignored for now" );
408 #endif // wxUSE_IMAGE
410 void *wxBitmap::GetRawData(wxPixelDataBase
& data
, int bpp
)
412 wxCHECK_MSG( Ok(), NULL
, "invalid bitmap" );
416 DFBSurfacePixelFormat format
;
422 // convert the bitmap into format compatible with requested raw access;
423 // note that we don't bother converting the bitmap back in UngetRawData(),
424 // as unpacked formats (RGB24, RGB32) are the common case and converting
425 // between them while blitting is fast enough (FIXME?)
426 if ( !ConvertSurfaceToFormat(M_BITMAP
->m_surface
, format
) )
430 if ( !M_BITMAP
->m_surface
->Lock
432 (DFBSurfaceLockFlags
)(DSLF_READ
| DSLF_WRITE
),
438 M_BITMAP
->m_surface
->GetSize(&data
.m_width
, &data
.m_height
);
443 void wxBitmap::UngetRawData(wxPixelDataBase
& WXUNUSED(data
))
445 M_BITMAP
->m_surface
->Unlock();
448 bool wxBitmap::HasAlpha() const
450 wxCHECK_MSG( Ok(), false, "invalid bitmap" );
452 return M_BITMAP
->m_surface
->GetPixelFormat() == DSPF_ARGB
;
455 wxBitmap::wxBitmap(const wxString
&filename
, wxBitmapType type
)
457 LoadFile(filename
, type
);
460 wxBitmap::wxBitmap(const char bits
[], int width
, int height
, int depth
)
462 wxCHECK_RET( depth
== 1, wxT("can only create mono bitmap from XBM data") );
464 wxFAIL_MSG( "not implemented" );
467 int wxBitmap::GetHeight() const
469 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
472 M_BITMAP
->m_surface
->GetSize(NULL
, &h
);
476 int wxBitmap::GetWidth() const
478 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
481 M_BITMAP
->m_surface
->GetSize(&w
, NULL
);
485 int wxBitmap::GetDepth() const
487 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
489 return M_BITMAP
->m_surface
->GetDepth();
492 wxMask
*wxBitmap::GetMask() const
494 wxCHECK_MSG( Ok(), NULL
, wxT("invalid bitmap") );
496 return M_BITMAP
->m_mask
;
499 void wxBitmap::SetMask(wxMask
*mask
)
501 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
504 delete M_BITMAP
->m_mask
;
505 M_BITMAP
->m_mask
= mask
;
508 bool wxBitmap::CopyFromIcon(const wxIcon
& icon
)
510 *this = *((wxBitmap
*)(&icon
));
514 wxBitmap
wxBitmap::GetSubBitmap(const wxRect
& rect
) const
517 rect
.x
>= 0 && rect
.y
>= 0 &&
518 rect
.x
+rect
.width
<= GetWidth() &&
519 rect
.y
+rect
.height
<= GetHeight(),
521 wxT("invalid bitmap or bitmap region") );
523 // NB: DirectFB subsurfaces share the same pixels buffer, so we must
524 // clone the obtained subsurface
525 DFBRectangle r
= { rect
.x
, rect
.y
, rect
.width
, rect
.height
};
526 return wxBitmap(M_BITMAP
->m_surface
->GetSubSurface(&r
)->Clone());
529 #warning "to common code"
530 bool wxBitmap::LoadFile(const wxString
&name
, wxBitmapType type
)
534 wxBitmapHandler
*handler
= FindHandler(type
);
536 if ( handler
== NULL
)
539 if ( !image
.LoadFile(name
, type
) || !image
.Ok() )
541 wxLogError(_("No bitmap handler for type %d defined."), type
);
546 *this = wxBitmap(image
);
551 m_refData
= new wxBitmapRefData();
553 return handler
->LoadFile(this, name
, type
, -1, -1);
556 #warning "to common code"
557 bool wxBitmap::SaveFile(const wxString
& filename
, wxBitmapType type
, const wxPalette
*palette
) const
559 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
561 wxBitmapHandler
*handler
= FindHandler(type
);
563 if ( handler
== NULL
)
565 wxImage image
= ConvertToImage();
568 image
.SetPalette(*palette
);
569 #endif // wxUSE_PALETTE
572 return image
.SaveFile(filename
, type
);
575 wxLogError(_("No bitmap handler for type %d defined."), type
);
580 return handler
->SaveFile(this, filename
, type
, palette
);
584 wxPalette
*wxBitmap::GetPalette() const
586 wxCHECK_MSG( Ok(), NULL
, wxT("invalid bitmap") );
588 return M_BITMAP
->m_palette
;
591 void wxBitmap::SetPalette(const wxPalette
& palette
)
593 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
594 wxCHECK_RET( GetDepth() > 1 && GetDepth() <= 8, wxT("cannot set palette for bitmap of this depth") );
597 delete M_BITMAP
->m_palette
;
598 M_BITMAP
->m_palette
= NULL
;
600 if ( !palette
.Ok() ) return;
602 M_BITMAP
->m_palette
= new wxPalette(palette
);
604 #endif // wxUSE_PALETTE
606 void wxBitmap::SetHeight(int height
)
610 wxFAIL_MSG( "SetHeight not implemented" );
613 void wxBitmap::SetWidth(int width
)
617 wxFAIL_MSG( "SetWidth not implemented" );
620 void wxBitmap::SetDepth(int depth
)
622 DFBSurfacePixelFormat format
= DepthToFormat(depth
);
623 if ( M_BITMAP
->m_surface
->GetPixelFormat() == format
)
629 M_BITMAP
->m_surface
->GetSize(&w
, &h
);
630 wxIDirectFBSurfacePtr s
= CreateSurfaceWithFormat(w
, h
, format
);
633 if ( !s
->SetBlittingFlags(DSBLIT_NOFX
) )
635 if ( !s
->Blit(M_BITMAP
->m_surface
->GetRaw(), NULL
, 0, 0) )
638 M_BITMAP
->m_surface
= s
;
641 wxIDirectFBSurfacePtr
wxBitmap::GetDirectFBSurface() const
643 wxCHECK_MSG( Ok(), NULL
, wxT("invalid bitmap") );
645 return M_BITMAP
->m_surface
;
648 wxGDIRefData
*wxBitmap::CreateGDIRefData() const
650 return new wxBitmapRefData
;
653 wxGDIRefData
*wxBitmap::CloneGDIRefData(const wxGDIRefData
*data
) const
655 return new wxBitmapRefData(*(wxBitmapRefData
*)data
);
660 void wxBitmap::InitStandardHandlers()
662 // not wxBitmap handlers, we rely on wxImage