Localization fix of the warning texts in the 3D scene.

Improved anti-aliasing of the warning texts in the 3D scene
and the G-code legend. A ClearType rendering has been suppressed
by rendering of the text into a red channel only.
This commit is contained in:
bubnikv 2019-03-21 14:33:55 +01:00
parent f9e3b935d3
commit 562343cd2a

View file

@ -34,6 +34,7 @@
#include <wx/settings.h> #include <wx/settings.h>
#include <wx/tooltip.h> #include <wx/tooltip.h>
#include <wx/debug.h> #include <wx/debug.h>
#include <wx/fontutil.h>
// Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx. // Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx.
#include "libslic3r/Print.hpp" #include "libslic3r/Print.hpp"
@ -1659,13 +1660,69 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool
_generate(text, canvas, red_colored); // GUI::GLTexture::reset() is called at the beginning of generate(...) _generate(text, canvas, red_colored); // GUI::GLTexture::reset() is called at the beginning of generate(...)
} }
bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanvas3D& canvas, const bool red_colored/* = false*/)
#ifdef __WXMSW__
static bool is_font_cleartype(const wxFont &font)
{
// Native font description: on MSW, it is a version number plus the content of LOGFONT, separated by semicolon.
wxString font_desc = font.GetNativeFontInfoDesc();
// Find the quality field.
wxString sep(";");
size_t startpos = 0;
for (size_t i = 0; i < 12; ++ i)
startpos = font_desc.find(sep, startpos + 1);
++ startpos;
size_t endpos = font_desc.find(sep, startpos);
int quality = wxAtoi(font_desc(startpos, endpos - startpos));
return quality == CLEARTYPE_QUALITY;
}
// ClearType produces renders, which are difficult to convert into an alpha blended OpenGL texture.
// Therefore it is better to disable it, though Vojtech found out, that the font returned with ClearType
// disabled is signifcantly thicker than the default ClearType font.
// This function modifies the font provided.
static void msw_disable_cleartype(wxFont &font)
{
// Native font description: on MSW, it is a version number plus the content of LOGFONT, separated by semicolon.
wxString font_desc = font.GetNativeFontInfoDesc();
// Find the quality field.
wxString sep(";");
size_t startpos_weight = 0;
for (size_t i = 0; i < 5; ++ i)
startpos_weight = font_desc.find(sep, startpos_weight + 1);
++ startpos_weight;
size_t endpos_weight = font_desc.find(sep, startpos_weight);
// Parse the weight field.
unsigned int weight = atoi(font_desc(startpos_weight, endpos_weight - startpos_weight));
size_t startpos = endpos_weight;
for (size_t i = 0; i < 6; ++ i)
startpos = font_desc.find(sep, startpos + 1);
++ startpos;
size_t endpos = font_desc.find(sep, startpos);
int quality = wxAtoi(font_desc(startpos, endpos - startpos));
if (quality == CLEARTYPE_QUALITY) {
// Replace the weight with a smaller value to compensate the weight of non ClearType font.
wxString sweight = std::to_string(weight * 2 / 4);
size_t len_weight = endpos_weight - startpos_weight;
wxString squality = std::to_string(ANTIALIASED_QUALITY);
font_desc.replace(startpos_weight, len_weight, sweight);
font_desc.replace(startpos + sweight.size() - len_weight, endpos - startpos, squality);
font.SetNativeFontInfo(font_desc);
wxString font_desc2 = font.GetNativeFontInfoDesc();
}
wxString font_desc2 = font.GetNativeFontInfoDesc();
}
#endif /* __WXMSW__ */
bool GLCanvas3D::WarningTexture::_generate(const std::string& msg_utf8, const GLCanvas3D& canvas, const bool red_colored/* = false*/)
{ {
reset(); reset();
if (msg.empty()) if (msg_utf8.empty())
return false; return false;
wxString msg = GUI::from_u8(msg_utf8);
wxMemoryDC memDC; wxMemoryDC memDC;
// select default font // select default font
const float scale = canvas.get_canvas_size().get_scale_factor(); const float scale = canvas.get_canvas_size().get_scale_factor();
@ -1676,46 +1733,47 @@ bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanva
// calculates texture size // calculates texture size
wxCoord w, h; wxCoord w, h;
// memDC.GetTextExtent(msg, &w, &h);
memDC.GetMultiLineTextExtent(msg, &w, &h); memDC.GetMultiLineTextExtent(msg, &w, &h);
int pow_of_two_size = next_highest_power_of_2(std::max<unsigned int>(w, h));
m_original_width = (int)w; m_original_width = (int)w;
m_original_height = (int)h; m_original_height = (int)h;
m_width = pow_of_two_size; m_width = (int)next_highest_power_of_2((uint32_t)w);
m_height = pow_of_two_size; m_height = (int)next_highest_power_of_2((uint32_t)h);
// generates bitmap // generates bitmap
wxBitmap bitmap(m_width, m_height); wxBitmap bitmap(m_width, m_height);
memDC.SelectObject(bitmap); memDC.SelectObject(bitmap);
memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2]))); memDC.SetBackground(wxBrush(*wxBLACK));
memDC.Clear(); memDC.Clear();
// draw message // draw message
memDC.SetTextForeground(red_colored ? wxColour(255,72,65/*204,204*/) : *wxWHITE); memDC.SetTextForeground(*wxRED);
// memDC.DrawText(msg, 0, 0); memDC.DrawLabel(msg, wxRect(0,0, m_original_width, m_original_height), wxALIGN_CENTER);
memDC.DrawLabel(msg, wxRect(0,0, m_original_width, m_original_height), wxALIGN_CENTER);
memDC.SelectObject(wxNullBitmap); memDC.SelectObject(wxNullBitmap);
// Convert the bitmap into a linear data ready to be loaded into the GPU. // Convert the bitmap into a linear data ready to be loaded into the GPU.
wxImage image = bitmap.ConvertToImage(); wxImage image = bitmap.ConvertToImage();
image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]);
// prepare buffer // prepare buffer
std::vector<unsigned char> data(4 * m_width * m_height, 0); std::vector<unsigned char> data(4 * m_width * m_height, 0);
const unsigned char *src = image.GetData();
for (int h = 0; h < m_height; ++h) for (int h = 0; h < m_height; ++h)
{ {
int hh = h * m_width; unsigned char* dst = data.data() + 4 * h * m_width;
unsigned char* px_ptr = data.data() + 4 * hh;
for (int w = 0; w < m_width; ++w) for (int w = 0; w < m_width; ++w)
{ {
*px_ptr++ = image.GetRed(w, h); *dst++ = 255;
*px_ptr++ = image.GetGreen(w, h); if (red_colored) {
*px_ptr++ = image.GetBlue(w, h); *dst++ = 72; // 204
*px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity; *dst++ = 65; // 204
} else {
*dst++ = 255;
*dst++ = 255;
}
*dst++ = (unsigned char)std::min<int>(255, *src);
src += 3;
} }
} }
@ -1839,7 +1897,15 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
const int scaled_border = Px_Border * scale; const int scaled_border = Px_Border * scale;
// select default font // select default font
const wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scale(scale_gl); wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scale(scale_gl);
#ifdef __WXMSW__
// Disabling ClearType works, but the font returned is very different (much thicker) from the default.
// msw_disable_cleartype(font);
bool cleartype = is_font_cleartype(font);
#else
bool cleartype = false;
#endif /* __WXMSW__ */
memDC.SetFont(font); memDC.SetFont(font);
mask_memDC.SetFont(font); mask_memDC.SetFont(font);
@ -1863,10 +1929,8 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
if (items_count > 1) if (items_count > 1)
m_original_height += (items_count - 1) * scaled_square_contour; m_original_height += (items_count - 1) * scaled_square_contour;
int pow_of_two_size = (int)next_highest_power_of_2(std::max<uint32_t>(m_original_width, m_original_height)); m_width = (int)next_highest_power_of_2((uint32_t)m_original_width);
m_height = (int)next_highest_power_of_2((uint32_t)m_original_height);
m_width = pow_of_two_size;
m_height = pow_of_two_size;
// generates bitmap // generates bitmap
wxBitmap bitmap(m_width, m_height); wxBitmap bitmap(m_width, m_height);
@ -1883,16 +1947,13 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
// draw title // draw title
memDC.SetTextForeground(*wxWHITE); memDC.SetTextForeground(*wxWHITE);
mask_memDC.SetTextForeground(*wxWHITE); mask_memDC.SetTextForeground(*wxRED);
int title_x = scaled_border; int title_x = scaled_border;
int title_y = scaled_border; int title_y = scaled_border;
memDC.DrawText(title, title_x, title_y); memDC.DrawText(title, title_x, title_y);
mask_memDC.DrawText(title, title_x, title_y); mask_memDC.DrawText(title, title_x, title_y);
mask_memDC.SetPen(wxPen(*wxWHITE));
mask_memDC.SetBrush(wxBrush(*wxWHITE));
// draw icons contours as background // draw icons contours as background
int squares_contour_x = scaled_border; int squares_contour_x = scaled_border;
int squares_contour_y = scaled_border + title_height + scaled_title_offset; int squares_contour_y = scaled_border + title_height + scaled_title_offset;
@ -1907,7 +1968,6 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
memDC.SetPen(pen); memDC.SetPen(pen);
memDC.SetBrush(brush); memDC.SetBrush(brush);
memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height)); memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height));
mask_memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height));
// draw items (colored icon + text) // draw items (colored icon + text)
int icon_x = squares_contour_x + scaled_square_contour; int icon_x = squares_contour_x + scaled_square_contour;
@ -1943,7 +2003,6 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
memDC.DrawRectangle(wxRect(icon_x_inner, icon_y + 1, px_inner_square, px_inner_square)); memDC.DrawRectangle(wxRect(icon_x_inner, icon_y + 1, px_inner_square, px_inner_square));
// draw text // draw text
memDC.DrawText(GUI::from_u8(item.text), text_x, icon_y + text_y_offset);
mask_memDC.DrawText(GUI::from_u8(item.text), text_x, icon_y + text_y_offset); mask_memDC.DrawText(GUI::from_u8(item.text), text_x, icon_y + text_y_offset);
// update y // update y
@ -1959,17 +2018,34 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
// prepare buffer // prepare buffer
std::vector<unsigned char> data(4 * m_width * m_height, 0); std::vector<unsigned char> data(4 * m_width * m_height, 0);
for (int h = 0; h < m_height; ++h) const unsigned char *src_image = image.GetData();
const unsigned char *src_mask = mask_image.GetData();
for (int h = 0; h < m_height; ++h)
{ {
int hh = h * m_width; int hh = h * m_width;
unsigned char* px_ptr = data.data() + 4 * hh; unsigned char* px_ptr = data.data() + 4 * hh;
for (int w = 0; w < m_width; ++w) for (int w = 0; w < m_width; ++w)
{ {
unsigned char alpha = (mask_image.GetRed(w, h) + mask_image.GetGreen(w, h) + mask_image.GetBlue(w, h)) / 3; if (w >= squares_contour_x && w < squares_contour_x + squares_contour_width &&
*px_ptr++ = image.GetRed(w, h); h >= squares_contour_y && h < squares_contour_y + squares_contour_height) {
*px_ptr++ = image.GetGreen(w, h); // Color palette, use the color verbatim.
*px_ptr++ = image.GetBlue(w, h); *px_ptr++ = *src_image++;
*px_ptr++ = (alpha == 0) ? 128 : 255; *px_ptr++ = *src_image++;
*px_ptr++ = *src_image++;
*px_ptr++ = 255;
} else {
// Text or background
unsigned char alpha = *src_mask;
// Compensate the white color for the 50% opacity reduction at the character edges.
//unsigned char color = (unsigned char)floor(alpha * 255.f / (128.f + 0.5f * alpha));
unsigned char color = alpha;
*px_ptr++ = color;
*px_ptr++ = color; // *src_mask ++;
*px_ptr++ = color; // *src_mask ++;
*px_ptr++ = 128 + (alpha / 2); // (alpha > 0) ? 255 : 128;
src_image += 3;
}
src_mask += 3;
} }
} }