From 64976c249d854572b9227e3283f35172e9d1a4a0 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 13 Apr 2018 12:49:12 +0200 Subject: [PATCH] Added @bubnikv's changes to BitmapCache --- xs/src/slic3r/GUI/BitmapCache.cpp | 186 +++++++++++++++++++----------- xs/src/slic3r/GUI/BitmapCache.hpp | 3 +- 2 files changed, 121 insertions(+), 68 deletions(-) diff --git a/xs/src/slic3r/GUI/BitmapCache.cpp b/xs/src/slic3r/GUI/BitmapCache.cpp index acbcb5c73c..93853458e4 100644 --- a/xs/src/slic3r/GUI/BitmapCache.cpp +++ b/xs/src/slic3r/GUI/BitmapCache.cpp @@ -1,5 +1,14 @@ #include "BitmapCache.hpp" +#if ! defined(WIN32) && ! defined(__APPLE__) +#define BROKEN_ALPHA +#endif + +#ifdef BROKEN_ALPHA + #include + #include +#endif /* BROKEN_ALPHA */ + namespace Slic3r { namespace GUI { void BitmapCache::clear() @@ -8,19 +17,31 @@ void BitmapCache::clear() delete bitmap.second; } +static wxBitmap wxImage_to_wxBitmap_with_alpha(wxImage &&image) +{ +#ifdef BROKEN_ALPHA + wxMemoryOutputStream stream; + image.SaveFile(stream, wxBITMAP_TYPE_PNG); + wxStreamBuffer *buf = stream.GetOutputStreamBuffer(); + return wxBitmap::NewFromPNGData(buf->GetBufferStart(), buf->GetBufferSize()); +#else + return wxBitmap(std::move(image)); +#endif +} + wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_t height) { - wxBitmap *bitmap = nullptr; - auto it = m_map.find(bitmap_key); - if (it == m_map.end()) { - bitmap = new wxBitmap(width, height); - m_map[bitmap_key] = bitmap; - } else { - bitmap = it->second; - if (bitmap->GetWidth() != width || bitmap->GetHeight() != height) - bitmap->Create(width, height); - } -#if defined(__APPLE__) || defined(_MSC_VER) + wxBitmap *bitmap = nullptr; + auto it = m_map.find(bitmap_key); + if (it == m_map.end()) { + bitmap = new wxBitmap(width, height); + m_map[bitmap_key] = bitmap; + } else { + bitmap = it->second; + if (bitmap->GetWidth() != width || bitmap->GetHeight() != height) + bitmap->Create(width, height); + } +#ifndef BROKEN_ALPHA bitmap->UseAlpha(); #endif return bitmap; @@ -28,77 +49,108 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp) { - wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth(), bmp.GetHeight()); - - wxMemoryDC memDC; - memDC.SelectObject(*bitmap); - memDC.SetBackground(*wxTRANSPARENT_BRUSH); - memDC.Clear(); - memDC.DrawBitmap(bmp, 0, 0, true); - memDC.SelectObject(wxNullBitmap); - - return bitmap; + wxBitmap *bitmap = nullptr; + auto it = m_map.find(bitmap_key); + if (it == m_map.end()) { + bitmap = new wxBitmap(bmp); + m_map[bitmap_key] = bitmap; + } else { + bitmap = it->second; + *bitmap = bmp; + } + return bitmap; } wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp, const wxBitmap &bmp2) { - wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth() + bmp2.GetWidth(), std::max(bmp.GetHeight(), bmp2.GetHeight())); - - wxMemoryDC memDC; - memDC.SelectObject(*bitmap); - memDC.SetBackground(*wxTRANSPARENT_BRUSH); - memDC.Clear(); - if (bmp.GetWidth() > 0) - memDC.DrawBitmap(bmp, 0, 0, true); - if (bmp2.GetWidth() > 0) - memDC.DrawBitmap(bmp2, bmp.GetWidth(), 0, true); - memDC.SelectObject(wxNullBitmap); - - return bitmap; + // Copying the wxBitmaps is cheap as the bitmap's content is reference counted. + const wxBitmap bmps[2] = { bmp, bmp2 }; + return this->insert(bitmap_key, bmps, bmps + 2); } wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3) { - wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth() + bmp2.GetWidth() + bmp3.GetWidth(), std::max(std::max(bmp.GetHeight(), bmp2.GetHeight()), bmp3.GetHeight())); + // Copying the wxBitmaps is cheap as the bitmap's content is reference counted. + const wxBitmap bmps[3] = { bmp, bmp2, bmp3 }; + return this->insert(bitmap_key, bmps, bmps + 3); +} +wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *begin, const wxBitmap *end) +{ + size_t width = 0; + size_t height = 0; + for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) { + width += bmp->GetWidth(); + height = std::max(height, bmp->GetHeight()); + } + +#ifdef BROKEN_ALPHA + + wxImage image(width, height); + image.InitAlpha(); + // Fill in with a white color. + memset(image.GetData(), 0x0ff, width * height * 3); + // Fill in with full transparency. + memset(image.GetAlpha(), 0, width * height); + size_t x = 0; + for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) { + if (bmp->GetWidth() > 0) { + if (bmp->GetDepth() == 32) { + wxAlphaPixelData data(*const_cast(bmp)); + data.UseAlpha(); + if (data) { + for (int r = 0; r < bmp->GetHeight(); ++ r) { + wxAlphaPixelData::Iterator src(data); + src.Offset(data, 0, r); + unsigned char *dst_pixels = image.GetData() + (x + r * width) * 3; + unsigned char *dst_alpha = image.GetAlpha() + x + r * width; + for (int c = 0; c < bmp->GetWidth(); ++ c, ++ src) { + *dst_pixels ++ = src.Red(); + *dst_pixels ++ = src.Green(); + *dst_pixels ++ = src.Blue(); + *dst_alpha ++ = src.Alpha(); + } + } + } + } else if (bmp->GetDepth() == 24) { + wxNativePixelData data(*const_cast(bmp)); + if (data) { + for (int r = 0; r < bmp->GetHeight(); ++ r) { + wxNativePixelData::Iterator src(data); + src.Offset(data, 0, r); + unsigned char *dst_pixels = image.GetData() + (x + r * width) * 3; + unsigned char *dst_alpha = image.GetAlpha() + x + r * width; + for (int c = 0; c < bmp->GetWidth(); ++ c, ++ src) { + *dst_pixels ++ = src.Red(); + *dst_pixels ++ = src.Green(); + *dst_pixels ++ = src.Blue(); + *dst_alpha ++ = wxALPHA_OPAQUE; + } + } + } + } + } + x += bmp->GetWidth(); + } + return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image))); + +#else + + wxBitmap *bitmap = this->insert(bitmap_key, width, height); wxMemoryDC memDC; memDC.SelectObject(*bitmap); memDC.SetBackground(*wxTRANSPARENT_BRUSH); memDC.Clear(); - if (bmp.GetWidth() > 0) - memDC.DrawBitmap(bmp, 0, 0, true); - if (bmp2.GetWidth() > 0) - memDC.DrawBitmap(bmp2, bmp.GetWidth(), 0, true); - if (bmp3.GetWidth() > 0) - memDC.DrawBitmap(bmp3, bmp.GetWidth() + bmp2.GetWidth(), 0, true); - memDC.SelectObject(wxNullBitmap); - - return bitmap; -} - -wxBitmap* BitmapCache::insert(const std::string &bitmap_key, std::vector &bmps) -{ - size_t width = 0; - size_t height = 0; - for (wxBitmap &bmp : bmps) { - width += bmp.GetWidth(); - height = std::max(height, bmp.GetHeight()); - } - wxBitmap *bitmap = this->insert(bitmap_key, width, height); - - wxMemoryDC memDC; - memDC.SelectObject(*bitmap); - memDC.SetBackground(*wxTRANSPARENT_BRUSH); - memDC.Clear(); size_t x = 0; - for (wxBitmap &bmp : bmps) { - if (bmp.GetWidth() > 0) - memDC.DrawBitmap(bmp, x, 0, true); - x += bmp.GetWidth(); - } + for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) { + if (bmp->GetWidth() > 0) + memDC.DrawBitmap(*bmp, x, 0, true); + x += bmp->GetWidth(); + } memDC.SelectObject(wxNullBitmap); + return bitmap; - return bitmap; +#endif } wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency) @@ -113,7 +165,7 @@ wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsi *imgdata ++ = b; *imgalpha ++ = transparency; } - return wxBitmap(std::move(image)); + return wxImage_to_wxBitmap_with_alpha(std::move(image)); } } // namespace GUI diff --git a/xs/src/slic3r/GUI/BitmapCache.hpp b/xs/src/slic3r/GUI/BitmapCache.hpp index 0cf9d8acf0..bec9a7ad25 100644 --- a/xs/src/slic3r/GUI/BitmapCache.hpp +++ b/xs/src/slic3r/GUI/BitmapCache.hpp @@ -27,7 +27,8 @@ public: wxBitmap* insert(const std::string &name, const wxBitmap &bmp); wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2); wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3); - wxBitmap* insert(const std::string &name, std::vector &bmps); + wxBitmap* insert(const std::string &name, const std::vector &bmps) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); } + wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end); static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency); static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }