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"
27 #include "wx/dfb/private.h"
29 //-----------------------------------------------------------------------------
31 //-----------------------------------------------------------------------------
33 // NB: Most of this conversion code is needed because of differences between
34 // wxImage and wxDFB's wxBitmap representations:
35 // (1) wxImage uses RGB order, while DirectFB uses BGR
36 // (2) wxImage has alpha channel in a separate plane, while DirectFB puts
37 // all components into single BGRA plane
39 // pitch = stride = # of bytes between the start of N-th line and (N+1)-th line
40 // {Src,Dst}PixSize = # of bytes used to represent one pixel
41 template<int SrcPixSize
, int DstPixSize
>
42 static void CopyPixelsAndSwapRGB(unsigned w
, unsigned h
,
43 const unsigned char *src
,
48 unsigned src_advance
= src_pitch
- SrcPixSize
* w
;
49 unsigned dst_advance
= dst_pitch
- DstPixSize
* w
;
50 for ( unsigned y
= 0; y
< h
; y
++, src
+= src_advance
, dst
+= dst_advance
)
52 for ( unsigned x
= 0; x
< w
; x
++, src
+= SrcPixSize
, dst
+= DstPixSize
)
54 // copy with RGB -> BGR translation:
62 static void CopySurfaceToImage(const wxIDirectFBSurfacePtr
& surface
,
65 wxIDirectFBSurface::Locked
locked(surface
, DSLF_READ
);
66 wxCHECK_RET( locked
.ptr
, _T("failed to lock surface") );
68 const unsigned width
= image
.GetWidth();
69 const unsigned height
= image
.GetHeight();
70 const DFBSurfacePixelFormat format
= surface
->GetPixelFormat();
72 // copy RGB data from the surface:
76 CopyPixelsAndSwapRGB
<3,3>
79 (unsigned char*)locked
.ptr
, locked
.pitch
,
80 image
.GetData(), width
* 3
86 CopyPixelsAndSwapRGB
<4,3>
89 (unsigned char*)locked
.ptr
, locked
.pitch
,
90 image
.GetData(), width
* 3
95 wxFAIL_MSG( "unexpected pixel format" );
99 // extract alpha channel if the bitmap has it:
100 if ( format
== DSPF_ARGB
)
102 // create alpha plane:
105 // and copy alpha data to it:
106 const unsigned advance
= locked
.pitch
- 4 * width
;
107 unsigned char *alpha
= image
.GetAlpha();
108 // NB: "+3" is to get pointer to alpha component
109 const unsigned char *src
= ((unsigned char*)locked
.ptr
) + 3;
111 for ( unsigned y
= 0; y
< height
; y
++, src
+= advance
)
112 for ( unsigned x
= 0; x
< width
; x
++, src
+= 4 )
117 static void CopyImageToSurface(const wxImage
& image
,
118 const wxIDirectFBSurfacePtr
& surface
)
120 wxIDirectFBSurface::Locked
locked(surface
, DSLF_WRITE
);
121 wxCHECK_RET( locked
.ptr
, "failed to lock surface" );
123 const unsigned width
= image
.GetWidth();
124 const unsigned height
= image
.GetHeight();
125 const DFBSurfacePixelFormat format
= surface
->GetPixelFormat();
127 // copy RGB data to the surface:
131 CopyPixelsAndSwapRGB
<3,3>
134 image
.GetData(), width
* 3,
135 (unsigned char*)locked
.ptr
, locked
.pitch
141 CopyPixelsAndSwapRGB
<3,4>
144 image
.GetData(), width
* 3,
145 (unsigned char*)locked
.ptr
, locked
.pitch
150 wxFAIL_MSG( "unexpected pixel format" );
154 // if the image has alpha channel, merge it in:
155 if ( format
== DSPF_ARGB
)
157 wxCHECK_RET( image
.HasAlpha(), "logic error - ARGB, but no alpha" );
159 const unsigned advance
= locked
.pitch
- 4 * width
;
160 const unsigned char *alpha
= image
.GetAlpha();
161 // NB: "+3" is to get pointer to alpha component
162 unsigned char *dest
= ((unsigned char*)locked
.ptr
) + 3;
164 for ( unsigned y
= 0; y
< height
; y
++, dest
+= advance
)
165 for ( unsigned x
= 0; x
< width
; x
++, dest
+= 4 )
170 // Creates a surface that will use wxImage's pixel data (RGB only)
171 static wxIDirectFBSurfacePtr
CreateSurfaceForImage(const wxImage
& image
)
173 wxCHECK_MSG( image
.Ok(), NULL
, _T("invalid image") );
174 // FIXME_DFB: implement alpha handling by merging alpha buffer with RGB
175 // into a temporary RGBA surface
176 wxCHECK_MSG( !image
.HasAlpha(), NULL
, _T("alpha channel not supported") );
178 // NB: wxImage uses RGB order of bytes while DirectFB uses BGR, so we
179 // cannot use preallocated surface that shares data with wxImage, we
180 // have to copy the data to temporary surface instead
181 DFBSurfaceDescription desc
;
182 desc
.flags
= (DFBSurfaceDescriptionFlags
)
183 (DSDESC_CAPS
| DSDESC_WIDTH
| DSDESC_HEIGHT
| DSDESC_PIXELFORMAT
);
184 desc
.caps
= DSCAPS_NONE
;
185 desc
.width
= image
.GetWidth();
186 desc
.height
= image
.GetHeight();
187 desc
.pixelformat
= DSPF_RGB24
;
189 return wxIDirectFB::Get()->CreateSurface(&desc
);
192 //-----------------------------------------------------------------------------
194 //-----------------------------------------------------------------------------
196 class wxBitmapRefData
: public wxObjectRefData
207 wxBitmapRefData(const wxBitmapRefData
& data
)
209 m_surface
= data
.m_surface
? data
.m_surface
->Clone() : NULL
;
211 m_mask
= data
.m_mask
? new wxMask(*data
.m_mask
) : NULL
;
213 m_palette
= data
.m_palette
? new wxPalette(*data
.m_palette
) : NULL
;
217 virtual ~wxBitmapRefData()
225 wxIDirectFBSurfacePtr m_surface
;
228 wxPalette
*m_palette
;
232 #define M_BITMAP ((wxBitmapRefData *)m_refData)
234 //-----------------------------------------------------------------------------
236 //-----------------------------------------------------------------------------
238 IMPLEMENT_ABSTRACT_CLASS(wxBitmapHandler
, wxBitmapHandlerBase
)
239 IMPLEMENT_DYNAMIC_CLASS(wxBitmap
, wxBitmapBase
)
241 wxBitmap::wxBitmap(int width
, int height
, int depth
)
243 Create(width
, height
, depth
);
246 bool wxBitmap::Create(const wxIDirectFBSurfacePtr
& surface
)
250 wxCHECK_MSG( surface
, false, _T("invalid surface") );
252 m_refData
= new wxBitmapRefData();
253 M_BITMAP
->m_surface
= surface
;
257 bool wxBitmap::Create(int width
, int height
, int depth
)
259 wxCHECK_MSG( depth
== -1, false, wxT("only default depth supported now") );
261 return CreateWithFormat(width
, height
, -1);
264 bool wxBitmap::CreateWithFormat(int width
, int height
, int dfbFormat
)
268 wxCHECK_MSG( width
> 0 && height
> 0, false, wxT("invalid bitmap size") );
270 DFBSurfaceDescription desc
;
271 desc
.flags
= (DFBSurfaceDescriptionFlags
)(
272 DSDESC_CAPS
| DSDESC_WIDTH
| DSDESC_HEIGHT
);
273 desc
.caps
= DSCAPS_NONE
;
275 desc
.height
= height
;
277 if ( dfbFormat
!= -1 )
279 desc
.flags
= (DFBSurfaceDescriptionFlags
)(
280 desc
.flags
| DSDESC_PIXELFORMAT
);
281 desc
.pixelformat
= (DFBSurfacePixelFormat
)dfbFormat
;
284 return Create(wxIDirectFB::Get()->CreateSurface(&desc
));
288 wxBitmap::wxBitmap(const wxImage
& image
, int depth
)
290 wxCHECK_RET( image
.Ok(), wxT("invalid image") );
291 wxCHECK_RET( depth
== -1, wxT("only default depth supported now") );
293 // create surface in screen's format (unless we need alpha channel,
294 // in which case use ARGB):
295 if ( !CreateWithFormat(image
.GetWidth(), image
.GetHeight(),
296 image
.HasAlpha() ? DSPF_ARGB
: -1) )
299 // then copy the image to it:
300 wxIDirectFBSurfacePtr dst
= M_BITMAP
->m_surface
;
302 switch ( dst
->GetPixelFormat() )
307 CopyImageToSurface(image
, dst
);
312 // wxBitmap uses different pixel format, so we have to use a
313 // temporary surface and blit to the bitmap via it:
314 wxIDirectFBSurfacePtr
src(CreateSurfaceForImage(image
));
315 CopyImageToSurface(image
, src
);
317 if ( !dst
->SetBlittingFlags(DSBLIT_NOFX
) )
319 if ( !dst
->Blit(src
->GetRaw(), NULL
, 0, 0) )
324 // FIXME: implement mask creation from image's mask (or alpha channel?)
325 wxASSERT_MSG( !image
.HasMask(), _T("image masks are ignored for now") );
328 wxImage
wxBitmap::ConvertToImage() const
330 wxCHECK_MSG( Ok(), wxNullImage
, wxT("invalid bitmap") );
332 wxImage
img(GetWidth(), GetHeight());
333 wxIDirectFBSurfacePtr src
= M_BITMAP
->m_surface
;
335 switch ( src
->GetPixelFormat() )
340 CopySurfaceToImage(src
, img
);
344 // wxBitmap uses different pixel format, so we have to use a
345 // temporary surface and blit to the bitmap via it:
346 wxIDirectFBSurfacePtr
dst(CreateSurfaceForImage(img
));
348 if ( !dst
->SetBlittingFlags(DSBLIT_NOFX
) )
350 if ( !dst
->Blit(src
->GetRaw(), NULL
, 0, 0) )
353 CopySurfaceToImage(dst
, img
);
357 // FIXME: implement mask setting in the image
358 wxASSERT_MSG( GetMask() == NULL
, _T("bitmap masks are ignored for now") );
362 #endif // wxUSE_IMAGE
364 wxBitmap::wxBitmap(const wxString
&filename
, wxBitmapType type
)
366 LoadFile(filename
, type
);
369 wxBitmap::wxBitmap(const char bits
[], int width
, int height
, int depth
)
371 wxCHECK_RET( depth
== 1, wxT("can only create mono bitmap from XBM data") );
373 wxFAIL_MSG( _T("not implemented") );
376 bool wxBitmap::IsOk() const
378 return (m_refData
!= NULL
&& M_BITMAP
->m_surface
);
381 int wxBitmap::GetHeight() const
383 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
386 M_BITMAP
->m_surface
->GetSize(NULL
, &h
);
390 int wxBitmap::GetWidth() const
392 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
395 M_BITMAP
->m_surface
->GetSize(&w
, NULL
);
399 int wxBitmap::GetDepth() const
401 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
403 return M_BITMAP
->m_surface
->GetDepth();
406 wxMask
*wxBitmap::GetMask() const
408 wxCHECK_MSG( Ok(), NULL
, wxT("invalid bitmap") );
410 return M_BITMAP
->m_mask
;
413 void wxBitmap::SetMask(wxMask
*mask
)
415 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
418 delete M_BITMAP
->m_mask
;
419 M_BITMAP
->m_mask
= mask
;
422 bool wxBitmap::CopyFromIcon(const wxIcon
& icon
)
424 *this = *((wxBitmap
*)(&icon
));
428 wxBitmap
wxBitmap::GetSubBitmap(const wxRect
& rect
) const
431 rect
.x
>= 0 && rect
.y
>= 0 &&
432 rect
.x
+rect
.width
<= GetWidth() &&
433 rect
.y
+rect
.height
<= GetHeight(),
435 wxT("invalid bitmap or bitmap region") );
437 // NB: DirectFB subsurfaces share the same pixels buffer, so we must
438 // clone the obtained subsurface
439 DFBRectangle r
= { rect
.x
, rect
.y
, rect
.width
, rect
.height
};
440 return wxBitmap(M_BITMAP
->m_surface
->GetSubSurface(&r
)->Clone());
443 #warning "to common code"
444 bool wxBitmap::LoadFile(const wxString
&name
, wxBitmapType type
)
448 wxBitmapHandler
*handler
= FindHandler(type
);
450 if ( handler
== NULL
)
453 if ( !image
.LoadFile(name
, type
) || !image
.Ok() )
455 wxLogError(_("No bitmap handler for type %d defined."), type
);
460 *this = wxBitmap(image
);
465 m_refData
= new wxBitmapRefData();
467 return handler
->LoadFile(this, name
, type
, -1, -1);
470 #warning "to common code"
471 bool wxBitmap::SaveFile(const wxString
& filename
, wxBitmapType type
, const wxPalette
*palette
) const
473 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
475 wxBitmapHandler
*handler
= FindHandler(type
);
477 if ( handler
== NULL
)
479 wxImage image
= ConvertToImage();
482 image
.SetPalette(*palette
);
483 #endif // wxUSE_PALETTE
486 return image
.SaveFile(filename
, type
);
489 wxLogError(_("No bitmap handler for type %d defined."), type
);
494 return handler
->SaveFile(this, filename
, type
, palette
);
498 wxPalette
*wxBitmap::GetPalette() const
500 wxCHECK_MSG( Ok(), NULL
, wxT("invalid bitmap") );
502 return M_BITMAP
->m_palette
;
505 void wxBitmap::SetPalette(const wxPalette
& palette
)
507 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
508 wxCHECK_RET( GetDepth() > 1 && GetDepth() <= 8, wxT("cannot set palette for bitmap of this depth") );
511 delete M_BITMAP
->m_palette
;
512 M_BITMAP
->m_palette
= NULL
;
514 if ( !palette
.Ok() ) return;
516 M_BITMAP
->m_palette
= new wxPalette(palette
);
518 #endif // wxUSE_PALETTE
520 void wxBitmap::SetHeight(int height
)
524 wxFAIL_MSG( _T("SetHeight not implemented") );
527 void wxBitmap::SetWidth(int width
)
531 wxFAIL_MSG( _T("SetWidth not implemented") );
534 void wxBitmap::SetDepth(int depth
)
538 wxFAIL_MSG( _T("SetDepth not implemented") );
541 wxIDirectFBSurfacePtr
wxBitmap::GetDirectFBSurface() const
543 wxCHECK_MSG( Ok(), NULL
, wxT("invalid bitmap") );
545 return M_BITMAP
->m_surface
;
548 wxObjectRefData
*wxBitmap::CreateRefData() const
550 return new wxBitmapRefData
;
553 wxObjectRefData
*wxBitmap::CloneRefData(const wxObjectRefData
*data
) const
555 return new wxBitmapRefData(*(wxBitmapRefData
*)data
);
560 void wxBitmap::InitStandardHandlers()
562 // not wxBitmap handlers, we rely on wxImage