diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index 9dbfeaff3..e768e9689 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -426,7 +426,7 @@ void GLCanvas3D::Bed::_render_mk2(float theta) const std::string filename = resources_dir() + "/icons/bed/mk2_top.png"; if ((m_top_texture.get_id() == 0) || (m_top_texture.get_source() != filename)) { - if (!m_top_texture.load_from_file(filename)) + if (!m_top_texture.load_from_file(filename, true)) { _render_custom(); return; @@ -436,7 +436,7 @@ void GLCanvas3D::Bed::_render_mk2(float theta) const filename = resources_dir() + "/icons/bed/mk2_bottom.png"; if ((m_bottom_texture.get_id() == 0) || (m_bottom_texture.get_source() != filename)) { - if (!m_bottom_texture.load_from_file(filename)) + if (!m_bottom_texture.load_from_file(filename, true)) { _render_custom(); return; @@ -451,7 +451,7 @@ void GLCanvas3D::Bed::_render_mk3(float theta) const std::string filename = resources_dir() + "/icons/bed/mk3_top.png"; if ((m_top_texture.get_id() == 0) || (m_top_texture.get_source() != filename)) { - if (!m_top_texture.load_from_file(filename)) + if (!m_top_texture.load_from_file(filename, true)) { _render_custom(); return; @@ -461,7 +461,7 @@ void GLCanvas3D::Bed::_render_mk3(float theta) const filename = resources_dir() + "/icons/bed/mk3_bottom.png"; if ((m_bottom_texture.get_id() == 0) || (m_bottom_texture.get_source() != filename)) { - if (!m_bottom_texture.load_from_file(filename)) + if (!m_bottom_texture.load_from_file(filename, true)) { _render_custom(); return; @@ -911,7 +911,7 @@ void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas if (m_tooltip_texture.get_id() == 0) { std::string filename = resources_dir() + "/icons/variable_layer_height_tooltip.png"; - if (!m_tooltip_texture.load_from_file(filename)) + if (!m_tooltip_texture.load_from_file(filename, false)) return; } @@ -935,7 +935,7 @@ void GLCanvas3D::LayersEditing::_render_reset_texture(const Rect& reset_rect) co if (m_reset_texture.get_id() == 0) { std::string filename = resources_dir() + "/icons/variable_layer_height_reset.png"; - if (!m_reset_texture.load_from_file(filename)) + if (!m_reset_texture.load_from_file(filename, false)) return; } diff --git a/xs/src/slic3r/GUI/GLGizmo.cpp b/xs/src/slic3r/GUI/GLGizmo.cpp index d98864931..64df649d4 100644 --- a/xs/src/slic3r/GUI/GLGizmo.cpp +++ b/xs/src/slic3r/GUI/GLGizmo.cpp @@ -95,15 +95,15 @@ bool GLGizmoRotate::on_init() std::string path = resources_dir() + "/icons/overlay/"; std::string filename = path + "rotate_off.png"; - if (!m_textures[Off].load_from_file(filename)) + if (!m_textures[Off].load_from_file(filename, false)) return false; filename = path + "rotate_hover.png"; - if (!m_textures[Hover].load_from_file(filename)) + if (!m_textures[Hover].load_from_file(filename, false)) return false; filename = path + "rotate_on.png"; - if (!m_textures[On].load_from_file(filename)) + if (!m_textures[On].load_from_file(filename, false)) return false; return true; @@ -224,15 +224,15 @@ bool GLGizmoScale::on_init() std::string path = resources_dir() + "/icons/overlay/"; std::string filename = path + "scale_off.png"; - if (!m_textures[Off].load_from_file(filename)) + if (!m_textures[Off].load_from_file(filename, false)) return false; filename = path + "scale_hover.png"; - if (!m_textures[Hover].load_from_file(filename)) + if (!m_textures[Hover].load_from_file(filename, false)) return false; filename = path + "scale_on.png"; - if (!m_textures[On].load_from_file(filename)) + if (!m_textures[On].load_from_file(filename, false)) return false; return true; diff --git a/xs/src/slic3r/GUI/GLTexture.cpp b/xs/src/slic3r/GUI/GLTexture.cpp index b9eb118a9..593362e54 100644 --- a/xs/src/slic3r/GUI/GLTexture.cpp +++ b/xs/src/slic3r/GUI/GLTexture.cpp @@ -5,6 +5,7 @@ #include <wx/image.h> #include <vector> +#include <algorithm> namespace Slic3r { namespace GUI { @@ -22,7 +23,7 @@ GLTexture::~GLTexture() reset(); } -bool GLTexture::load_from_file(const std::string& filename) +bool GLTexture::load_from_file(const std::string& filename, bool generate_mipmaps) { reset(); @@ -68,10 +69,20 @@ bool GLTexture::load_from_file(const std::string& filename) // sends data to gpu ::glGenTextures(1, &m_id); ::glBindTexture(GL_TEXTURE_2D, m_id); - ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); + if (generate_mipmaps) + { + // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards + _generate_mipmaps(image); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } + else + { + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); + } + ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + ::glBindTexture(GL_TEXTURE_2D, 0); m_source = filename; @@ -134,5 +145,41 @@ void GLTexture::render_texture(unsigned int tex_id, float left, float right, flo ::glEnable(GL_LIGHTING); } +void GLTexture::_generate_mipmaps(wxImage& image) +{ + int w = image.GetWidth(); + int h = image.GetHeight(); + GLint level = 0; + std::vector<unsigned char> data(w * h * 4, 0); + + while ((w > 1) && (h > 1)) + { + ++level; + + w = std::max(w / 2, 1); + h = std::max(h / 2, 1); + + int n_pixels = w * h; + + image = image.ResampleBicubic(w, h); + + unsigned char* img_rgb = image.GetData(); + unsigned char* img_alpha = image.GetAlpha(); + + data.resize(n_pixels * 4); + for (int i = 0; i < n_pixels; ++i) + { + int data_id = i * 4; + int img_id = i * 3; + data[data_id + 0] = img_rgb[img_id + 0]; + data[data_id + 1] = img_rgb[img_id + 1]; + data[data_id + 2] = img_rgb[img_id + 2]; + data[data_id + 3] = (img_alpha != nullptr) ? img_alpha[i] : 255; + } + + ::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, (GLsizei)w, (GLsizei)h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data()); + } +} + } // namespace GUI } // namespace Slic3r diff --git a/xs/src/slic3r/GUI/GLTexture.hpp b/xs/src/slic3r/GUI/GLTexture.hpp index 3e3bf83f7..70480c605 100644 --- a/xs/src/slic3r/GUI/GLTexture.hpp +++ b/xs/src/slic3r/GUI/GLTexture.hpp @@ -3,10 +3,12 @@ #include <string> +class wxImage; + namespace Slic3r { namespace GUI { - struct GLTexture + class GLTexture { private: unsigned int m_id; @@ -18,7 +20,7 @@ namespace GUI { GLTexture(); ~GLTexture(); - bool load_from_file(const std::string& filename); + bool load_from_file(const std::string& filename, bool generate_mipmaps); void reset(); unsigned int get_id() const; @@ -27,6 +29,9 @@ namespace GUI { const std::string& get_source() const; static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top); + + private: + void _generate_mipmaps(wxImage& image); }; } // namespace GUI