From 6a06a2882c60ee39965c8b839621ff97038be671 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 16 May 2019 15:54:11 +0200 Subject: [PATCH 01/37] Camera refactoring: Frustrum calculations moved into Camera class --- src/slic3r/GUI/Camera.cpp | 43 ++++++++++++++++++++++----- src/slic3r/GUI/Camera.hpp | 7 +++-- src/slic3r/GUI/GLCanvas3D.cpp | 56 +++-------------------------------- 3 files changed, 44 insertions(+), 62 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index dd6cbefe19b..5f7a7ce4b2e 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -28,6 +28,8 @@ Camera::Camera() , inverted_phi(false) , m_theta(45.0f) , m_target(Vec3d::Zero()) + , m_view_matrix(Transform3d::Identity()) + , m_projection_matrix(Transform3d::Identity()) { } @@ -65,11 +67,6 @@ void Camera::set_theta(float theta, bool apply_limit) } } -void Camera::set_scene_box(const BoundingBoxf3& box) -{ - m_scene_box = box; -} - bool Camera::select_view(const std::string& direction) { const float* dir_vec = nullptr; @@ -111,13 +108,43 @@ void Camera::apply_view_matrix() const glsafe(::glLoadIdentity()); glsafe(::glRotatef(-m_theta, 1.0f, 0.0f, 0.0f)); // pitch - glsafe(::glRotatef(phi, 0.0f, 0.0f, 1.0f)); // yaw - glsafe(::glTranslated(-m_target(0), -m_target(1), -m_target(2))); + glsafe(::glRotatef(phi, 0.0f, 0.0f, 1.0f)); // yaw + + glsafe(::glTranslated(-m_target(0), -m_target(1), -m_target(2))); // target to origin glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, m_view_matrix.data())); } -void Camera::apply_ortho_projection(float x_min, float x_max, float y_min, float y_max, float z_min, float z_max) const +void Camera::apply_projection(const BoundingBoxf3& box) const +{ + switch (type) + { + case Ortho: + { + double w2 = (double)m_viewport[2]; + double h2 = (double)m_viewport[3]; + double two_zoom = 2.0 * zoom; + if (two_zoom != 0.0) + { + double inv_two_zoom = 1.0 / two_zoom; + w2 *= inv_two_zoom; + h2 *= inv_two_zoom; + } + + // FIXME: calculate a tighter value for depth will improve z-fighting + // Set at least some minimum depth in case the bounding box is empty to avoid an OpenGL driver error. + double depth = std::max(1.0, 5.0 * box.max_size()); + apply_ortho_projection(-w2, w2, -h2, h2, -depth, depth); + + break; + } +// case Perspective: +// { +// } + } +} + +void Camera::apply_ortho_projection(double x_min, double x_max, double y_min, double y_max, double z_min, double z_max) const { glsafe(::glMatrixMode(GL_PROJECTION)); glsafe(::glLoadIdentity()); diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 6e1b539ab60..f0d22fd67ac 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -46,7 +46,7 @@ public: void set_theta(float theta, bool apply_limit); const BoundingBoxf3& get_scene_box() const { return m_scene_box; } - void set_scene_box(const BoundingBoxf3& box); + void set_scene_box(const BoundingBoxf3& box){ m_scene_box = box; } bool select_view(const std::string& direction); @@ -62,7 +62,10 @@ public: void apply_viewport(int x, int y, unsigned int w, unsigned int h) const; void apply_view_matrix() const; - void apply_ortho_projection(float x_min, float x_max, float y_min, float y_max, float z_min, float z_max) const; + void apply_projection(const BoundingBoxf3& box) const; + +private: + void apply_ortho_projection(double x_min, double x_max, double y_min, double y_max, double z_min, double z_max) const; }; } // GUI diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index bb2cb5e2ddd..ed9c1bd60a5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1472,6 +1472,7 @@ BoundingBoxf3 GLCanvas3D::scene_bounding_box() const bb.min(2) = std::min(bb.min(2), -h); bb.max(2) = std::max(bb.max(2), h); } + return bb; } @@ -3593,59 +3594,10 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) // ensures that this canvas is current _set_current(); + + // updates camera m_camera.apply_viewport(0, 0, w, h); - - const BoundingBoxf3& bbox = _max_bounding_box(); - - switch (m_camera.type) - { - case Camera::Ortho: - { - float w2 = w; - float h2 = h; - float two_zoom = 2.0f * m_camera.zoom; - if (two_zoom != 0.0f) - { - float inv_two_zoom = 1.0f / two_zoom; - w2 *= inv_two_zoom; - h2 *= inv_two_zoom; - } - - // FIXME: calculate a tighter value for depth will improve z-fighting - // Set at least some minimum depth in case the bounding box is empty to avoid an OpenGL driver error. - float depth = std::max(1.f, 5.0f * (float)bbox.max_size()); - m_camera.apply_ortho_projection(-w2, w2, -h2, h2, -depth, depth); - - break; - } -// case Camera::Perspective: -// { -// float bbox_r = (float)bbox.radius(); -// float fov = PI * 45.0f / 180.0f; -// float fov_tan = tan(0.5f * fov); -// float cam_distance = 0.5f * bbox_r / fov_tan; -// m_camera.distance = cam_distance; -// -// float nr = cam_distance - bbox_r * 1.1f; -// float fr = cam_distance + bbox_r * 1.1f; -// if (nr < 1.0f) -// nr = 1.0f; -// -// if (fr < nr + 1.0f) -// fr = nr + 1.0f; -// -// float h2 = fov_tan * nr; -// float w2 = h2 * w / h; -// ::glFrustum(-w2, w2, -h2, h2, nr, fr); -// -// break; -// } - default: - { - throw std::runtime_error("Invalid camera type."); - break; - } - } + m_camera.apply_projection(_max_bounding_box()); m_dirty = false; } From ccc522dd2b59c70e29cffaaf390533097b98a91c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 20 May 2019 09:39:57 +0200 Subject: [PATCH 02/37] Added imgui debug dialog for camera statistics --- src/libslic3r/Technologies.hpp | 2 ++ src/slic3r/GUI/Camera.cpp | 27 ++++++++++++++++++++++++++- src/slic3r/GUI/Camera.hpp | 4 ++++ src/slic3r/GUI/GLCanvas3D.cpp | 4 ++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 3375a282b1e..fdc5ef7d27a 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -13,6 +13,8 @@ #define ENABLE_RENDER_SELECTION_CENTER 0 // Shows an imgui dialog with render related data #define ENABLE_RENDER_STATISTICS 0 +// Shows an imgui dialog with camera related data +#define ENABLE_CAMERA_STATISTICS 1 //==================== diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 5f7a7ce4b2e..a9edb762645 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -2,6 +2,9 @@ #include "Camera.hpp" #include "3DScene.hpp" +#if ENABLE_CAMERA_STATISTICS +#include "GUI_App.hpp" +#endif // ENABLE_CAMERA_STATISTICS #include @@ -109,7 +112,6 @@ void Camera::apply_view_matrix() const glsafe(::glRotatef(-m_theta, 1.0f, 0.0f, 0.0f)); // pitch glsafe(::glRotatef(phi, 0.0f, 0.0f, 1.0f)); // yaw - glsafe(::glTranslated(-m_target(0), -m_target(1), -m_target(2))); // target to origin glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, m_view_matrix.data())); @@ -144,6 +146,29 @@ void Camera::apply_projection(const BoundingBoxf3& box) const } } +#if ENABLE_CAMERA_STATISTICS +void Camera::debug_render() const +{ + ImGuiWrapper& imgui = *wxGetApp().imgui(); + imgui.set_next_window_bg_alpha(0.5f); + imgui.begin(std::string("Camera statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + + Vec3f position = get_position().cast(); + Vec3f target = m_target.cast(); + Vec3f forward = get_dir_forward().cast(); + Vec3f right = get_dir_right().cast(); + Vec3f up = get_dir_up().cast(); + + ImGui::InputFloat3("Position", position.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); + ImGui::InputFloat3("Target", target.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); + ImGui::Separator(); + ImGui::InputFloat3("Forward", forward.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); + ImGui::InputFloat3("Right", right.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); + ImGui::InputFloat3("Up", up.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); + imgui.end(); +} +#endif // ENABLE_CAMERA_STATISTICS + void Camera::apply_ortho_projection(double x_min, double x_max, double y_min, double y_max, double z_min, double z_max) const { glsafe(::glMatrixMode(GL_PROJECTION)); diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index f0d22fd67ac..1f217be280e 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -64,6 +64,10 @@ public: void apply_view_matrix() const; void apply_projection(const BoundingBoxf3& box) const; +#if ENABLE_CAMERA_STATISTICS + void debug_render() const; +#endif // ENABLE_CAMERA_STATISTICS + private: void apply_ortho_projection(double x_min, double x_max, double y_min, double y_max, double z_min, double z_max) const; }; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index ed9c1bd60a5..f01d1a3adae 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1700,6 +1700,10 @@ void GLCanvas3D::render() imgui.end(); #endif // ENABLE_RENDER_STATISTICS +#if ENABLE_CAMERA_STATISTICS + m_camera.debug_render(); +#endif // ENABLE_CAMERA_STATISTICS + wxGetApp().imgui()->render(); m_canvas->SwapBuffers(); From 76abf5c2852107d6f8308587ed93b085dbc1c2c3 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 21 May 2019 14:19:03 +0200 Subject: [PATCH 03/37] Use texture compression on GPU --- src/libslic3r/Technologies.hpp | 6 ++++- src/slic3r/GUI/GLCanvas3D.cpp | 24 +++++++++++++++++-- src/slic3r/GUI/GLCanvas3DManager.cpp | 36 +++++++++++++++++----------- src/slic3r/GUI/GLCanvas3DManager.hpp | 15 ++++++++---- src/slic3r/GUI/GLTexture.cpp | 35 +++++++++++++++++++++++++++ src/slic3r/GUI/ImGuiWrapper.cpp | 7 ++++++ 6 files changed, 102 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index bffc45cde7e..3c5626a09d1 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -12,7 +12,7 @@ // Renders a small sphere in the center of the bounding box of the current selection when no gizmo is active #define ENABLE_RENDER_SELECTION_CENTER 0 // Shows an imgui dialog with render related data -#define ENABLE_RENDER_STATISTICS 0 +#define ENABLE_RENDER_STATISTICS 1 //==================== @@ -46,4 +46,8 @@ #define ENABLE_SVG_ICONS (1 && ENABLE_1_42_0_ALPHA8 && ENABLE_TEXTURES_FROM_SVG) +// Enable saving textures on GPU in compressed format +#define ENABLE_COMPRESSED_TEXTURES 1 + + #endif // _technologies_h_ diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 26d205055e7..bac3a3c64f3 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -864,7 +864,14 @@ bool GLCanvas3D::WarningTexture::_generate(const std::string& msg_utf8, const GL glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); glsafe(::glGenTextures(1, &m_id)); glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id)); +#if ENABLE_COMPRESSED_TEXTURES + if (GLEW_EXT_texture_compression_s3tc) + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); + else + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); +#else glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); +#endif // ENABLE_COMPRESSED_TEXTURES glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); @@ -1147,7 +1154,14 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); glsafe(::glGenTextures(1, &m_id)); glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id)); +#if ENABLE_COMPRESSED_TEXTURES + if (GLEW_EXT_texture_compression_s3tc) + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); + else + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); +#else glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); +#endif // ENABLE_COMPRESSED_TEXTURES glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); @@ -1691,11 +1705,17 @@ void GLCanvas3D::render() ImGuiWrapper& imgui = *wxGetApp().imgui(); imgui.set_next_window_bg_alpha(0.5f); imgui.begin(std::string("Render statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); - imgui.text(_(L("Last frame")) +": "); + imgui.text("Last frame: "); ImGui::SameLine(); imgui.text(std::to_string(m_render_stats.last_frame)); ImGui::SameLine(); - imgui.text(" "+_(L("ms"))); + imgui.text(" ms"); +#if ENABLE_COMPRESSED_TEXTURES + ImGui::Separator(); + imgui.text("Textures: "); + ImGui::SameLine(); + imgui.text(GLCanvas3DManager::are_compressed_textures_supported() ? "Compressed" : "Uncompressed"); +#endif // ENABLE_COMPRESSED_TEXTURES imgui.end(); #endif // ENABLE_RENDER_STATISTICS diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index e409bed0dd9..5f4391a5e24 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -111,6 +111,9 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten } GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown; +#if ENABLE_COMPRESSED_TEXTURES +bool GLCanvas3DManager::s_compressed_textures_supported = false; +#endif // ENABLE_COMPRESSED_TEXTURES GLCanvas3DManager::GLCanvas3DManager() : m_context(nullptr) @@ -134,7 +137,7 @@ bool GLCanvas3DManager::add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLTo if (canvas == nullptr) return false; - if (_get_canvas(canvas) != m_canvases.end()) + if (do_get_canvas(canvas) != m_canvases.end()) return false; GLCanvas3D* canvas3D = new GLCanvas3D(canvas, bed, camera, view_toolbar); @@ -159,7 +162,7 @@ bool GLCanvas3DManager::add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLTo bool GLCanvas3DManager::remove(wxGLCanvas* canvas) { - CanvasesMap::iterator it = _get_canvas(canvas); + CanvasesMap::iterator it = do_get_canvas(canvas); if (it == m_canvases.end()) return false; @@ -195,6 +198,12 @@ void GLCanvas3DManager::init_gl() m_use_legacy_opengl = (config == nullptr) || (config->get("use_legacy_opengl") == "1"); m_use_VBOs = !m_use_legacy_opengl && m_gl_info.is_version_greater_or_equal_to(2, 0); m_gl_initialized = true; +#if ENABLE_COMPRESSED_TEXTURES + if (GLEW_EXT_texture_compression_s3tc) + s_compressed_textures_supported = true; + else + s_compressed_textures_supported = false; +#endif // ENABLE_COMPRESSED_TEXTURES } } @@ -205,16 +214,16 @@ std::string GLCanvas3DManager::get_gl_info(bool format_as_html, bool extensions) bool GLCanvas3DManager::init(wxGLCanvas* canvas) { - CanvasesMap::const_iterator it = _get_canvas(canvas); + CanvasesMap::const_iterator it = do_get_canvas(canvas); if (it != m_canvases.end()) - return (it->second != nullptr) ? _init(*it->second) : false; + return (it->second != nullptr) ? init(*it->second) : false; else return false; } GLCanvas3D* GLCanvas3DManager::get_canvas(wxGLCanvas* canvas) { - CanvasesMap::const_iterator it = _get_canvas(canvas); + CanvasesMap::const_iterator it = do_get_canvas(canvas); return (it != m_canvases.end()) ? it->second : nullptr; } @@ -224,29 +233,28 @@ wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent) if (s_multisample == MS_Unknown) { - _detect_multisample(attribList); - // debug output - std::cout << "Multisample " << (can_multisample() ? "enabled" : "disabled") << std::endl; + detect_multisample(attribList); +// // debug output +// std::cout << "Multisample " << (can_multisample() ? "enabled" : "disabled") << std::endl; } - if (! can_multisample()) { + if (! can_multisample()) attribList[4] = 0; - } return new wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS); } -GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::_get_canvas(wxGLCanvas* canvas) +GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::do_get_canvas(wxGLCanvas* canvas) { return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas); } -GLCanvas3DManager::CanvasesMap::const_iterator GLCanvas3DManager::_get_canvas(wxGLCanvas* canvas) const +GLCanvas3DManager::CanvasesMap::const_iterator GLCanvas3DManager::do_get_canvas(wxGLCanvas* canvas) const { return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas); } -bool GLCanvas3DManager::_init(GLCanvas3D& canvas) +bool GLCanvas3DManager::init(GLCanvas3D& canvas) { if (!m_gl_initialized) init_gl(); @@ -254,7 +262,7 @@ bool GLCanvas3DManager::_init(GLCanvas3D& canvas) return canvas.init(m_use_VBOs, m_use_legacy_opengl); } -void GLCanvas3DManager::_detect_multisample(int* attribList) +void GLCanvas3DManager::detect_multisample(int* attribList) { int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER; const AppConfig* app_config = GUI::get_app_config(); diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index 75647e6b258..d391cd60c71 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -60,6 +60,9 @@ class GLCanvas3DManager bool m_use_legacy_opengl; bool m_use_VBOs; static EMultisampleState s_multisample; +#if ENABLE_COMPRESSED_TEXTURES + static bool s_compressed_textures_supported; +#endif // ENABLE_COMPRESSED_TEXTURES public: GLCanvas3DManager(); @@ -79,14 +82,18 @@ public: GLCanvas3D* get_canvas(wxGLCanvas* canvas); static bool can_multisample() { return s_multisample == MS_Enabled; } +#if ENABLE_COMPRESSED_TEXTURES + static bool are_compressed_textures_supported() { return s_compressed_textures_supported; } +#endif // ENABLE_COMPRESSED_TEXTURES + static wxGLCanvas* create_wxglcanvas(wxWindow *parent); private: - CanvasesMap::iterator _get_canvas(wxGLCanvas* canvas); - CanvasesMap::const_iterator _get_canvas(wxGLCanvas* canvas) const; + CanvasesMap::iterator do_get_canvas(wxGLCanvas* canvas); + CanvasesMap::const_iterator do_get_canvas(wxGLCanvas* canvas) const; - bool _init(GLCanvas3D& canvas); - static void _detect_multisample(int* attribList); + bool init(GLCanvas3D& canvas); + static void detect_multisample(int* attribList); }; } // namespace GUI diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 2fff0869adf..f7d2edfe7ba 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -178,7 +178,14 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vectorTexID = (ImTextureID)(intptr_t)m_font_texture; From d6375831ef098841a50d80348f3803a7dc1d1a1c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 22 May 2019 14:42:38 +0200 Subject: [PATCH 04/37] Prototype of scale to fit print volume command --- src/libslic3r/Technologies.hpp | 6 +- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 13 ++++ src/slic3r/GUI/Plater.cpp | 24 ++++++- src/slic3r/GUI/Plater.hpp | 3 + src/slic3r/GUI/Selection.cpp | 81 ++++++++++++++++++++--- src/slic3r/GUI/Selection.hpp | 3 + 6 files changed, 119 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 3c5626a09d1..0bf984b1bf7 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -12,7 +12,7 @@ // Renders a small sphere in the center of the bounding box of the current selection when no gizmo is active #define ENABLE_RENDER_SELECTION_CENTER 0 // Shows an imgui dialog with render related data -#define ENABLE_RENDER_STATISTICS 1 +#define ENABLE_RENDER_STATISTICS 0 //==================== @@ -47,7 +47,9 @@ // Enable saving textures on GPU in compressed format -#define ENABLE_COMPRESSED_TEXTURES 1 +#define ENABLE_COMPRESSED_TEXTURES 0 +// Enable scale object to fit print volume +#define ENABLE_SCALE_TO_FIT_PRINT_VOLUME 1 #endif // _technologies_h_ diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 1a431708aa7..ceffd6e0d3f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -847,6 +847,19 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt, GLCanvas3D& canvas) break; } +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME + case 'F': + case 'f': + { + if (m_current == Scale) + { + wxGetApp().plater()->scale_selection_to_fit_print_volume(); + processed = true; + } + + break; + } +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME } } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 1a5c3224636..05b378407b5 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1286,7 +1286,10 @@ struct Plater::priv void sla_optimize_rotation(); void split_object(); void split_volume(); - bool background_processing_enabled() const { return this->get_config("background_processing") == "1"; } +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME + void scale_selection_to_fit_print_volume(); +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME + bool background_processing_enabled() const { return this->get_config("background_processing") == "1"; } void update_print_volume_state(); void schedule_background_process(); // Update background processing thread from the current config and Model. @@ -2346,6 +2349,13 @@ void Plater::priv::split_volume() wxGetApp().obj_list()->split(); } +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME +void Plater::priv::scale_selection_to_fit_print_volume() +{ + this->view3D->get_canvas3d()->get_selection().scale_to_fit_print_volume(*config); +} +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME + void Plater::priv::schedule_background_process() { delayed_error_message.clear(); @@ -3008,6 +3018,11 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ sidebar->obj_list()->append_menu_item_fix_through_netfabb(menu); +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME + append_menu_item(menu, wxID_ANY, _(L("Scale to print volume")), _(L("Scale the selected object to fit the print volume")), + [this](wxCommandEvent&) { scale_selection_to_fit_print_volume(); }, "", menu); +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME + wxMenu* mirror_menu = new wxMenu(); if (mirror_menu == nullptr) return false; @@ -3447,6 +3462,13 @@ bool Plater::is_selection_empty() const return p->get_selection().is_empty() || p->get_selection().is_wipe_tower(); } +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME +void Plater::scale_selection_to_fit_print_volume() +{ + p->scale_selection_to_fit_print_volume(); +} +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME + void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper, bool keep_lower, bool rotate_lower) { wxCHECK_RET(obj_idx < p->model.objects.size(), "obj_idx out of bounds"); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index bc6d4b942d4..b836649dbe1 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -162,6 +162,9 @@ public: void decrease_instances(size_t num = 1); void set_number_of_copies(/*size_t num*/); bool is_selection_empty() const; +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME + void scale_selection_to_fit_print_volume(); +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME void cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 00fbaa42a59..836f1d5727a 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -662,14 +662,34 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type { GLVolume &volume = *(*m_volumes)[i]; if (is_single_full_instance()) { - assert(transformation_type.absolute()); - if (transformation_type.world() && (std::abs(scale.x() - scale.y()) > EPSILON || std::abs(scale.x() - scale.z()) > EPSILON)) { - // Non-uniform scaling. Transform the scaling factors into the local coordinate system. - // This is only possible, if the instance rotation is mulitples of ninety degrees. - assert(Geometry::is_rotation_ninety_degrees(volume.get_instance_rotation())); - volume.set_instance_scaling_factor((volume.get_instance_transformation().get_matrix(true, false, true, true).matrix().block<3, 3>(0, 0).transpose() * scale).cwiseAbs()); - } else - volume.set_instance_scaling_factor(scale); +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME + if (transformation_type.relative()) + { + Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale); + Eigen::Matrix new_matrix = (m * m_cache.volumes_data[i].get_instance_scale_matrix()).matrix().block(0, 0, 3, 3); + // extracts scaling factors from the composed transformation + Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm()); + if (transformation_type.joint()) + volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); + + volume.set_instance_scaling_factor(new_scale); + } + else + { +#else + assert(transformation_type.absolute()); +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME + if (transformation_type.world() && (std::abs(scale.x() - scale.y()) > EPSILON || std::abs(scale.x() - scale.z()) > EPSILON)) { + // Non-uniform scaling. Transform the scaling factors into the local coordinate system. + // This is only possible, if the instance rotation is mulitples of ninety degrees. + assert(Geometry::is_rotation_ninety_degrees(volume.get_instance_rotation())); + volume.set_instance_scaling_factor((volume.get_instance_transformation().get_matrix(true, false, true, true).matrix().block<3, 3>(0, 0).transpose() * scale).cwiseAbs()); + } + else + volume.set_instance_scaling_factor(scale); +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME + } +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME } else if (is_single_volume() || is_single_modifier()) volume.set_volume_scaling_factor(scale); @@ -713,6 +733,51 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type this->set_bounding_boxes_dirty(); } +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME +void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config) +{ + if (is_empty() || (m_mode == Volume)) + return; + + // adds 1/100th of a mm on all sides to avoid false out of print volume detections due to floating-point roundings + Vec3d box_size = get_bounding_box().size() + 0.01 * Vec3d::Ones(); + + const ConfigOptionPoints* opt = dynamic_cast(config.option("bed_shape")); + if (opt != nullptr) + { + BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); + BoundingBoxf3 print_volume(Vec3d(unscale(bed_box_2D.min(0)), unscale(bed_box_2D.min(1)), 0.0), Vec3d(unscale(bed_box_2D.max(0)), unscale(bed_box_2D.max(1)), config.opt_float("max_print_height"))); + Vec3d print_volume_size = print_volume.size(); + double sx = (box_size(0) != 0.0) ? print_volume_size(0) / box_size(0) : 0.0; + double sy = (box_size(1) != 0.0) ? print_volume_size(1) / box_size(1) : 0.0; + double sz = (box_size(2) != 0.0) ? print_volume_size(2) / box_size(2) : 0.0; + if ((sx != 0.0) && (sy != 0.0) && (sz != 0.0)) + { + double s = std::min(sx, std::min(sy, sz)); + if (s != 1.0) + { + TransformationType type; + type.set_world(); + type.set_relative(); + type.set_joint(); + + // apply scale + start_dragging(); + scale(s * Vec3d::Ones(), type); + wxGetApp().plater()->canvas3D()->do_scale(); + + // center selection on print bed + start_dragging(); + translate(print_volume.center() - get_bounding_box().center()); + wxGetApp().plater()->canvas3D()->do_move(); + + wxGetApp().obj_manipul()->set_dirty(); + } + } + } +} +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME + void Selection::mirror(Axis axis) { if (!m_valid) diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 99d939acc56..03967b4d4c4 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -287,6 +287,9 @@ public: void rotate(const Vec3d& rotation, TransformationType transformation_type); void flattening_rotate(const Vec3d& normal); void scale(const Vec3d& scale, TransformationType transformation_type); +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME + void scale_to_fit_print_volume(const DynamicPrintConfig& config); +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME void mirror(Axis axis); void translate(unsigned int object_idx, const Vec3d& displacement); From 59e6ac0428835967f695f01e685e8038903fc389 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 23 May 2019 09:20:11 +0200 Subject: [PATCH 05/37] 1) Added Scale to print volume menu item to objects list context menu 2) Disable [F] key when scale sizmo is dragging --- src/slic3r/GUI/GUI_ObjectList.cpp | 12 ++++++++++++ src/slic3r/GUI/GUI_ObjectList.hpp | 3 +++ src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 4 +++- src/slic3r/GUI/Plater.cpp | 3 +-- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 5a837f14dd1..d49198ca8c9 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1,3 +1,4 @@ +#include "libslic3r/libslic3r.h" #include "GUI_ObjectList.hpp" #include "GUI_ObjectManipulation.hpp" #include "GUI_App.hpp" @@ -1283,6 +1284,14 @@ void ObjectList::append_menu_item_delete(wxMenu* menu) [this](wxCommandEvent&) { remove(); }, "", menu); } +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME +void ObjectList::append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu) +{ + append_menu_item(menu, wxID_ANY, _(L("Scale to print volume")), _(L("Scale the selected object to fit the print volume")), + [this](wxCommandEvent&) { wxGetApp().plater()->scale_selection_to_fit_print_volume(); }, "", menu); +} +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME + void ObjectList::create_object_popupmenu(wxMenu *menu) { #ifdef __WXOSX__ @@ -1291,6 +1300,9 @@ void ObjectList::create_object_popupmenu(wxMenu *menu) append_menu_item_export_stl(menu); append_menu_item_fix_through_netfabb(menu); +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME + append_menu_item_scale_selection_to_fit_print_volume(menu); +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME // Split object to parts m_menu_item_split = append_menu_item_split(menu); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 0dcfe256002..d030b5c5121 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -207,6 +207,9 @@ public: void append_menu_item_export_stl(wxMenu* menu) const ; void append_menu_item_change_extruder(wxMenu* menu) const; void append_menu_item_delete(wxMenu* menu); +#if ENABLE_SCALE_TO_FIT_PRINT_VOLUME + void append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu); +#endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME void create_object_popupmenu(wxMenu *menu); void create_sla_object_popupmenu(wxMenu*menu); void create_part_popupmenu(wxMenu*menu); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index ceffd6e0d3f..49262932470 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -853,7 +853,9 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt, GLCanvas3D& canvas) { if (m_current == Scale) { - wxGetApp().plater()->scale_selection_to_fit_print_volume(); + if (!is_dragging()) + wxGetApp().plater()->scale_selection_to_fit_print_volume(); + processed = true; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 22f239516e5..c82955b097b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3021,8 +3021,7 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ sidebar->obj_list()->append_menu_item_fix_through_netfabb(menu); #if ENABLE_SCALE_TO_FIT_PRINT_VOLUME - append_menu_item(menu, wxID_ANY, _(L("Scale to print volume")), _(L("Scale the selected object to fit the print volume")), - [this](wxCommandEvent&) { scale_selection_to_fit_print_volume(); }, "", menu); + sidebar->obj_list()->append_menu_item_scale_selection_to_fit_print_volume(menu); #endif // ENABLE_SCALE_TO_FIT_PRINT_VOLUME wxMenu* mirror_menu = new wxMenu(); From 15edeb87f54a601ab22a99f0e37cd5e658f0035f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 23 May 2019 13:49:57 +0200 Subject: [PATCH 06/37] Max texture size dependent on OpenGL version on Win and Linux and on retina monitors on Mac --- src/libslic3r/Technologies.hpp | 7 +- src/slic3r/GUI/3DBed.cpp | 8 ++ src/slic3r/GUI/3DScene.cpp | 4 + src/slic3r/GUI/GLCanvas3D.cpp | 7 +- src/slic3r/GUI/GLCanvas3DManager.cpp | 155 +++++++++++++++++++++++++++ src/slic3r/GUI/GLCanvas3DManager.hpp | 47 ++++++++ src/slic3r/GUI/GLTexture.cpp | 18 ++++ 7 files changed, 243 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 0bf984b1bf7..e571965549e 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -12,7 +12,7 @@ // Renders a small sphere in the center of the bounding box of the current selection when no gizmo is active #define ENABLE_RENDER_SELECTION_CENTER 0 // Shows an imgui dialog with render related data -#define ENABLE_RENDER_STATISTICS 0 +#define ENABLE_RENDER_STATISTICS 1 //==================== @@ -47,7 +47,10 @@ // Enable saving textures on GPU in compressed format -#define ENABLE_COMPRESSED_TEXTURES 0 +#define ENABLE_COMPRESSED_TEXTURES 1 + +// Enable texture max size to be dependent on detected OpenGL version +#define ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION 1 // Enable scale object to fit print volume #define ENABLE_SCALE_TO_FIT_PRINT_VOLUME 1 diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 8392e534a46..2f20a65d906 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -493,6 +493,13 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const std::string model_path = resources_dir() + "/models/" + key; +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION + // use anisotropic filter if graphic card allows + GLfloat max_anisotropy = GLCanvas3DManager::get_gl_info().get_max_anisotropy(); + + // use higher resolution images if graphic card and opengl version allow + GLint max_tex_size = GLCanvas3DManager::get_gl_info().get_max_tex_size(); +#else // use anisotropic filter if graphic card allows GLfloat max_anisotropy = 0.0f; if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) @@ -504,6 +511,7 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const // clamp or the texture generation becomes too slow max_tex_size = std::min(max_tex_size, 8192); +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION std::string filename = tex_path + ".svg"; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 59480de1ce8..37e022329c6 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -2026,7 +2026,11 @@ bool GLBed::on_init_from_file(const std::string& filename, bool useVBOs) std::string _3DScene::get_gl_info(bool format_as_html, bool extensions) { +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION + return Slic3r::GUI::GLCanvas3DManager::get_gl_info().to_string(format_as_html, extensions); +#else return s_canvas_mgr.get_gl_info(format_as_html, extensions); +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION } bool _3DScene::add_canvas(wxGLCanvas* canvas, GUI::Bed3D& bed, GUI::Camera& camera, GUI::GLToolbar& view_toolbar) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index bac3a3c64f3..0630e42656f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1714,8 +1714,13 @@ void GLCanvas3D::render() ImGui::Separator(); imgui.text("Textures: "); ImGui::SameLine(); - imgui.text(GLCanvas3DManager::are_compressed_textures_supported() ? "Compressed" : "Uncompressed"); + imgui.text(GLCanvas3DManager::are_compressed_textures_supported() ? "compressed" : "uncompressed"); #endif // ENABLE_COMPRESSED_TEXTURES +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION + imgui.text("Max texture size: "); + ImGui::SameLine(); + imgui.text(std::to_string(GLCanvas3DManager::get_gl_info().get_max_tex_size())); +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION imgui.end(); #endif // ENABLE_RENDER_STATISTICS diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index 5f4391a5e24..d213990ba36 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -15,17 +15,115 @@ #include #include +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION +#ifdef __APPLE__ +#include "../Utils/MacDarkMode.hpp" +#endif // __APPLE__ +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION + namespace Slic3r { namespace GUI { GLCanvas3DManager::GLInfo::GLInfo() +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION + : m_detected(false) + , m_version("") + , m_glsl_version("") + , m_vendor("") + , m_renderer("") + , m_max_tex_size(0) + , m_max_anisotropy(0.0f) +#else : version("") , glsl_version("") , vendor("") , renderer("") +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION { } +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION +const std::string& GLCanvas3DManager::GLInfo::get_version() const +{ + if (!m_detected) + detect(); + + return m_version; +} + +const std::string& GLCanvas3DManager::GLInfo::get_glsl_version() const +{ + if (!m_detected) + detect(); + + return m_glsl_version; +} + +const std::string& GLCanvas3DManager::GLInfo::get_vendor() const +{ + if (!m_detected) + detect(); + + return m_vendor; +} + +const std::string& GLCanvas3DManager::GLInfo::get_renderer() const +{ + if (!m_detected) + detect(); + + return m_renderer; +} + +int GLCanvas3DManager::GLInfo::get_max_tex_size() const +{ + if (!m_detected) + detect(); + + // clamp to avoid the texture generation become too slow and use too much GPU memory +#ifdef __APPLE__ + // and use smaller texture for non retina systems + return (Slic3r::GUI::mac_max_scaling_factor() > 1.0) ? std::min(m_max_tex_size, 8192) : std::min(m_max_tex_size / 2, 4096); +#else + // and use smaller texture for older OpenGL versions + return is_version_greater_or_equal_to(3, 0) ? std::min(m_max_tex_size, 8192) : std::min(m_max_tex_size / 2, 4096); +#endif // __APPLE__ +} + +float GLCanvas3DManager::GLInfo::get_max_anisotropy() const +{ + if (!m_detected) + detect(); + + return m_max_anisotropy; +} + +void GLCanvas3DManager::GLInfo::detect() const +{ + const char* data = (const char*)::glGetString(GL_VERSION); + if (data != nullptr) + m_version = data; + + data = (const char*)::glGetString(GL_SHADING_LANGUAGE_VERSION); + if (data != nullptr) + m_glsl_version = data; + + data = (const char*)::glGetString(GL_VENDOR); + if (data != nullptr) + m_vendor = data; + + data = (const char*)::glGetString(GL_RENDERER); + if (data != nullptr) + m_renderer = data; + + glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_max_tex_size)); + + if (GLEW_EXT_texture_filter_anisotropic) + glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_max_anisotropy)); + + m_detected = true; +} +#else void GLCanvas3DManager::GLInfo::detect() { const char* data = (const char*)::glGetString(GL_VERSION); @@ -44,7 +142,40 @@ void GLCanvas3DManager::GLInfo::detect() if (data != nullptr) renderer = data; } +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION +bool GLCanvas3DManager::GLInfo::is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const +{ + if (!m_detected) + detect(); + + std::vector tokens; + boost::split(tokens, m_version, boost::is_any_of(" "), boost::token_compress_on); + + if (tokens.empty()) + return false; + + std::vector numbers; + boost::split(numbers, tokens[0], boost::is_any_of("."), boost::token_compress_on); + + unsigned int gl_major = 0; + unsigned int gl_minor = 0; + + if (numbers.size() > 0) + gl_major = ::atoi(numbers[0].c_str()); + + if (numbers.size() > 1) + gl_minor = ::atoi(numbers[1].c_str()); + + if (gl_major < major) + return false; + else if (gl_major > major) + return true; + else + return gl_minor >= minor; +} +#else bool GLCanvas3DManager::GLInfo::is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const { std::vector tokens; @@ -72,9 +203,15 @@ bool GLCanvas3DManager::GLInfo::is_version_greater_or_equal_to(unsigned int majo else return gl_minor >= minor; } +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool extensions) const { +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION + if (!m_detected) + detect(); +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION + std::stringstream out; std::string h2_start = format_as_html ? "" : ""; @@ -84,10 +221,17 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten std::string line_end = format_as_html ? "
" : "\n"; out << h2_start << "OpenGL installation" << h2_end << line_end; +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION + out << b_start << "GL version: " << b_end << (m_version.empty() ? "N/A" : m_version) << line_end; + out << b_start << "Vendor: " << b_end << (m_vendor.empty() ? "N/A" : m_vendor) << line_end; + out << b_start << "Renderer: " << b_end << (m_renderer.empty() ? "N/A" : m_renderer) << line_end; + out << b_start << "GLSL version: " << b_end << (m_glsl_version.empty() ? "N/A" : m_glsl_version) << line_end; +#else out << b_start << "GL version: " << b_end << (version.empty() ? "N/A" : version) << line_end; out << b_start << "Vendor: " << b_end << (vendor.empty() ? "N/A" : vendor) << line_end; out << b_start << "Renderer: " << b_end << (renderer.empty() ? "N/A" : renderer) << line_end; out << b_start << "GLSL version: " << b_end << (glsl_version.empty() ? "N/A" : glsl_version) << line_end; +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION if (extensions) { @@ -114,6 +258,9 @@ GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas #if ENABLE_COMPRESSED_TEXTURES bool GLCanvas3DManager::s_compressed_textures_supported = false; #endif // ENABLE_COMPRESSED_TEXTURES +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION +GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info; +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION GLCanvas3DManager::GLCanvas3DManager() : m_context(nullptr) @@ -193,10 +340,16 @@ void GLCanvas3DManager::init_gl() if (!m_gl_initialized) { glewInit(); +#if !ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION m_gl_info.detect(); +#endif // !ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION const AppConfig* config = GUI::get_app_config(); m_use_legacy_opengl = (config == nullptr) || (config->get("use_legacy_opengl") == "1"); +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION + m_use_VBOs = !m_use_legacy_opengl && s_gl_info.is_version_greater_or_equal_to(2, 0); +#else m_use_VBOs = !m_use_legacy_opengl && m_gl_info.is_version_greater_or_equal_to(2, 0); +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION m_gl_initialized = true; #if ENABLE_COMPRESSED_TEXTURES if (GLEW_EXT_texture_compression_s3tc) @@ -207,10 +360,12 @@ void GLCanvas3DManager::init_gl() } } +#if !ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION std::string GLCanvas3DManager::get_gl_info(bool format_as_html, bool extensions) const { return m_gl_info.to_string(format_as_html, extensions); } +#endif // !ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION bool GLCanvas3DManager::init(wxGLCanvas* canvas) { diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index d391cd60c71..3ad30411c29 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -29,6 +29,39 @@ struct Camera; class GLCanvas3DManager { +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION +public: + class GLInfo + { + mutable bool m_detected; + + mutable std::string m_version; + mutable std::string m_glsl_version; + mutable std::string m_vendor; + mutable std::string m_renderer; + + mutable int m_max_tex_size; + mutable float m_max_anisotropy; + + public: + GLInfo(); + + const std::string& get_version() const; + const std::string& get_glsl_version() const; + const std::string& get_vendor() const; + const std::string& get_renderer() const; + + int get_max_tex_size() const; + float get_max_anisotropy() const; + + bool is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const; + + std::string to_string(bool format_as_html, bool extensions) const; + + private: + void detect() const; + }; +#else struct GLInfo { std::string version; @@ -43,7 +76,11 @@ class GLCanvas3DManager std::string to_string(bool format_as_html, bool extensions) const; }; +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION +private: +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION enum EMultisampleState : unsigned char { MS_Unknown, @@ -55,7 +92,11 @@ class GLCanvas3DManager CanvasesMap m_canvases; wxGLContext* m_context; +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION + static GLInfo s_gl_info; +#else GLInfo m_gl_info; +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION bool m_gl_initialized; bool m_use_legacy_opengl; bool m_use_VBOs; @@ -75,7 +116,9 @@ public: unsigned int count() const; void init_gl(); +#if !ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION std::string get_gl_info(bool format_as_html, bool extensions) const; +#endif // !ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION bool init(wxGLCanvas* canvas); @@ -88,6 +131,10 @@ public: static wxGLCanvas* create_wxglcanvas(wxWindow *parent); +#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION + static const GLInfo& get_gl_info() { return s_gl_info; } +#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION + private: CanvasesMap::iterator do_get_canvas(wxGLCanvas* canvas); CanvasesMap::const_iterator do_get_canvas(wxGLCanvas* canvas) const; diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index f7d2edfe7ba..2216a14f241 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -18,6 +18,10 @@ #include "libslic3r/Utils.hpp" +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#include +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + namespace Slic3r { namespace GUI { @@ -380,6 +384,10 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps) bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, unsigned int max_size_px) { +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + auto start_time = std::chrono::high_resolution_clock::now(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + NSVGimage* image = nsvgParseFromFile(filename.c_str(), "px", 96.0f); if (image == nullptr) { @@ -426,6 +434,11 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns #else glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); #endif // ENABLE_COMPRESSED_TEXTURES +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + auto end_time = std::chrono::high_resolution_clock::now(); + std::cout << "texture level 0 to GPU in: " << std::chrono::duration_cast(end_time - start_time).count() << std::endl; + start_time = end_time; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ if (use_mipmaps) { // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards @@ -468,6 +481,11 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns nsvgDeleteRasterizer(rast); nsvgDelete(image); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + end_time = std::chrono::high_resolution_clock::now(); + std::cout << "mipmaps to GPU in: " << std::chrono::duration_cast(end_time - start_time).count() << std::endl; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + return true; } From 168268202fbd3228b8e5af9e95a37efae9efef9b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 27 May 2019 09:20:48 +0200 Subject: [PATCH 07/37] Disabled debug render statistics dialog --- src/libslic3r/Technologies.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 6822582c86c..d7e5aed768e 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -12,7 +12,7 @@ // Renders a small sphere in the center of the bounding box of the current selection when no gizmo is active #define ENABLE_RENDER_SELECTION_CENTER 0 // Shows an imgui dialog with render related data -#define ENABLE_RENDER_STATISTICS 1 +#define ENABLE_RENDER_STATISTICS 0 //==================== From 4ab6ee114cee1e64caa0956d37d0ed796b715592 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 28 May 2019 12:53:16 +0200 Subject: [PATCH 08/37] Texture compression set as an option --- src/slic3r/GUI/3DBed.cpp | 4 ++ src/slic3r/GUI/GLCanvas3D.cpp | 36 +++++++++++-- src/slic3r/GUI/GLCanvas3D.hpp | 8 +++ src/slic3r/GUI/GLTexture.cpp | 64 +++++++++++++++-------- src/slic3r/GUI/GLTexture.hpp | 19 +++++++ src/slic3r/GUI/GLToolbar.cpp | 8 +++ src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 8 +++ src/slic3r/GUI/ImGuiWrapper.cpp | 10 +++- src/slic3r/GUI/ImGuiWrapper.hpp | 4 ++ 9 files changed, 133 insertions(+), 28 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 2f20a65d906..4c4e600e8e5 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -517,7 +517,11 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const if ((m_texture.get_id() == 0) || (m_texture.get_source() != filename)) { +#if ENABLE_COMPRESSED_TEXTURES + if (!m_texture.load_from_svg_file(filename, true, true, max_tex_size)) +#else if (!m_texture.load_from_svg_file(filename, true, max_tex_size)) +#endif // ENABLE_COMPRESSED_TEXTURES { render_custom(); return; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f64ed41a4a5..f7d685502a2 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -405,7 +405,11 @@ 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 ENABLE_COMPRESSED_TEXTURES + if (!m_tooltip_texture.load_from_file(filename, false, true)) +#else if (!m_tooltip_texture.load_from_file(filename, false)) +#endif // ENABLE_COMPRESSED_TEXTURES return; } @@ -437,7 +441,11 @@ 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 ENABLE_COMPRESSED_TEXTURES + if (!m_reset_texture.load_from_file(filename, false, true)) +#else if (!m_reset_texture.load_from_file(filename, false)) +#endif // ENABLE_COMPRESSED_TEXTURES return; } @@ -729,7 +737,11 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool } } +#if ENABLE_COMPRESSED_TEXTURES + generate(text, canvas, true, red_colored); // GUI::GLTexture::reset() is called at the beginning of generate(...) +#else _generate(text, canvas, red_colored); // GUI::GLTexture::reset() is called at the beginning of generate(...) +#endif // ENABLE_COMPRESSED_TEXTURES // save information for rescaling m_msg_text = text; @@ -790,7 +802,11 @@ static void msw_disable_cleartype(wxFont &font) } #endif /* __WXMSW__ */ +#if ENABLE_COMPRESSED_TEXTURES +bool GLCanvas3D::WarningTexture::generate(const std::string& msg_utf8, const GLCanvas3D& canvas, bool compress, bool red_colored/* = false*/) +#else bool GLCanvas3D::WarningTexture::_generate(const std::string& msg_utf8, const GLCanvas3D& canvas, const bool red_colored/* = false*/) +#endif // ENABLE_COMPRESSED_TEXTURES { reset(); @@ -865,7 +881,7 @@ bool GLCanvas3D::WarningTexture::_generate(const std::string& msg_utf8, const GL glsafe(::glGenTextures(1, &m_id)); glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id)); #if ENABLE_COMPRESSED_TEXTURES - if (GLEW_EXT_texture_compression_s3tc) + if (compress && GLEW_EXT_texture_compression_s3tc) glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); else glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); @@ -922,7 +938,11 @@ void GLCanvas3D::WarningTexture::msw_rescale(const GLCanvas3D& canvas) if (m_msg_text.empty()) return; +#if ENABLE_COMPRESSED_TEXTURES + generate(m_msg_text, canvas, true, m_is_colored_red); +#else _generate(m_msg_text, canvas, m_is_colored_red); +#endif // ENABLE_COMPRESSED_TEXTURES } const unsigned char GLCanvas3D::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 }; @@ -965,7 +985,11 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_values(const GCodePrevie } } +#if ENABLE_COMPRESSED_TEXTURES +bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector& tool_colors, const GLCanvas3D& canvas, bool compress) +#else bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector& tool_colors, const GLCanvas3D& canvas) +#endif // ENABLE_COMPRESSED_TEXTURES { reset(); @@ -1155,7 +1179,7 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c glsafe(::glGenTextures(1, &m_id)); glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id)); #if ENABLE_COMPRESSED_TEXTURES - if (GLEW_EXT_texture_compression_s3tc) + if (compress && GLEW_EXT_texture_compression_s3tc) glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); else glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); @@ -1714,9 +1738,9 @@ void GLCanvas3D::render() imgui.text(" ms"); #if ENABLE_COMPRESSED_TEXTURES ImGui::Separator(); - imgui.text("Textures: "); + imgui.text("Compressed textures: "); ImGui::SameLine(); - imgui.text(GLCanvas3DManager::are_compressed_textures_supported() ? "compressed" : "uncompressed"); + imgui.text(GLCanvas3DManager::are_compressed_textures_supported() ? "supported" : "not supported"); #endif // ENABLE_COMPRESSED_TEXTURES #if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION imgui.text("Max texture size: "); @@ -5698,7 +5722,11 @@ std::vector GLCanvas3D::_parse_colors(const std::vector& col void GLCanvas3D::_generate_legend_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors) { +#if ENABLE_COMPRESSED_TEXTURES + m_legend_texture.generate(preview_data, tool_colors, *this, true); +#else m_legend_texture.generate(preview_data, tool_colors, *this); +#endif // ENABLE_COMPRESSED_TEXTURES } void GLCanvas3D::_set_warning_texture(WarningTexture::Warning warning, bool state) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 51a36cf69f8..6d77a507f10 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -374,7 +374,11 @@ class GLCanvas3D std::vector m_warnings; // Generates the texture with given text. +#if ENABLE_COMPRESSED_TEXTURES + bool generate(const std::string& msg, const GLCanvas3D& canvas, bool compress, bool red_colored = false); +#else bool _generate(const std::string& msg, const GLCanvas3D& canvas, const bool red_colored = false); +#endif // ENABLE_COMPRESSED_TEXTURES }; class LegendTexture : public GUI::GLTexture @@ -397,7 +401,11 @@ class GLCanvas3D void fill_color_print_legend_values(const GCodePreviewData& preview_data, const GLCanvas3D& canvas, std::vector>& cp_legend_values); +#if ENABLE_COMPRESSED_TEXTURES + bool generate(const GCodePreviewData& preview_data, const std::vector& tool_colors, const GLCanvas3D& canvas, bool compress); +#else bool generate(const GCodePreviewData& preview_data, const std::vector& tool_colors, const GLCanvas3D& canvas); +#endif // ENABLE_COMPRESSED_TEXTURES void render(const GLCanvas3D& canvas) const; }; diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 2216a14f241..bdd7ee62485 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -18,10 +18,6 @@ #include "libslic3r/Utils.hpp" -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#include -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - namespace Slic3r { namespace GUI { @@ -40,7 +36,11 @@ GLTexture::~GLTexture() reset(); } +#if ENABLE_COMPRESSED_TEXTURES +bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps, bool compress) +#else bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps) +#endif // ENABLE_COMPRESSED_TEXTURES { reset(); @@ -48,12 +48,20 @@ bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps) return false; if (boost::algorithm::iends_with(filename, ".png")) +#if ENABLE_COMPRESSED_TEXTURES + return load_from_png(filename, use_mipmaps, compress); +#else return load_from_png(filename, use_mipmaps); +#endif // ENABLE_COMPRESSED_TEXTURES else return false; } +#if ENABLE_COMPRESSED_TEXTURES +bool GLTexture::load_from_svg_file(const std::string& filename, bool use_mipmaps, bool compress, unsigned int max_size_px) +#else bool GLTexture::load_from_svg_file(const std::string& filename, bool use_mipmaps, unsigned int max_size_px) +#endif // ENABLE_COMPRESSED_TEXTURES { reset(); @@ -61,12 +69,20 @@ bool GLTexture::load_from_svg_file(const std::string& filename, bool use_mipmaps return false; if (boost::algorithm::iends_with(filename, ".svg")) +#if ENABLE_COMPRESSED_TEXTURES + return load_from_svg(filename, use_mipmaps, compress, max_size_px); +#else return load_from_svg(filename, use_mipmaps, max_size_px); +#endif // ENABLE_COMPRESSED_TEXTURES else return false; } +#if ENABLE_COMPRESSED_TEXTURES +bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector& filenames, const std::vector>& states, unsigned int sprite_size_px, bool compress) +#else bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector& filenames, const std::vector>& states, unsigned int sprite_size_px) +#endif // ENABLE_COMPRESSED_TEXTURES { reset(); @@ -183,7 +199,7 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector(end_time - start_time).count() << std::endl; - start_time = end_time; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ if (use_mipmaps) { // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards @@ -455,7 +478,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns nsvgRasterize(rast, image, 0, 0, scale, data.data(), lod_w, lod_h, lod_w * 4); #if ENABLE_COMPRESSED_TEXTURES - if (GLEW_EXT_texture_compression_s3tc) + if (compress && GLEW_EXT_texture_compression_s3tc) glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); else glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); @@ -481,11 +504,6 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns nsvgDeleteRasterizer(rast); nsvgDelete(image); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - end_time = std::chrono::high_resolution_clock::now(); - std::cout << "mipmaps to GPU in: " << std::chrono::duration_cast(end_time - start_time).count() << std::endl; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - return true; } diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index e00b3a3bea1..b474f7b0537 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -38,8 +38,13 @@ namespace GUI { GLTexture(); virtual ~GLTexture(); +#if ENABLE_COMPRESSED_TEXTURES + bool load_from_file(const std::string& filename, bool use_mipmaps, bool compress); + bool load_from_svg_file(const std::string& filename, bool use_mipmaps, bool compress, unsigned int max_size_px); +#else bool load_from_file(const std::string& filename, bool use_mipmaps); bool load_from_svg_file(const std::string& filename, bool use_mipmaps, unsigned int max_size_px); +#endif // ENABLE_COMPRESSED_TEXTURES // meanings of states: (std::pair) // first field (int): // 0 -> no changes @@ -48,7 +53,11 @@ namespace GUI { // second field (bool): // false -> no changes // true -> add background color +#if ENABLE_COMPRESSED_TEXTURES + bool load_from_svg_files_as_sprites_array(const std::vector& filenames, const std::vector>& states, unsigned int sprite_size_px, bool compress); +#else bool load_from_svg_files_as_sprites_array(const std::vector& filenames, const std::vector>& states, unsigned int sprite_size_px); +#endif // ENABLE_COMPRESSED_TEXTURES void reset(); unsigned int get_id() const { return m_id; } @@ -61,10 +70,20 @@ namespace GUI { static void render_sub_texture(unsigned int tex_id, float left, float right, float bottom, float top, const Quad_UVs& uvs); protected: +#if ENABLE_COMPRESSED_TEXTURES + unsigned int generate_mipmaps(wxImage& image, bool compress); +#else unsigned int generate_mipmaps(wxImage& image); +#endif // ENABLE_COMPRESSED_TEXTURES + private: +#if ENABLE_COMPRESSED_TEXTURES + bool load_from_png(const std::string& filename, bool use_mipmaps, bool compress); + bool load_from_svg(const std::string& filename, bool use_mipmaps, bool compress, unsigned int max_size_px); +#else bool load_from_png(const std::string& filename, bool use_mipmaps); bool load_from_svg(const std::string& filename, bool use_mipmaps, unsigned int max_size_px); +#endif // ENABLE_COMPRESSED_TEXTURES }; } // namespace GUI diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 00cbdfec715..813a319b807 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -194,7 +194,11 @@ bool GLToolbar::init(const ItemsIconsTexture::Metadata& icons_texture, const Bac #endif // ENABLE_SVG_ICONS if (!background_texture.filename.empty()) +#if ENABLE_COMPRESSED_TEXTURES + res = m_background_texture.texture.load_from_file(path + background_texture.filename, false, true); +#else res = m_background_texture.texture.load_from_file(path + background_texture.filename, false); +#endif // ENABLE_COMPRESSED_TEXTURES if (res) m_background_texture.metadata = background_texture; @@ -1338,7 +1342,11 @@ bool GLToolbar::generate_icons_texture() const states.push_back(std::make_pair(1, true)); } +#if ENABLE_COMPRESSED_TEXTURES + bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, (unsigned int)(m_layout.icons_size * m_layout.scale), true); +#else bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, (unsigned int)(m_layout.icons_size * m_layout.scale)); +#endif // ENABLE_COMPRESSED_TEXTURES if (res) m_icons_texture_dirty = false; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 1006d2bd1e9..c254f5796d9 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -65,7 +65,11 @@ bool GLGizmosManager::init(GLCanvas3D& parent) if (!m_background_texture.metadata.filename.empty()) { +#if ENABLE_COMPRESSED_TEXTURES + if (!m_background_texture.texture.load_from_file(resources_dir() + "/icons/" + m_background_texture.metadata.filename, false, true)) +#else if (!m_background_texture.texture.load_from_file(resources_dir() + "/icons/" + m_background_texture.metadata.filename, false)) +#endif // ENABLE_COMPRESSED_TEXTURES { reset(); return false; @@ -1160,7 +1164,11 @@ bool GLGizmosManager::generate_icons_texture() const states.push_back(std::make_pair(0, false)); states.push_back(std::make_pair(0, true)); +#if ENABLE_COMPRESSED_TEXTURES + bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, (unsigned int)(m_overlay_icons_size * m_overlay_scale), true); +#else bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, (unsigned int)(m_overlay_icons_size * m_overlay_scale)); +#endif // ENABLE_COMPRESSED_TEXTURES if (res) m_icons_texture_dirty = false; diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 9202c0ac38a..7267da2956a 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -206,7 +206,11 @@ void ImGuiWrapper::new_frame() } if (m_font_texture == 0) { +#if ENABLE_COMPRESSED_TEXTURES + init_font(true); +#else init_font(); +#endif // ENABLE_COMPRESSED_TEXTURES } ImGui::NewFrame(); @@ -383,7 +387,11 @@ bool ImGuiWrapper::want_any_input() const return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput; } +#if ENABLE_COMPRESSED_TEXTURES +void ImGuiWrapper::init_font(bool compress) +#else void ImGuiWrapper::init_font() +#endif // ENABLE_COMPRESSED_TEXTURES { destroy_font(); @@ -413,7 +421,7 @@ void ImGuiWrapper::init_font() glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); #if ENABLE_COMPRESSED_TEXTURES - if (GLEW_EXT_texture_compression_s3tc) + if (compress && GLEW_EXT_texture_compression_s3tc) glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); else glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 37ef90ff350..a1e4048ac6f 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -77,7 +77,11 @@ public: bool want_any_input() const; private: +#if ENABLE_COMPRESSED_TEXTURES + void init_font(bool compress); +#else void init_font(); +#endif // ENABLE_COMPRESSED_TEXTURES void init_input(); void init_style(); void render_draw_data(ImDrawData *draw_data); From 5eab8cddfafb5147f8069e2d22443e313c00a281 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 28 May 2019 15:21:34 +0200 Subject: [PATCH 09/37] Application of anisotropy to textures moved into GLTexture methods --- src/slic3r/GUI/3DBed.cpp | 8 +++++++- src/slic3r/GUI/GLTexture.cpp | 13 ++++++++++--- src/slic3r/GUI/GLTexture.hpp | 4 ++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 4c4e600e8e5..91275f4e62a 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -494,16 +494,20 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const std::string model_path = resources_dir() + "/models/" + key; #if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION +#if !ENABLE_COMPRESSED_TEXTURES // use anisotropic filter if graphic card allows GLfloat max_anisotropy = GLCanvas3DManager::get_gl_info().get_max_anisotropy(); +#endif // !ENABLE_COMPRESSED_TEXTURES // use higher resolution images if graphic card and opengl version allow GLint max_tex_size = GLCanvas3DManager::get_gl_info().get_max_tex_size(); #else +#if !ENABLE_COMPRESSED_TEXTURES // use anisotropic filter if graphic card allows GLfloat max_anisotropy = 0.0f; if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy)); +#endif // !ENABLE_COMPRESSED_TEXTURES // use higher resolution images if graphic card allows GLint max_tex_size; @@ -518,7 +522,7 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const if ((m_texture.get_id() == 0) || (m_texture.get_source() != filename)) { #if ENABLE_COMPRESSED_TEXTURES - if (!m_texture.load_from_svg_file(filename, true, true, max_tex_size)) + if (!m_texture.load_from_svg_file(filename, true, true, true, max_tex_size)) #else if (!m_texture.load_from_svg_file(filename, true, max_tex_size)) #endif // ENABLE_COMPRESSED_TEXTURES @@ -527,12 +531,14 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const return; } +#if !ENABLE_COMPRESSED_TEXTURES if (max_anisotropy > 0.0f) { glsafe(::glBindTexture(GL_TEXTURE_2D, m_texture.get_id())); glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); } +#endif // !ENABLE_COMPRESSED_TEXTURES } if (!bottom) diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index bdd7ee62485..9c1e1f22ef8 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -58,7 +58,7 @@ bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps) } #if ENABLE_COMPRESSED_TEXTURES -bool GLTexture::load_from_svg_file(const std::string& filename, bool use_mipmaps, bool compress, unsigned int max_size_px) +bool GLTexture::load_from_svg_file(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px) #else bool GLTexture::load_from_svg_file(const std::string& filename, bool use_mipmaps, unsigned int max_size_px) #endif // ENABLE_COMPRESSED_TEXTURES @@ -70,7 +70,7 @@ bool GLTexture::load_from_svg_file(const std::string& filename, bool use_mipmaps if (boost::algorithm::iends_with(filename, ".svg")) #if ENABLE_COMPRESSED_TEXTURES - return load_from_svg(filename, use_mipmaps, compress, max_size_px); + return load_from_svg(filename, use_mipmaps, compress, apply_anisotropy, max_size_px); #else return load_from_svg(filename, use_mipmaps, max_size_px); #endif // ENABLE_COMPRESSED_TEXTURES @@ -411,7 +411,7 @@ bool GLTexture::load_from_png(const std::string& filename, bool use_mipmaps) } #if ENABLE_COMPRESSED_TEXTURES -bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, bool compress, unsigned int max_size_px) +bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px) #else bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, unsigned int max_size_px) #endif // ENABLE_COMPRESSED_TEXTURES @@ -455,6 +455,13 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns glsafe(::glGenTextures(1, &m_id)); glsafe(::glBindTexture(GL_TEXTURE_2D, m_id)); #if ENABLE_COMPRESSED_TEXTURES + if (apply_anisotropy) + { + GLfloat max_anisotropy = GLCanvas3DManager::get_gl_info().get_max_anisotropy(); + if (max_anisotropy > 1.0f) + glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); + } + if (compress && GLEW_EXT_texture_compression_s3tc) glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); else diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index b474f7b0537..032d19121ff 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -40,7 +40,7 @@ namespace GUI { #if ENABLE_COMPRESSED_TEXTURES bool load_from_file(const std::string& filename, bool use_mipmaps, bool compress); - bool load_from_svg_file(const std::string& filename, bool use_mipmaps, bool compress, unsigned int max_size_px); + bool load_from_svg_file(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px); #else bool load_from_file(const std::string& filename, bool use_mipmaps); bool load_from_svg_file(const std::string& filename, bool use_mipmaps, unsigned int max_size_px); @@ -79,7 +79,7 @@ namespace GUI { private: #if ENABLE_COMPRESSED_TEXTURES bool load_from_png(const std::string& filename, bool use_mipmaps, bool compress); - bool load_from_svg(const std::string& filename, bool use_mipmaps, bool compress, unsigned int max_size_px); + bool load_from_svg(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px); #else bool load_from_png(const std::string& filename, bool use_mipmaps); bool load_from_svg(const std::string& filename, bool use_mipmaps, unsigned int max_size_px); From 8231684ea448888e425e7a59a80aedce525a1cd1 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 31 May 2019 15:25:02 +0200 Subject: [PATCH 10/37] Asynchronous texture compression on CPU --- src/slic3r/GUI/3DBed.cpp | 4 + src/slic3r/GUI/GLTexture.cpp | 164 +++++- src/slic3r/GUI/GLTexture.hpp | 46 ++ src/stb_dxt/stb_dxt.h | 1049 ++++++++++++++++++++++++++++++++++ 4 files changed, 1256 insertions(+), 7 deletions(-) create mode 100644 src/stb_dxt/stb_dxt.h diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 91275f4e62a..e6589e5481a 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -540,6 +540,10 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const } #endif // !ENABLE_COMPRESSED_TEXTURES } +#if ENABLE_COMPRESSED_TEXTURES + else if (m_texture.unsent_compressed_data_available()) + m_texture.send_compressed_data_to_gpu(); +#endif // ENABLE_COMPRESSED_TEXTURES if (!bottom) { diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 9c1e1f22ef8..cc6bdc715a1 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -12,6 +12,12 @@ #include #include +#if ENABLE_COMPRESSED_TEXTURES +#include + +#define STB_DXT_IMPLEMENTATION +#include "stb_dxt/stb_dxt.h" +#endif // ENABLE_COMPRESSED_TEXTURES #include "nanosvg/nanosvg.h" #include "nanosvg/nanosvgrast.h" @@ -21,6 +27,86 @@ namespace Slic3r { namespace GUI { +#if ENABLE_COMPRESSED_TEXTURES +void GLTexture::Compressor::reset() +{ + // force compression completion, if any + m_abort_compressing = true; + // wait for compression completion, if any + while (m_is_compressing) {} + + m_levels.clear(); +} + +void GLTexture::Compressor::add_level(unsigned int w, unsigned int h, const std::vector& data) +{ + m_levels.emplace_back(w, h, data); +} + +void GLTexture::Compressor::start_compressing() +{ + m_is_compressing = true; + m_abort_compressing = false; + std::thread t(&GLTexture::Compressor::compress, this); + t.detach(); +} + +bool GLTexture::Compressor::unsent_compressed_data_available() const +{ + for (const Level& level : m_levels) + { + if (!level.sent_to_gpu && (level.compressed_data.size() > 0)) + return true; + } + + return false; +} + +void GLTexture::Compressor::send_compressed_data_to_gpu() +{ + glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); + glsafe(::glBindTexture(GL_TEXTURE_2D, m_texture.m_id)); + for (int i = 0; i < (int)m_levels.size(); ++i) + { + Level& level = m_levels[i]; + if (!level.sent_to_gpu && (level.compressed_data.size() > 0)) + { + glsafe(::glCompressedTexSubImage2D(GL_TEXTURE_2D, (GLint)i, 0, 0, (GLsizei)level.w, (GLsizei)level.h, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)level.compressed_data.size(), (const GLvoid*)level.compressed_data.data())); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (i > 0) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR)); + level.sent_to_gpu = true; + // we are done with the compressed data, we can discard it + level.compressed_data.clear(); + } + } + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); +} + +void GLTexture::Compressor::compress() +{ + // reference: https://github.com/Cyan4973/RygsDXTc + + for (Level& level : m_levels) + { + if (m_abort_compressing) + break; + + // stb_dxt library, despite claiming that the needed size of the destination buffer is equal to (source buffer size)/4, + // crashes if doing so, so we start with twice the required size + level.compressed_data = std::vector(level.w * level.h * 2, 0); + int compressed_size = 0; + rygCompress(level.compressed_data.data(), level.src_data.data(), level.w, level.h, 1, compressed_size); + level.compressed_data.resize(compressed_size); + + // we are done with the source data, we can discard it + level.src_data.clear(); + } + + m_is_compressing = false; + m_abort_compressing = false; +} +#endif // ENABLE_COMPRESSED_TEXTURES + GLTexture::Quad_UVs GLTexture::FullTextureUVs = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f } }; GLTexture::GLTexture() @@ -28,6 +114,9 @@ GLTexture::GLTexture() , m_width(0) , m_height(0) , m_source("") +#if ENABLE_COMPRESSED_TEXTURES + , m_compressor(*this) +#endif // ENABLE_COMPRESSED_TEXTURES { } @@ -249,8 +338,23 @@ void GLTexture::reset() m_width = 0; m_height = 0; m_source = ""; +#if ENABLE_COMPRESSED_TEXTURES + m_compressor.reset(); +#endif // ENABLE_COMPRESSED_TEXTURES } +#if ENABLE_COMPRESSED_TEXTURES +bool GLTexture::unsent_compressed_data_available() const +{ + return m_compressor.unsent_compressed_data_available(); +} + +void GLTexture::send_compressed_data_to_gpu() +{ + m_compressor.send_compressed_data_to_gpu(); +} +#endif // ENABLE_COMPRESSED_TEXTURES + void GLTexture::render_texture(unsigned int tex_id, float left, float right, float bottom, float top) { render_sub_texture(tex_id, left, right, bottom, top, FullTextureUVs); @@ -416,6 +520,8 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, unsigned int max_size_px) #endif // ENABLE_COMPRESSED_TEXTURES { + bool compression_enabled = compress && GLEW_EXT_texture_compression_s3tc; + NSVGimage* image = nsvgParseFromFile(filename.c_str(), "px", 96.0f); if (image == nullptr) { @@ -428,6 +534,22 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns m_width = (int)(scale * image->width); m_height = (int)(scale * image->height); + +#if ENABLE_COMPRESSED_TEXTURES + if (compression_enabled) + { + // the stb_dxt compression library seems to like only texture sizes which are a multiple of 4 + int width_rem = m_width % 4; + int height_rem = m_height % 4; + + if (width_rem != 0) + m_width += (4 - width_rem); + + if (height_rem != 0) + m_height += (4 - height_rem); + } +#endif // ENABLE_COMPRESSED_TEXTURES + int n_pixels = m_width * m_height; if (n_pixels <= 0) @@ -462,8 +584,13 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); } - if (compress && GLEW_EXT_texture_compression_s3tc) - glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); + if (compression_enabled) + { + // initializes the texture on GPU + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); + // and send the uncompressed data to the compressor + m_compressor.add_level((unsigned int)m_width, (unsigned int)m_height, data); + } else glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); #else @@ -475,7 +602,8 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns int lod_w = m_width; int lod_h = m_height; GLint level = 0; - while ((lod_w > 1) || (lod_h > 1)) + // we do not need to generate all levels down to 1x1 + while ((lod_w > 64) || (lod_h > 64)) { ++level; @@ -483,10 +611,19 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns lod_h = std::max(lod_h / 2, 1); scale /= 2.0f; +#if ENABLE_COMPRESSED_TEXTURES + data.resize(lod_w * lod_h * 4); +#endif // ENABLE_COMPRESSED_TEXTURES + nsvgRasterize(rast, image, 0, 0, scale, data.data(), lod_w, lod_h, lod_w * 4); #if ENABLE_COMPRESSED_TEXTURES - if (compress && GLEW_EXT_texture_compression_s3tc) - glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); + if (compression_enabled) + { + // initializes the texture on GPU + glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); + // and send the uncompressed data to the compressor + m_compressor.add_level((unsigned int)lod_w, (unsigned int)lod_h, data); + } else glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); #else @@ -494,8 +631,15 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns #endif // ENABLE_COMPRESSED_TEXTURES } - glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level)); - glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); +#if ENABLE_COMPRESSED_TEXTURES + if (!compression_enabled) + { +#endif // ENABLE_COMPRESSED_TEXTURES + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); +#if ENABLE_COMPRESSED_TEXTURES + } +#endif // ENABLE_COMPRESSED_TEXTURES } else { @@ -508,6 +652,12 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns m_source = filename; +#if ENABLE_COMPRESSED_TEXTURES + if (compression_enabled) + // start asynchronous compression + m_compressor.start_compressing(); +#endif // ENABLE_COMPRESSED_TEXTURES + nsvgDeleteRasterizer(rast); nsvgDelete(image); diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index 032d19121ff..f5cf13a455a 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -11,6 +11,42 @@ namespace GUI { class GLTexture { +#if ENABLE_COMPRESSED_TEXTURES + class Compressor + { + struct Level + { + unsigned int w; + unsigned int h; + std::vector src_data; + std::vector compressed_data; + bool sent_to_gpu; + + Level(unsigned int w, unsigned int h, const std::vector& data) : w(w), h(h), src_data(data), sent_to_gpu(false) {} + }; + + GLTexture& m_texture; + std::vector m_levels; + bool m_is_compressing; + bool m_abort_compressing; + + public: + explicit Compressor(GLTexture& texture) : m_texture(texture), m_is_compressing(false), m_abort_compressing(false) {} + + void reset(); + + void add_level(unsigned int w, unsigned int h, const std::vector& data); + + void start_compressing(); + + bool unsent_compressed_data_available() const; + void send_compressed_data_to_gpu(); + + private: + void compress(); + }; +#endif // ENABLE_COMPRESSED_TEXTURES + public: struct UV { @@ -33,6 +69,9 @@ namespace GUI { int m_width; int m_height; std::string m_source; +#if ENABLE_COMPRESSED_TEXTURES + Compressor m_compressor; +#endif // ENABLE_COMPRESSED_TEXTURES public: GLTexture(); @@ -66,6 +105,11 @@ namespace GUI { const std::string& get_source() const { return m_source; } +#if ENABLE_COMPRESSED_TEXTURES + bool unsent_compressed_data_available() const; + void send_compressed_data_to_gpu(); +#endif // ENABLE_COMPRESSED_TEXTURES + static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top); static void render_sub_texture(unsigned int tex_id, float left, float right, float bottom, float top, const Quad_UVs& uvs); @@ -80,6 +124,8 @@ namespace GUI { #if ENABLE_COMPRESSED_TEXTURES bool load_from_png(const std::string& filename, bool use_mipmaps, bool compress); bool load_from_svg(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px); + + friend class Compressor; #else bool load_from_png(const std::string& filename, bool use_mipmaps); bool load_from_svg(const std::string& filename, bool use_mipmaps, unsigned int max_size_px); diff --git a/src/stb_dxt/stb_dxt.h b/src/stb_dxt/stb_dxt.h new file mode 100644 index 00000000000..db19110f433 --- /dev/null +++ b/src/stb_dxt/stb_dxt.h @@ -0,0 +1,1049 @@ +// stb_dxt.h - Real-Time DXT1/DXT5 compressor +// Based on original by fabian "ryg" giesen v1.04 +// Custom version, modified by Yann Collet +// +/* + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + You can contact the author at : + - RygsDXTc source repository : http://code.google.com/p/rygsdxtc/ + +*/ +// use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation +// +// USAGE: +// call stb_compress_dxt_block() for every block (you must pad) +// source should be a 4x4 block of RGBA data in row-major order; +// A is ignored if you specify alpha=0; you can turn on dithering +// and "high quality" using mode. +// +// version history: +// v1.06 - (cyan) implement Fabian Giesen's comments +// v1.05 - (cyan) speed optimizations +// v1.04 - (ryg) default to no rounding bias for lerped colors (as per S3TC/DX10 spec); +// single color match fix (allow for inexact color interpolation); +// optimal DXT5 index finder; "high quality" mode that runs multiple refinement steps. +// v1.03 - (stb) endianness support +// v1.02 - (stb) fix alpha encoding bug +// v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom +// v1.00 - (stb) first release + +#ifndef STB_INCLUDE_STB_DXT_H +#define STB_INCLUDE_STB_DXT_H + + +//******************************************************************* +// Enable custom Optimisations +// Comment this define if you want to revert to ryg's original code +#define NEW_OPTIMISATIONS +//******************************************************************* + +// compression mode (bitflags) +#define STB_DXT_NORMAL 0 +#define STB_DXT_DITHER 1 // use dithering. dubious win. never use for normal maps and the like! +#define STB_DXT_HIGHQUAL 2 // high quality mode, does two refinement steps instead of 1. ~30-40% slower. + +// The original signature has been modified by adding the parameter compressed_size which returns +// the size in bytes of the compressed data contained into dst +void rygCompress(unsigned char *dst, unsigned char *src, int w, int h, int isDxt5, int& compressed_size); + +// TODO remove these, not working properly.. +void rygCompressYCoCg( unsigned char *dst, unsigned char *src, int w, int h ); +void linearize( unsigned char * dst, const unsigned char * src, int n ); + +void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int mode); +#define STB_COMPRESS_DXT_BLOCK + +#ifdef STB_DXT_IMPLEMENTATION + +// configuration options for DXT encoder. set them in the project/makefile or just define +// them at the top. + +// STB_DXT_USE_ROUNDING_BIAS +// use a rounding bias during color interpolation. this is closer to what "ideal" +// interpolation would do but doesn't match the S3TC/DX10 spec. old versions (pre-1.03) +// implicitly had this turned on. +// +// in case you're targeting a specific type of hardware (e.g. console programmers): +// NVidia and Intel GPUs (as of 2010) as well as DX9 ref use DXT decoders that are closer +// to STB_DXT_USE_ROUNDING_BIAS. AMD/ATI, S3 and DX10 ref are closer to rounding with no bias. +// you also see "(a*5 + b*3) / 8" on some old GPU designs. +// #define STB_DXT_USE_ROUNDING_BIAS + +#include +#include +#include +#include // memset +#include +#include +#include + + +static unsigned char stb__Expand5[32]; +static unsigned char stb__Expand6[64]; +static unsigned char stb__OMatch5[256][2]; +static unsigned char stb__OMatch6[256][2]; +static unsigned char stb__QuantRBTab[256+16]; +static unsigned char stb__QuantGTab[256+16]; + +static int stb__Mul8Bit(int a, int b) +{ + int t = a*b + 128; + return (t + (t >> 8)) >> 8; +} + +static void stb__From16Bit(unsigned char *out, unsigned short v) +{ + int rv = (v & 0xf800) >> 11; + int gv = (v & 0x07e0) >> 5; + int bv = (v & 0x001f) >> 0; + + out[0] = stb__Expand5[rv]; + out[1] = stb__Expand6[gv]; + out[2] = stb__Expand5[bv]; + out[3] = 0; +} + +static unsigned short stb__As16Bit(int r, int g, int b) +{ + return (stb__Mul8Bit(r,31) << 11) + (stb__Mul8Bit(g,63) << 5) + stb__Mul8Bit(b,31); +} + +// linear interpolation at 1/3 point between a and b, using desired rounding type +static int stb__Lerp13(int a, int b) +{ +#ifdef STB_DXT_USE_ROUNDING_BIAS + // with rounding bias + return a + stb__Mul8Bit(b-a, 0x55); +#else + // without rounding bias + // replace "/ 3" by "* 0xaaab) >> 17" if your compiler sucks or you really need every ounce of speed. + return (2*a + b) / 3; +#endif +} + +// lerp RGB color +static void stb__Lerp13RGB(unsigned char *out, unsigned char *p1, unsigned char *p2) +{ + out[0] = stb__Lerp13(p1[0], p2[0]); + out[1] = stb__Lerp13(p1[1], p2[1]); + out[2] = stb__Lerp13(p1[2], p2[2]); +} + +/****************************************************************************/ + +// compute table to reproduce constant colors as accurately as possible +static void stb__PrepareOptTable(unsigned char *Table,const unsigned char *expand,int size) +{ + int i,mn,mx; + for (i=0;i<256;i++) { + int bestErr = 256; + for (mn=0;mn> 4)]; + ep1[0] = bp[ 0] - dp[ 0]; + dp[ 4] = quant[bp[ 4] + ((7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]) >> 4)]; + ep1[1] = bp[ 4] - dp[ 4]; + dp[ 8] = quant[bp[ 8] + ((7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]) >> 4)]; + ep1[2] = bp[ 8] - dp[ 8]; + dp[12] = quant[bp[12] + ((7*ep1[2] + 5*ep2[3] + ep2[2]) >> 4)]; + ep1[3] = bp[12] - dp[12]; + bp += 16; + dp += 16; + et = ep1, ep1 = ep2, ep2 = et; // swap + } + } +} + +// The color matching function +static unsigned int stb__MatchColorsBlock(unsigned char *block, unsigned char *color,int dither) +{ + unsigned int mask = 0; + int dirr = color[0*4+0] - color[1*4+0]; + int dirg = color[0*4+1] - color[1*4+1]; + int dirb = color[0*4+2] - color[1*4+2]; + int dots[16]; + int stops[4]; + int i; + int c0Point, halfPoint, c3Point; + + for(i=0;i<16;i++) + dots[i] = block[i*4+0]*dirr + block[i*4+1]*dirg + block[i*4+2]*dirb; + + for(i=0;i<4;i++) + stops[i] = color[i*4+0]*dirr + color[i*4+1]*dirg + color[i*4+2]*dirb; + + // think of the colors as arranged on a line; project point onto that line, then choose + // next color out of available ones. we compute the crossover points for "best color in top + // half"/"best in bottom half" and then the same inside that subinterval. + // + // relying on this 1d approximation isn't always optimal in terms of euclidean distance, + // but it's very close and a lot faster. + // http://cbloomrants.blogspot.com/2008/12/12-08-08-dxtc-summary.html + + c0Point = (stops[1] + stops[3]) >> 1; + halfPoint = (stops[3] + stops[2]) >> 1; + c3Point = (stops[2] + stops[0]) >> 1; + + if(!dither) + { + // the version without dithering is straightforward + +#ifdef NEW_OPTIMISATIONS + const int indexMap[8] = { 0 << 30,2 << 30,0 << 30,2 << 30,3 << 30,3 << 30,1 << 30,1 << 30 }; + + for(int i=0;i<16;i++) + { + int dot = dots[i]; + mask >>= 2; + + int bits =( (dot < halfPoint) ? 4 : 0 ) + | ( (dot < c0Point) ? 2 : 0 ) + | ( (dot < c3Point) ? 1 : 0 ); + + mask |= indexMap[bits]; + } + +#else + for (i=15;i>=0;i--) { + int dot = dots[i]; + mask <<= 2; + + if(dot < halfPoint) + mask |= (dot < c0Point) ? 1 : 3; + else + mask |= (dot < c3Point) ? 2 : 0; + } +#endif + + } else { + // with floyd-steinberg dithering + int err[8],*ep1 = err,*ep2 = err+4; + int *dp = dots, y; + + c0Point <<= 4; + halfPoint <<= 4; + c3Point <<= 4; + for(i=0;i<8;i++) + err[i] = 0; + + for(y=0;y<4;y++) + { + int dot,lmask,step; + + dot = (dp[0] << 4) + (3*ep2[1] + 5*ep2[0]); + if(dot < halfPoint) + step = (dot < c0Point) ? 1 : 3; + else + step = (dot < c3Point) ? 2 : 0; + ep1[0] = dp[0] - stops[step]; + lmask = step; + + dot = (dp[1] << 4) + (7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]); + if(dot < halfPoint) + step = (dot < c0Point) ? 1 : 3; + else + step = (dot < c3Point) ? 2 : 0; + ep1[1] = dp[1] - stops[step]; + lmask |= step<<2; + + dot = (dp[2] << 4) + (7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]); + if(dot < halfPoint) + step = (dot < c0Point) ? 1 : 3; + else + step = (dot < c3Point) ? 2 : 0; + ep1[2] = dp[2] - stops[step]; + lmask |= step<<4; + + dot = (dp[3] << 4) + (7*ep1[2] + 5*ep2[3] + ep2[2]); + if(dot < halfPoint) + step = (dot < c0Point) ? 1 : 3; + else + step = (dot < c3Point) ? 2 : 0; + ep1[3] = dp[3] - stops[step]; + lmask |= step<<6; + + dp += 4; + mask |= lmask << (y*8); + { int *et = ep1; ep1 = ep2; ep2 = et; } // swap + } + } + + return mask; +} + +// The color optimization function. (Clever code, part 1) +static void stb__OptimizeColorsBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16) +{ + unsigned char *minp, *maxp; + double magn; + int v_r,v_g,v_b; + static const int nIterPower = 4; + float covf[6],vfr,vfg,vfb; + + // determine color distribution + int cov[6]; + int mu[3],min[3],max[3]; + int ch,i,iter; + + for(ch=0;ch<3;ch++) + { + const unsigned char *bp = ((const unsigned char *) block) + ch; + int muv,minv,maxv; + +#ifdef NEW_OPTIMISATIONS +# define MIN(a,b) (int)a + ( ((int)b-a) & ( ((int)b-a) >> 31 ) ) +# define MAX(a,b) (int)a + ( ((int)b-a) & ( ((int)a-b) >> 31 ) ) +# define RANGE(a,b,n) int min##n = MIN(a,b); int max##n = a+b - min##n; muv += a+b; +# define MINMAX(a,b,n) int min##n = MIN(min##a, min##b); int max##n = MAX(max##a, max##b); + + muv = 0; + RANGE(bp[0], bp[4], 1); + RANGE(bp[8], bp[12], 2); + RANGE(bp[16], bp[20], 3); + RANGE(bp[24], bp[28], 4); + RANGE(bp[32], bp[36], 5); + RANGE(bp[40], bp[44], 6); + RANGE(bp[48], bp[52], 7); + RANGE(bp[56], bp[60], 8); + + MINMAX(1,2,9); + MINMAX(3,4,10); + MINMAX(5,6,11); + MINMAX(7,8,12); + + MINMAX(9,10,13); + MINMAX(11,12,14); + + minv = MIN(min13,min14); + maxv = MAX(max13,max14); + +#else + muv = minv = maxv = bp[0]; + for(i=4;i<64;i+=4) + { + muv += bp[i]; + if (bp[i] < minv) minv = bp[i]; + else if (bp[i] > maxv) maxv = bp[i]; + } +#endif + + mu[ch] = (muv + 8) >> 4; + min[ch] = minv; + max[ch] = maxv; + } + + // determine covariance matrix + for (i=0;i<6;i++) + cov[i] = 0; + + for (i=0;i<16;i++) + { + int r = block[i*4+0] - mu[0]; + int g = block[i*4+1] - mu[1]; + int b = block[i*4+2] - mu[2]; + + cov[0] += r*r; + cov[1] += r*g; + cov[2] += r*b; + cov[3] += g*g; + cov[4] += g*b; + cov[5] += b*b; + } + + // convert covariance matrix to float, find principal axis via power iter + for(i=0;i<6;i++) + covf[i] = cov[i] / 255.0f; + + vfr = (float) (max[0] - min[0]); + vfg = (float) (max[1] - min[1]); + vfb = (float) (max[2] - min[2]); + + for(iter=0;iter magn) magn = fabs(vfg); + if (fabs(vfb) > magn) magn = fabs(vfb); + + if(magn < 4.0f) + { // too small, default to luminance + v_r = 299; // JPEG YCbCr luma coefs, scaled by 1000. + v_g = 587; + v_b = 114; + } else { + magn = 512.0 / magn; + v_r = (int) (vfr * magn); + v_g = (int) (vfg * magn); + v_b = (int) (vfb * magn); + } + + +#ifdef NEW_OPTIMISATIONS + // Pick colors at extreme points + int mind, maxd; + mind = maxd = block[0]*v_r + block[1]*v_g + block[2]*v_b; + minp = maxp = block; + for(i=1;i<16;i++) + { + int dot = block[i*4+0]*v_r + block[i*4+1]*v_g + block[i*4+2]*v_b; + + if (dot < mind) { + mind = dot; + minp = block+i*4; + continue; + } + + if (dot > maxd) { + maxd = dot; + maxp = block+i*4; + } + } +#else + int mind = 0x7fffffff,maxd = -0x7fffffff; + // Pick colors at extreme points + for(i=0;i<16;i++) + { + int dot = block[i*4+0]*v_r + block[i*4+1]*v_g + block[i*4+2]*v_b; + + if (dot < mind) { + mind = dot; + minp = block+i*4; + } + + if (dot > maxd) { + maxd = dot; + maxp = block+i*4; + } + } +#endif + + *pmax16 = stb__As16Bit(maxp[0],maxp[1],maxp[2]); + *pmin16 = stb__As16Bit(minp[0],minp[1],minp[2]); +} + +inline static int stb__sclamp(float y, int p0, int p1) +{ + int x = (int) y; + +#ifdef NEW_OPTIMISATIONS + x = x>p1 ? p1 : x; + return x p1) return p1; + return x; +#endif +} + +// The refinement function. (Clever code, part 2) +// Tries to optimize colors to suit block contents better. +// (By solving a least squares system via normal equations+Cramer's rule) +static int stb__RefineBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16, unsigned int mask) +{ + static const int w1Tab[4] = { 3,0,2,1 }; + static const int prods[4] = { 0x090000,0x000900,0x040102,0x010402 }; + // ^some magic to save a lot of multiplies in the accumulating loop... + // (precomputed products of weights for least squares system, accumulated inside one 32-bit register) + + float frb,fg; + unsigned short oldMin, oldMax, min16, max16; + int i, akku = 0, xx,xy,yy; + int At1_r,At1_g,At1_b; + int At2_r,At2_g,At2_b; + unsigned int cm = mask; + + oldMin = *pmin16; + oldMax = *pmax16; + + if((mask ^ (mask<<2)) < 4) // all pixels have the same index? + { + // yes, linear system would be singular; solve using optimal + // single-color match on average color + int r = 8, g = 8, b = 8; + for (i=0;i<16;++i) { + r += block[i*4+0]; + g += block[i*4+1]; + b += block[i*4+2]; + } + + r >>= 4; g >>= 4; b >>= 4; + + max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0]; + min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1]; + } else { + At1_r = At1_g = At1_b = 0; + At2_r = At2_g = At2_b = 0; + for (i=0;i<16;++i,cm>>=2) + { + int step = cm&3; + int w1 = w1Tab[step]; + int r = block[i*4+0]; + int g = block[i*4+1]; + int b = block[i*4+2]; + + akku += prods[step]; + At1_r += w1*r; + At1_g += w1*g; + At1_b += w1*b; + At2_r += r; + At2_g += g; + At2_b += b; + } + + At2_r = 3*At2_r - At1_r; + At2_g = 3*At2_g - At1_g; + At2_b = 3*At2_b - At1_b; + + // extract solutions and decide solvability + xx = akku >> 16; + yy = (akku >> 8) & 0xff; + xy = (akku >> 0) & 0xff; + + frb = 3.0f * 31.0f / 255.0f / (xx*yy - xy*xy); + fg = frb * 63.0f / 31.0f; + + // solve. + max16 = stb__sclamp((At1_r*yy - At2_r*xy)*frb+0.5f,0,31) << 11; + max16 |= stb__sclamp((At1_g*yy - At2_g*xy)*fg +0.5f,0,63) << 5; + max16 |= stb__sclamp((At1_b*yy - At2_b*xy)*frb+0.5f,0,31) << 0; + + min16 = stb__sclamp((At2_r*xx - At1_r*xy)*frb+0.5f,0,31) << 11; + min16 |= stb__sclamp((At2_g*xx - At1_g*xy)*fg +0.5f,0,63) << 5; + min16 |= stb__sclamp((At2_b*xx - At1_b*xy)*frb+0.5f,0,31) << 0; + } + + *pmin16 = min16; + *pmax16 = max16; + return oldMin != min16 || oldMax != max16; +} + +// Color block compression +static void stb__CompressColorBlock(unsigned char *dest, unsigned char *block, int mode) +{ + unsigned int mask; + int i; + int dither; + int refinecount; + unsigned short max16, min16; + unsigned char dblock[16*4],color[4*4]; + + dither = mode & STB_DXT_DITHER; + refinecount = (mode & STB_DXT_HIGHQUAL) ? 2 : 1; + + // check if block is constant + for (i=1;i<16;i++) + if (((unsigned int *) block)[i] != ((unsigned int *) block)[0]) + break; + + if(i == 16) + { // constant color + int r = block[0], g = block[1], b = block[2]; + mask = 0xaaaaaaaa; + max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0]; + min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1]; + } else + { + // first step: compute dithered version for PCA if desired + if(dither) + stb__DitherBlock(dblock,block); + + // second step: pca+map along principal axis + stb__OptimizeColorsBlock(dither ? dblock : block,&max16,&min16); + if (max16 != min16) + { + stb__EvalColors(color,max16,min16); + mask = stb__MatchColorsBlock(block,color,dither); + } else + mask = 0; + + // third step: refine (multiple times if requested) + for (i=0;i> 8); + dest[2] = (unsigned char) (min16); + dest[3] = (unsigned char) (min16 >> 8); + dest[4] = (unsigned char) (mask); + dest[5] = (unsigned char) (mask >> 8); + dest[6] = (unsigned char) (mask >> 16); + dest[7] = (unsigned char) (mask >> 24); +} + +// Alpha block compression (this is easy for a change) +static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src,int mode) +{ + int i,dist,bias,dist4,dist2,bits,mask; + + // find min/max color + int mn,mx; + + mn = mx = src[3]; + for (i=1;i<16;i++) + { + if (src[i*4+3] < mn) mn = src[i*4+3]; + else if (src[i*4+3] > mx) mx = src[i*4+3]; + } + + // encode them + ((unsigned char *)dest)[0] = mx; + ((unsigned char *)dest)[1] = mn; + dest += 2; + +#ifdef NEW_OPTIMISATIONS + // mono-alpha shortcut + if (mn==mx) + { + *(unsigned short*)dest = 0; + dest += 2; + *(unsigned int*)dest = 0; + return; + } +#endif + + // determine bias and emit color indices + // given the choice of mx/mn, these indices are optimal: + // http://fgiesen.wordpress.com/2009/12/15/dxt5-alpha-block-index-determination/ + dist = mx-mn; + //printf("mn = %i; mx = %i; dist = %i\n", mn, mx, dist); + dist4 = dist*4; + dist2 = dist*2; + bias = (dist < 8) ? (dist - 1) : (dist/2 + 2); + bias -= mn * 7; + bits = 0, mask=0; + + for (i=0;i<16;i++) + { + int a = src[i*4+3]*7 + bias; + int ind,t; + + // select index. this is a "linear scale" lerp factor between 0 (val=min) and 7 (val=max). + t = (a >= dist4) ? -1 : 0; ind = t & 4; a -= dist4 & t; + t = (a >= dist2) ? -1 : 0; ind += t & 2; a -= dist2 & t; + ind += (a >= dist); + + // turn linear scale into DXT index (0/1 are extremal pts) + ind = -ind & 7; + ind ^= (2 > ind); + + // write index + mask |= ind << bits; + if((bits += 3) >= 8) + { + *dest++ = mask; + mask >>= 8; + bits -= 8; + } + } +} + + +static void stb__InitDXT() +{ + int i; + for(i=0;i<32;i++) + stb__Expand5[i] = (i<<3)|(i>>2); + + for(i=0;i<64;i++) + stb__Expand6[i] = (i<<2)|(i>>4); + + for(i=0;i<256+16;i++) + { + int v = i-8 < 0 ? 0 : i-8 > 255 ? 255 : i-8; + stb__QuantRBTab[i] = stb__Expand5[stb__Mul8Bit(v,31)]; + stb__QuantGTab[i] = stb__Expand6[stb__Mul8Bit(v,63)]; + } + + stb__PrepareOptTable(&stb__OMatch5[0][0],stb__Expand5,32); + stb__PrepareOptTable(&stb__OMatch6[0][0],stb__Expand6,64); +} + + +void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int mode) +{ + static int init=1; + if (init) + { + stb__InitDXT(); + init=0; + } + + if (alpha) + { + stb__CompressAlphaBlock(dest,(unsigned char*) src,mode); + dest += 8; + } + + stb__CompressColorBlock(dest,(unsigned char*) src,mode); +} + +int imin(int x, int y) { return (x < y) ? x : y; } + + + + + +static void extractBlock(const unsigned char *src, int x, int y, + int w, int h, unsigned char *block) +{ + int i, j; + +#ifdef NEW_OPTIMISATIONS + if ((w-x >=4) && (h-y >=4)) + { + // Full Square shortcut + src += x*4; + src += y*w*4; + for (i=0; i < 4; ++i) + { + *(unsigned int*)block = *(unsigned int*) src; block += 4; src += 4; + *(unsigned int*)block = *(unsigned int*) src; block += 4; src += 4; + *(unsigned int*)block = *(unsigned int*) src; block += 4; src += 4; + *(unsigned int*)block = *(unsigned int*) src; block += 4; + src += (w*4) - 12; + } + return; + } +#endif + + int bw = imin(w - x, 4); + int bh = imin(h - y, 4); + int bx, by; + + const int rem[] = + { + 0, 0, 0, 0, + 0, 1, 0, 1, + 0, 1, 2, 0, + 0, 1, 2, 3 + }; + + for(i = 0; i < 4; ++i) + { + by = rem[(bh - 1) * 4 + i] + y; + for(j = 0; j < 4; ++j) + { + bx = rem[(bw - 1) * 4 + j] + x; + block[(i * 4 * 4) + (j * 4) + 0] = + src[(by * (w * 4)) + (bx * 4) + 0]; + block[(i * 4 * 4) + (j * 4) + 1] = + src[(by * (w * 4)) + (bx * 4) + 1]; + block[(i * 4 * 4) + (j * 4) + 2] = + src[(by * (w * 4)) + (bx * 4) + 2]; + block[(i * 4 * 4) + (j * 4) + 3] = + src[(by * (w * 4)) + (bx * 4) + 3]; + } + } +} + + // should be a pretty optimized 0-255 clamper +inline static unsigned char clamp255( int n ) +{ + if( n > 255 ) n = 255; + if( n < 0 ) n = 0; + return n; +} + + +void rgbToYCoCgBlock( unsigned char * dst, const unsigned char * src ) +{ + // Calculate Co and Cg extents + int extents = 0; + int n = 0; + int iY, iCo, iCg; //, r, g, b; + int blockCo[16]; + int blockCg[16]; + int i; + + const unsigned char *px = src; + for(i=0;i extents) extents = -iCo; + if( iCo > extents) extents = iCo; + if(-iCg > extents) extents = -iCg; + if( iCg > extents) extents = iCg; + + blockCo[n] = iCo; + blockCg[n++] = iCg; + + px += 4; + } + + // Co = -510..510 + // Cg = -510..510 + float scaleFactor = 1.0f; + if(extents > 127) + scaleFactor = (float)extents * 4.0f / 510.0f; + + // Convert to quantized scalefactor + unsigned char scaleFactorQuantized = (unsigned char)(ceil((scaleFactor - 1.0f) * 31.0f / 3.0f)); + + // Unquantize + scaleFactor = 1.0f + (float)(scaleFactorQuantized / 31.0f) * 3.0f; + + unsigned char bVal = (unsigned char)((scaleFactorQuantized << 3) | (scaleFactorQuantized >> 2)); + + unsigned char *outPx = dst; + + n = 0; + px = src; + /* + for(i=0;i<16;i++) + { + // Calculate components + iY = ( px[0] + (px[1]<<1) + px[2] + 2 ) / 4; + iCo = ((blockCo[n] / scaleFactor) + 128); + iCg = ((blockCg[n] / scaleFactor) + 128); + + if(iCo < 0) iCo = 0; else if(iCo > 255) iCo = 255; + if(iCg < 0) iCg = 0; else if(iCg > 255) iCg = 255; + if(iY < 0) iY = 0; else if(iY > 255) iY = 255; + + px += 4; + + outPx[0] = (unsigned char)iCo; + outPx[1] = (unsigned char)iCg; + outPx[2] = bVal; + outPx[3] = (unsigned char)iY; + + outPx += 4; + }*/ + for(i=0;i<16;i++) + { + // Calculate components + int r = px[0]; + int g = (px[1] + 1) >> 1; + int b = px[2]; + int tmp = (2 + r + b) >> 2; + + // Co + iCo = clamp255( 128 + ((r - b + 1) >> 1) ); + // Y + iY = clamp255( g + tmp ); + // Cg + iCg = clamp255( 128 + g - tmp ); + + px += 4; + + outPx[0] = (unsigned char)iCo; + outPx[1] = (unsigned char)iCg; + outPx[2] = bVal; + outPx[3] = (unsigned char)iY; + + outPx += 4; + } + +} + + +void rygCompress(unsigned char *dst, unsigned char *src, int w, int h, int isDxt5, int& compressed_size) +{ + + unsigned char block[64]; + int x, y; + + unsigned char* initial_dst = dst; + + for (y = 0; y < h; y += 4) + { + for(x = 0; x < w; x += 4) + { + extractBlock(src, x, y, w, h, block); + stb_compress_dxt_block(dst, block, isDxt5, STB_DXT_NORMAL); + dst += isDxt5 ? 16 : 8; + } + } + + compressed_size = dst - initial_dst; +} + +void rygCompressYCoCg( unsigned char *dst, unsigned char *src, int w, int h ) +{ + unsigned char block[64]; + unsigned char ycocgblock[64]; + int x, y; + + for(y = 0; y < h; y += 4) + { + for(x = 0; x < w; x += 4) + { + extractBlock(src, x, y, w, h, block); + rgbToYCoCgBlock(ycocgblock,block); + stb_compress_dxt_block(dst, ycocgblock, 1, 10); + dst += 16; + } + } + +} + +static void stbgl__compress(unsigned char *p, unsigned char *rgba, int w, int h, int isDxt5) +{ + int i,j,y,y2; + int alpha = isDxt5; + + for (j=0; j < w; j += 4) { + int x=4; + for (i=0; i < h; i += 4) { + unsigned char block[16*4]; + if (i+3 >= w) x = w-i; + for (y=0; y < 4; ++y) { + if (j+y >= h) break; + memcpy(block+y*16, rgba + w*4*(j+y) + i*4, x*4); + } + if (x < 4) { + switch (x) { + case 0: assert(0); + case 1: + for (y2=0; y2 < y; ++y2) { + memcpy(block+y2*16+1*4, block+y2*16+0*4, 4); + memcpy(block+y2*16+2*4, block+y2*16+0*4, 8); + } + break; + case 2: + for (y2=0; y2 < y; ++y2) + memcpy(block+y2*16+2*4, block+y2*16+0*4, 8); + break; + case 3: + for (y2=0; y2 < y; ++y2) + memcpy(block+y2*16+3*4, block+y2*16+1*4, 4); + break; + } + } + y2 = 0; + for(; y<4; ++y,++y2) + memcpy(block+y*16, block+y2*16, 4*4); + stb_compress_dxt_block(p, block, alpha, 10); + p += alpha ? 16 : 8; + } + } + // assert(p <= end); +} + +static inline unsigned char linearize(unsigned char inByte) +{ + float srgbVal = ((float)inByte) / 255.0f; + float linearVal; + + if(srgbVal < 0.04045) + linearVal = srgbVal / 12.92f; + else + linearVal = pow( (srgbVal + 0.055f) / 1.055f, 2.4f); + + return (unsigned char)(floor(sqrt(linearVal)* 255.0 + 0.5)); +} + +void linearize( unsigned char * dst, const unsigned char * src, int n ) +{ + n*=4; + for( int i = 0; i < n; i++ ) + dst[i] = linearize(src[i]); +} + + + +#endif // STB_DXT_IMPLEMENTATION + +#endif // STB_INCLUDE_STB_DXT_H From 9211475bdf1ca327456d288aecfc002dbde39d44 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Sun, 2 Jun 2019 11:01:51 +0200 Subject: [PATCH 11/37] Temporary low-res texture shown while generating compressed data on the CPU --- src/slic3r/GUI/3DBed.cpp | 24 ++++++++++++++++++++++++ src/slic3r/GUI/3DBed.hpp | 4 ++++ src/slic3r/GUI/GLTexture.cpp | 14 +------------- src/slic3r/GUI/GLTexture.hpp | 4 ++-- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index e6589e5481a..98f2d7dc32d 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -522,6 +522,14 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const if ((m_texture.get_id() == 0) || (m_texture.get_source() != filename)) { #if ENABLE_COMPRESSED_TEXTURES + // generate a temporary lower resolution texture to show while no main texture levels have been compressed + if (!m_temp_texture.load_from_svg_file(filename, false, false, false, max_tex_size / 8)) + { + render_custom(); + return; + } + + // starts generating the main texture, compression will run asynchronously if (!m_texture.load_from_svg_file(filename, true, true, true, max_tex_size)) #else if (!m_texture.load_from_svg_file(filename, true, max_tex_size)) @@ -542,7 +550,14 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const } #if ENABLE_COMPRESSED_TEXTURES else if (m_texture.unsent_compressed_data_available()) + { + // sends to gpu the already available compressed levels of the main texture m_texture.send_compressed_data_to_gpu(); + + // the temporary texture is not needed anymore, reset it + if (m_temp_texture.get_id() != 0) + m_temp_texture.reset(); + } #endif // ENABLE_COMPRESSED_TEXTURES if (!bottom) @@ -616,7 +631,16 @@ void Bed3D::render_prusa_shader(bool transparent) const GLint position_id = m_shader.get_attrib_location("v_position"); GLint tex_coords_id = m_shader.get_attrib_location("v_tex_coords"); +#if ENABLE_COMPRESSED_TEXTURES + // show the temporary texture while no compressed data is available + GLuint tex_id = (GLuint)m_temp_texture.get_id(); + if (tex_id == 0) + tex_id = (GLuint)m_texture.get_id(); + + glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id)); +#else glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_texture.get_id())); +#endif // ENABLE_COMPRESSED_TEXTURES glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); if (position_id != -1) diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index e60cdf94e1b..054b746e5e9 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -91,6 +91,10 @@ private: GeometryBuffer m_gridlines; #if ENABLE_TEXTURES_FROM_SVG mutable GLTexture m_texture; +#if ENABLE_COMPRESSED_TEXTURES + // temporary texture shown until the main texture has still no levels compressed + mutable GLTexture m_temp_texture; +#endif // ENABLE_COMPRESSED_TEXTURES mutable Shader m_shader; mutable unsigned int m_vbo_id; #else diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index cc6bdc715a1..469e192b593 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -343,18 +343,6 @@ void GLTexture::reset() #endif // ENABLE_COMPRESSED_TEXTURES } -#if ENABLE_COMPRESSED_TEXTURES -bool GLTexture::unsent_compressed_data_available() const -{ - return m_compressor.unsent_compressed_data_available(); -} - -void GLTexture::send_compressed_data_to_gpu() -{ - m_compressor.send_compressed_data_to_gpu(); -} -#endif // ENABLE_COMPRESSED_TEXTURES - void GLTexture::render_texture(unsigned int tex_id, float left, float right, float bottom, float top) { render_sub_texture(tex_id, left, right, bottom, top, FullTextureUVs); @@ -603,7 +591,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns int lod_h = m_height; GLint level = 0; // we do not need to generate all levels down to 1x1 - while ((lod_w > 64) || (lod_h > 64)) + while ((lod_w > 16) || (lod_h > 16)) { ++level; diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index f5cf13a455a..ed2070a44e0 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -106,8 +106,8 @@ namespace GUI { const std::string& get_source() const { return m_source; } #if ENABLE_COMPRESSED_TEXTURES - bool unsent_compressed_data_available() const; - void send_compressed_data_to_gpu(); + bool unsent_compressed_data_available() const { return m_compressor.unsent_compressed_data_available(); } + void send_compressed_data_to_gpu() { m_compressor.send_compressed_data_to_gpu(); } #endif // ENABLE_COMPRESSED_TEXTURES static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top); From e9d6007c00886cf0fb6cfd7692e15e9cc05fae50 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 3 Jun 2019 13:53:30 +0200 Subject: [PATCH 12/37] Fixed race condition while compressing texture data and sending them to the GPU --- src/slic3r/GUI/GLTexture.cpp | 8 ++++++-- src/slic3r/GUI/GLTexture.hpp | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 469e192b593..78de38d5492 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -55,7 +55,7 @@ bool GLTexture::Compressor::unsent_compressed_data_available() const { for (const Level& level : m_levels) { - if (!level.sent_to_gpu && (level.compressed_data.size() > 0)) + if (!level.sent_to_gpu && level.compressed) return true; } @@ -64,12 +64,14 @@ bool GLTexture::Compressor::unsent_compressed_data_available() const void GLTexture::Compressor::send_compressed_data_to_gpu() { + // this method should be called inside the main thread of Slicer or a new OpenGL context (sharing resources) would be needed + glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); glsafe(::glBindTexture(GL_TEXTURE_2D, m_texture.m_id)); for (int i = 0; i < (int)m_levels.size(); ++i) { Level& level = m_levels[i]; - if (!level.sent_to_gpu && (level.compressed_data.size() > 0)) + if (!level.sent_to_gpu && level.compressed) { glsafe(::glCompressedTexSubImage2D(GL_TEXTURE_2D, (GLint)i, 0, 0, (GLsizei)level.w, (GLsizei)level.h, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)level.compressed_data.size(), (const GLvoid*)level.compressed_data.data())); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i)); @@ -77,6 +79,7 @@ void GLTexture::Compressor::send_compressed_data_to_gpu() level.sent_to_gpu = true; // we are done with the compressed data, we can discard it level.compressed_data.clear(); + level.compressed = false; } } glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); @@ -100,6 +103,7 @@ void GLTexture::Compressor::compress() // we are done with the source data, we can discard it level.src_data.clear(); + level.compressed = true; } m_is_compressing = false; diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index ed2070a44e0..d1ff366c345 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -20,9 +20,10 @@ namespace GUI { unsigned int h; std::vector src_data; std::vector compressed_data; + bool compressed; bool sent_to_gpu; - Level(unsigned int w, unsigned int h, const std::vector& data) : w(w), h(h), src_data(data), sent_to_gpu(false) {} + Level(unsigned int w, unsigned int h, const std::vector& data) : w(w), h(h), src_data(data), compressed(false), sent_to_gpu(false) {} }; GLTexture& m_texture; From 9f4881e88b75556deb85725ce3168cfdb50a9b1c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 5 Jun 2019 10:07:59 +0200 Subject: [PATCH 13/37] Update 3D scene when all compressed texture data are sent to GPU --- src/slic3r/GUI/3DBed.cpp | 66 +++++++++++++++++++++++++++++++++-- src/slic3r/GUI/3DBed.hpp | 14 ++++++++ src/slic3r/GUI/GLCanvas3D.cpp | 16 +++++++++ src/slic3r/GUI/GLCanvas3D.hpp | 8 +++++ src/slic3r/GUI/GLTexture.cpp | 13 +++++++ src/slic3r/GUI/GLTexture.hpp | 2 ++ 6 files changed, 117 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 98f2d7dc32d..04ab4e2da2f 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -9,6 +9,9 @@ #include "GUI_App.hpp" #include "PresetBundle.hpp" #include "Gizmos/GLGizmoBase.hpp" +#if ENABLE_COMPRESSED_TEXTURES +#include "GLCanvas3D.hpp" +#endif // ENABLE_COMPRESSED_TEXTURES #include @@ -273,6 +276,9 @@ void Bed3D::Axes::render_axis(double length) const Bed3D::Bed3D() : m_type(Custom) +#if ENABLE_COMPRESSED_TEXTURES + , m_requires_canvas_update(false) +#endif // ENABLE_COMPRESSED_TEXTURES #if ENABLE_TEXTURES_FROM_SVG , m_vbo_id(0) #endif // ENABLE_TEXTURES_FROM_SVG @@ -328,14 +334,34 @@ Point Bed3D::point_projection(const Point& point) const } #if ENABLE_TEXTURES_FROM_SVG +#if ENABLE_COMPRESSED_TEXTURES +void Bed3D::render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_factor) const +#else void Bed3D::render(float theta, bool useVBOs, float scale_factor) const +#endif // ENABLE_COMPRESSED_TEXTURES { m_scale_factor = scale_factor; EType type = useVBOs ? m_type : Custom; switch (type) - { +#if ENABLE_COMPRESSED_TEXTURES + case MK2: + { + render_prusa(canvas, "mk2", theta > 90.0f); + break; + } + case MK3: + { + render_prusa(canvas, "mk3", theta > 90.0f); + break; + } + case SL1: + { + render_prusa(canvas, "sl1", theta > 90.0f); + break; + } +#else case MK2: { render_prusa("mk2", theta > 90.0f); @@ -351,6 +377,7 @@ void Bed3D::render(float theta, bool useVBOs, float scale_factor) const render_prusa("sl1", theta > 90.0f); break; } +#endif // ENABLE_COMPRESSED_TEXTURES default: case Custom: { @@ -360,7 +387,11 @@ void Bed3D::render(float theta, bool useVBOs, float scale_factor) const } } #else +#if ENABLE_COMPRESSED_TEXTURES +void Bed3D::render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_factor) const +#else void Bed3D::render(float theta, bool useVBOs, float scale_factor) const +#endif // ENABLE_COMPRESSED_TEXTURES { m_scale_factor = scale_factor; @@ -369,6 +400,23 @@ void Bed3D::render(float theta, bool useVBOs, float scale_factor) const switch (m_type) { +#if ENABLE_COMPRESSED_TEXTURES + case MK2: + { + render_prusa(canvas, "mk2", theta, useVBOs); + break; + } + case MK3: + { + render_prusa(canvas, "mk3", theta, useVBOs); + break; + } + case SL1: + { + render_prusa(canvas, "sl1", theta, useVBOs); + break; + } +#else case MK2: { render_prusa("mk2", theta, useVBOs); @@ -383,7 +431,8 @@ void Bed3D::render(float theta, bool useVBOs, float scale_factor) const { render_prusa("sl1", theta, useVBOs); break; - } + } +#endif // ENABLE_COMPRESSED_TEXTURES default: case Custom: { @@ -487,7 +536,11 @@ Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const } #if ENABLE_TEXTURES_FROM_SVG +#if ENABLE_COMPRESSED_TEXTURES +void Bed3D::render_prusa(GLCanvas3D* canvas, const std::string &key, bool bottom) const +#else void Bed3D::render_prusa(const std::string &key, bool bottom) const +#endif // ENABLE_COMPRESSED_TEXTURES { std::string tex_path = resources_dir() + "/icons/bed/" + key; @@ -557,6 +610,15 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const // the temporary texture is not needed anymore, reset it if (m_temp_texture.get_id() != 0) m_temp_texture.reset(); + + m_requires_canvas_update = true; + } + else if (m_requires_canvas_update && m_texture.all_compressed_data_sent_to_gpu()) + { + if (canvas != nullptr) + canvas->stop_keeping_dirty(); + + m_requires_canvas_update = false; } #endif // ENABLE_COMPRESSED_TEXTURES diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 054b746e5e9..401f1232f30 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -13,6 +13,10 @@ typedef class GLUquadric GLUquadricObj; namespace Slic3r { namespace GUI { +#if ENABLE_COMPRESSED_TEXTURES +class GLCanvas3D; +#endif // ENABLE_COMPRESSED_TEXTURES + class GeometryBuffer { #if ENABLE_TEXTURES_FROM_SVG @@ -94,6 +98,8 @@ private: #if ENABLE_COMPRESSED_TEXTURES // temporary texture shown until the main texture has still no levels compressed mutable GLTexture m_temp_texture; + // used to trigger 3D scene update once all compressed textures have been sent to GPU + mutable bool m_requires_canvas_update; #endif // ENABLE_COMPRESSED_TEXTURES mutable Shader m_shader; mutable unsigned int m_vbo_id; @@ -125,7 +131,11 @@ public: bool contains(const Point& point) const; Point point_projection(const Point& point) const; +#if ENABLE_COMPRESSED_TEXTURES + void render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_factor) const; +#else void render(float theta, bool useVBOs, float scale_factor) const; +#endif // ENABLE_COMPRESSED_TEXTURES void render_axes() const; private: @@ -134,7 +144,11 @@ private: void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); EType detect_type(const Pointfs& shape) const; #if ENABLE_TEXTURES_FROM_SVG +#if ENABLE_COMPRESSED_TEXTURES + void render_prusa(GLCanvas3D* canvas, const std::string& key, bool bottom) const; +#else void render_prusa(const std::string& key, bool bottom) const; +#endif // ENABLE_COMPRESSED_TEXTURES void render_prusa_shader(bool transparent) const; #else void render_prusa(const std::string &key, float theta, bool useVBOs) const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f7d685502a2..90c21608e44 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1266,6 +1266,9 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar #endif // ENABLE_SVG_ICONS , m_use_clipping_planes(false) , m_sidebar_field("") +#if ENABLE_COMPRESSED_TEXTURES + , m_keep_dirty(false) +#endif // ENABLE_COMPRESSED_TEXTURES , m_config(nullptr) , m_process(nullptr) , m_model(nullptr) @@ -1483,6 +1486,10 @@ void GLCanvas3D::bed_shape_changed() m_camera.set_scene_box(scene_bounding_box()); m_camera.requires_zoom_to_bed = true; m_dirty = true; +#if ENABLE_COMPRESSED_TEXTURES + if (m_bed.is_prusa()) + start_keeping_dirty(); +#endif // ENABLE_COMPRESSED_TEXTURES } void GLCanvas3D::set_color_by(const std::string& value) @@ -2353,6 +2360,11 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt) return; _refresh_if_shown_on_screen(); + +#if ENABLE_COMPRESSED_TEXTURES + if (m_keep_dirty) + m_dirty = true; +#endif // ENABLE_COMPRESSED_TEXTURES } void GLCanvas3D::on_char(wxKeyEvent& evt) @@ -3966,7 +3978,11 @@ void GLCanvas3D::_render_bed(float theta) const #if ENABLE_RETINA_GL scale_factor = m_retina_helper->get_scale_factor(); #endif // ENABLE_RETINA_GL +#if ENABLE_COMPRESSED_TEXTURES + m_bed.render(const_cast(this), theta, m_use_VBOs, scale_factor); +#else m_bed.render(theta, m_use_VBOs, scale_factor); +#endif // ENABLE_COMPRESSED_TEXTURES } void GLCanvas3D::_render_axes() const diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 6d77a507f10..d7a4c6d22d6 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -449,6 +449,9 @@ private: bool m_use_clipping_planes; mutable SlaCap m_sla_caps[2]; std::string m_sidebar_field; +#if ENABLE_COMPRESSED_TEXTURES + bool m_keep_dirty; +#endif // ENABLE_COMPRESSED_TEXTURES mutable GLVolumeCollection m_volumes; Selection m_selection; @@ -635,6 +638,11 @@ public: void set_cursor(ECursorType type); void msw_rescale(); +#if ENABLE_COMPRESSED_TEXTURES + void start_keeping_dirty() { m_keep_dirty = true; } + void stop_keeping_dirty() { m_keep_dirty = false; } +#endif // ENABLE_COMPRESSED_TEXTURES + private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 78de38d5492..9b373440a16 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -85,6 +85,17 @@ void GLTexture::Compressor::send_compressed_data_to_gpu() glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); } +bool GLTexture::Compressor::all_compressed_data_sent_to_gpu() const +{ + for (const Level& level : m_levels) + { + if (!level.sent_to_gpu) + return false; + } + + return true; +} + void GLTexture::Compressor::compress() { // reference: https://github.com/Cyan4973/RygsDXTc @@ -512,7 +523,9 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, boo bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, unsigned int max_size_px) #endif // ENABLE_COMPRESSED_TEXTURES { +#if ENABLE_COMPRESSED_TEXTURES bool compression_enabled = compress && GLEW_EXT_texture_compression_s3tc; +#endif // ENABLE_COMPRESSED_TEXTURES NSVGimage* image = nsvgParseFromFile(filename.c_str(), "px", 96.0f); if (image == nullptr) diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index d1ff366c345..5df6189b6f8 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -42,6 +42,7 @@ namespace GUI { bool unsent_compressed_data_available() const; void send_compressed_data_to_gpu(); + bool all_compressed_data_sent_to_gpu() const; private: void compress(); @@ -109,6 +110,7 @@ namespace GUI { #if ENABLE_COMPRESSED_TEXTURES bool unsent_compressed_data_available() const { return m_compressor.unsent_compressed_data_available(); } void send_compressed_data_to_gpu() { m_compressor.send_compressed_data_to_gpu(); } + bool all_compressed_data_sent_to_gpu() const { return m_compressor.all_compressed_data_sent_to_gpu(); } #endif // ENABLE_COMPRESSED_TEXTURES static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top); From f4a72f19a2fc751213df4236c529e48eb4648d7a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 13 Jun 2019 09:12:44 +0200 Subject: [PATCH 14/37] Added support for distance between camera position and camera target --- src/slic3r/GUI/Camera.cpp | 15 +++++++++++---- src/slic3r/GUI/Camera.hpp | 5 ++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index a9edb762645..4c7cb314acb 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -22,11 +22,13 @@ static const float VIEW_REAR[2] = { 180.0f, 90.0f }; namespace Slic3r { namespace GUI { +const float Camera::DefaultDistance = 1000.0f; + Camera::Camera() : type(Ortho) , zoom(1.0f) , phi(45.0f) -// , distance(0.0f) + , distance(DefaultDistance) , requires_zoom_to_bed(false) , inverted_phi(false) , m_theta(45.0f) @@ -107,12 +109,18 @@ void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) const void Camera::apply_view_matrix() const { + double theta_rad = Geometry::deg2rad(-(double)m_theta); + double phi_rad = Geometry::deg2rad((double)phi); + double sin_theta = ::sin(theta_rad); + Vec3d camera_pos = m_target + (double)distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad)); + glsafe(::glMatrixMode(GL_MODELVIEW)); glsafe(::glLoadIdentity()); glsafe(::glRotatef(-m_theta, 1.0f, 0.0f, 0.0f)); // pitch glsafe(::glRotatef(phi, 0.0f, 0.0f, 1.0f)); // yaw - glsafe(::glTranslated(-m_target(0), -m_target(1), -m_target(2))); // target to origin + + glsafe(::glTranslated(-camera_pos(0), -camera_pos(1), -camera_pos(2))); glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, m_view_matrix.data())); } @@ -136,8 +144,7 @@ void Camera::apply_projection(const BoundingBoxf3& box) const // FIXME: calculate a tighter value for depth will improve z-fighting // Set at least some minimum depth in case the bounding box is empty to avoid an OpenGL driver error. double depth = std::max(1.0, 5.0 * box.max_size()); - apply_ortho_projection(-w2, w2, -h2, h2, -depth, depth); - + apply_ortho_projection(-w2, w2, -h2, h2, (double)distance - depth, (double)distance + depth); break; } // case Perspective: diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 4b719dc238f..83dbb0f6d89 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -9,6 +9,8 @@ namespace GUI { struct Camera { + static const float DefaultDistance; + enum EType : unsigned char { Unknown, @@ -20,7 +22,8 @@ struct Camera EType type; float zoom; float phi; -// float distance; + // Distance between camera position and camera target measured along the camera Z axis + float distance; bool requires_zoom_to_bed; bool inverted_phi; From 2c1f88865296fac0dd9d0507e065e8967c383ced Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 13 Jun 2019 10:24:19 +0200 Subject: [PATCH 15/37] Method Camera::apply_projection() called at every rendered frame --- src/slic3r/GUI/Camera.cpp | 5 ++++- src/slic3r/GUI/GLCanvas3D.cpp | 9 ++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 4c7cb314acb..5aa881e3e56 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -48,7 +48,7 @@ std::string Camera::get_type_as_string() const // case Perspective: // return "perspective"; case Ortho: - return "ortho"; + return "orthographic"; }; } @@ -160,12 +160,15 @@ void Camera::debug_render() const imgui.set_next_window_bg_alpha(0.5f); imgui.begin(std::string("Camera statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + std::string type = get_type_as_string(); Vec3f position = get_position().cast(); Vec3f target = m_target.cast(); Vec3f forward = get_dir_forward().cast(); Vec3f right = get_dir_right().cast(); Vec3f up = get_dir_up().cast(); + ImGui::InputText("Type", const_cast(type.data()), type.length(), ImGuiInputTextFlags_ReadOnly); + ImGui::Separator(); ImGui::InputFloat3("Position", position.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); ImGui::InputFloat3("Target", target.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); ImGui::Separator(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 151ec3bdb30..6648d744bd7 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1624,6 +1624,7 @@ void GLCanvas3D::render() } m_camera.apply_view_matrix(); + m_camera.apply_projection(_max_bounding_box()); GLfloat position_cam[4] = { 1.0f, 0.0f, 1.0f, 0.0f }; glsafe(::glLightfv(GL_LIGHT1, GL_POSITION, position_cam)); @@ -2515,7 +2516,7 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) m_layers_editing.band_width = std::max(std::min(m_layers_editing.band_width * (1.0f + 0.1f * (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta()), 10.0f), 1.5f); if (m_canvas != nullptr) m_canvas->Refresh(); - + return; } } @@ -2526,8 +2527,7 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) return; // Calculate the zoom delta and apply it to the current zoom factor - float zoom = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta(); - set_camera_zoom(zoom); + set_camera_zoom((float)evt.GetWheelRotation() / (float)evt.GetWheelDelta()); } void GLCanvas3D::on_timer(wxTimerEvent& evt) @@ -3293,7 +3293,7 @@ void GLCanvas3D::set_camera_zoom(float zoom) zoom = std::min(zoom, 100.0f); m_camera.zoom = zoom; - _refresh_if_shown_on_screen(); + m_dirty = true; } void GLCanvas3D::update_gizmos_on_off_state() @@ -3609,7 +3609,6 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) // updates camera m_camera.apply_viewport(0, 0, w, h); - m_camera.apply_projection(_max_bounding_box()); m_dirty = false; } From 9877945e2aadae259333d3d32b39ed2206871ae3 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 14 Jun 2019 10:38:09 +0200 Subject: [PATCH 16/37] Tighter camera frustrum to reduce z-fighting --- src/slic3r/GUI/3DBed.cpp | 26 +++++++- src/slic3r/GUI/3DBed.hpp | 8 ++- src/slic3r/GUI/Camera.cpp | 55 ++++++++++++++-- src/slic3r/GUI/Camera.hpp | 9 +++ src/slic3r/GUI/GLCanvas3D.cpp | 76 ++++++++++------------- src/slic3r/GUI/GLCanvas3D.hpp | 3 +- src/slic3r/GUI/GLTexture.hpp | 1 + src/slic3r/GUI/GLToolbar.cpp | 7 --- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 9 --- 9 files changed, 123 insertions(+), 71 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 8392e534a46..c82b34f498c 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -273,6 +273,7 @@ void Bed3D::Axes::render_axis(double length) const Bed3D::Bed3D() : m_type(Custom) + , m_extended_bounding_box_dirty(true) #if ENABLE_TEXTURES_FROM_SVG , m_vbo_id(0) #endif // ENABLE_TEXTURES_FROM_SVG @@ -290,7 +291,7 @@ bool Bed3D::set_shape(const Pointfs& shape) m_shape = shape; m_type = new_type; - calc_bounding_box(); + calc_bounding_boxes(); ExPolygon poly; for (const Vec2d& p : m_shape) @@ -311,7 +312,9 @@ bool Bed3D::set_shape(const Pointfs& shape) // Set the origin and size for painting of the coordinate system axes. m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z); - m_axes.length = 0.1 * get_bounding_box().max_size() * Vec3d::Ones(); + m_axes.length = 0.1 * m_bounding_box.max_size() * Vec3d::Ones(); + + m_extended_bounding_box_dirty = true; // Let the calee to update the UI. return true; @@ -400,13 +403,27 @@ void Bed3D::render_axes() const m_axes.render(); } -void Bed3D::calc_bounding_box() +void Bed3D::calc_bounding_boxes() const { m_bounding_box = BoundingBoxf3(); for (const Vec2d& p : m_shape) { m_bounding_box.merge(Vec3d(p(0), p(1), 0.0)); } + + m_extended_bounding_box = m_bounding_box; + + if (m_extended_bounding_box_dirty) + { + // extend to contain Z axis + m_extended_bounding_box.merge(0.1 * m_bounding_box.max_size() * Vec3d::UnitZ()); + + if (!m_model.get_filename().empty()) + // extend to contain model + m_extended_bounding_box.merge(m_model.get_bounding_box()); + + m_extended_bounding_box_dirty = false; + } } void Bed3D::calc_triangles(const ExPolygon& poly) @@ -539,6 +556,9 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const offset += Vec3d(0.0, 0.0, -0.03); m_model.center_around(offset); + + // update extended bounding box + calc_bounding_boxes(); } if (!m_model.get_filename().empty()) diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index e60cdf94e1b..79e96fdf010 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -85,7 +85,9 @@ public: private: EType m_type; Pointfs m_shape; - BoundingBoxf3 m_bounding_box; + mutable BoundingBoxf3 m_bounding_box; + mutable BoundingBoxf3 m_extended_bounding_box; + mutable bool m_extended_bounding_box_dirty; Polygon m_polygon; GeometryBuffer m_triangles; GeometryBuffer m_gridlines; @@ -117,7 +119,7 @@ public: // Return true if the bed shape changed, so the calee will update the UI. bool set_shape(const Pointfs& shape); - const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; } + const BoundingBoxf3& get_bounding_box(bool extended) const { return extended ? m_extended_bounding_box : m_bounding_box; } bool contains(const Point& point) const; Point point_projection(const Point& point) const; @@ -125,7 +127,7 @@ public: void render_axes() const; private: - void calc_bounding_box(); + void calc_bounding_boxes() const; void calc_triangles(const ExPolygon& poly); void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); EType detect_type(const Pointfs& shape) const; diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 5aa881e3e56..1fc2f6be360 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -23,6 +23,8 @@ namespace Slic3r { namespace GUI { const float Camera::DefaultDistance = 1000.0f; +double Camera::FrustrumMinZSize = 50.0; +double Camera::FrustrumZMargin = 10.0; Camera::Camera() : type(Ortho) @@ -127,6 +129,8 @@ void Camera::apply_view_matrix() const void Camera::apply_projection(const BoundingBoxf3& box) const { + m_frustrum_zs = calc_tight_frustrum_zs_around(box); + switch (type) { case Ortho: @@ -141,10 +145,7 @@ void Camera::apply_projection(const BoundingBoxf3& box) const h2 *= inv_two_zoom; } - // FIXME: calculate a tighter value for depth will improve z-fighting - // Set at least some minimum depth in case the bounding box is empty to avoid an OpenGL driver error. - double depth = std::max(1.0, 5.0 * box.max_size()); - apply_ortho_projection(-w2, w2, -h2, h2, (double)distance - depth, (double)distance + depth); + apply_ortho_projection(-w2, w2, -h2, h2, m_frustrum_zs.first, m_frustrum_zs.second); break; } // case Perspective: @@ -166,6 +167,8 @@ void Camera::debug_render() const Vec3f forward = get_dir_forward().cast(); Vec3f right = get_dir_right().cast(); Vec3f up = get_dir_up().cast(); + float nearZ = (float)m_frustrum_zs.first; + float farZ = (float)m_frustrum_zs.second; ImGui::InputText("Type", const_cast(type.data()), type.length(), ImGuiInputTextFlags_ReadOnly); ImGui::Separator(); @@ -175,6 +178,9 @@ void Camera::debug_render() const ImGui::InputFloat3("Forward", forward.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); ImGui::InputFloat3("Right", right.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); ImGui::InputFloat3("Up", up.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); + ImGui::Separator(); + ImGui::InputFloat("Near Z", &nearZ, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); + ImGui::InputFloat("Far Z", &farZ, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); imgui.end(); } #endif // ENABLE_CAMERA_STATISTICS @@ -190,6 +196,47 @@ void Camera::apply_ortho_projection(double x_min, double x_max, double y_min, do glsafe(::glMatrixMode(GL_MODELVIEW)); } +std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const +{ + std::pair ret = std::make_pair(DBL_MAX, -DBL_MAX); + + Vec3d bb_min = box.min; + Vec3d bb_max = box.max; + + // bbox vertices in world space + std::vector vertices; + vertices.reserve(8); + vertices.push_back(bb_min); + vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2)); + vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2)); + vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2)); + vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2)); + vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2)); + vertices.push_back(bb_max); + vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2)); + + // set the Z range in eye coordinates (only negative Zs are in front of the camera) + for (const Vec3d& v : vertices) + { + // ensure non-negative values + double z = std::max(-(m_view_matrix * v)(2), 0.0); + ret.first = std::min(ret.first, z); + ret.second = std::max(ret.second, z); + } + + // apply margin + ret.first -= FrustrumZMargin; + ret.second += FrustrumZMargin; + + // ensure min size + if (ret.second - ret.first < FrustrumMinZSize) + ret.second = ret.first + FrustrumMinZSize; + + assert(ret.first > 0.0); + + return ret; +} + } // GUI } // Slic3r diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 83dbb0f6d89..18dec6083c7 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -10,6 +10,8 @@ namespace GUI { struct Camera { static const float DefaultDistance; + static double FrustrumMinZSize; + static double FrustrumZMargin; enum EType : unsigned char { @@ -34,6 +36,7 @@ private: mutable std::array m_viewport; mutable Transform3d m_view_matrix; mutable Transform3d m_projection_matrix; + mutable std::pair m_frustrum_zs; BoundingBoxf3 m_scene_box; @@ -63,6 +66,9 @@ public: Vec3d get_position() const { return m_view_matrix.matrix().inverse().block(0, 3, 3, 1); } + double get_near_z() const { return m_frustrum_zs.first; } + double get_far_z() const { return m_frustrum_zs.second; } + void apply_viewport(int x, int y, unsigned int w, unsigned int h) const; void apply_view_matrix() const; void apply_projection(const BoundingBoxf3& box) const; @@ -73,6 +79,9 @@ public: private: void apply_ortho_projection(double x_min, double x_max, double y_min, double y_max, double z_min, double z_max) const; + // returns tight values for nearZ and farZ plane around the given bounding box + // the camera MUST be outside of the bounding box in eye coordinate of the given box + std::pair calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const; }; } // GUI diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 6648d744bd7..6980e5267d1 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -304,22 +304,10 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const const Rect& bar_rect = get_bar_rect_viewport(canvas); const Rect& reset_rect = get_reset_rect_viewport(canvas); - glsafe(::glDisable(GL_DEPTH_TEST)); - - // The viewport and camera are set to complete view and glOrtho(-$x / 2, $x / 2, -$y / 2, $y / 2, -$depth, $depth), - // where x, y is the window size divided by $self->_zoom. - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - _render_tooltip_texture(canvas, bar_rect, reset_rect); _render_reset_texture(reset_rect); _render_active_object_annotations(canvas, bar_rect); _render_profile(bar_rect); - - // Revert the matrices. - glsafe(::glPopMatrix()); - - glsafe(::glEnable(GL_DEPTH_TEST)); } float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas) @@ -880,10 +868,6 @@ void GLCanvas3D::WarningTexture::render(const GLCanvas3D& canvas) const if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0)) { - glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - const Size& cnv_size = canvas.get_canvas_size(); float zoom = canvas.get_camera().zoom; float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; @@ -904,9 +888,6 @@ void GLCanvas3D::WarningTexture::render(const GLCanvas3D& canvas) const uvs.right_top = { uv_right, uv_top }; GLTexture::render_sub_texture(m_id, left, right, bottom, top, uvs); - - glsafe(::glPopMatrix()); - glsafe(::glEnable(GL_DEPTH_TEST)); } } @@ -1160,10 +1141,6 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const { if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0)) { - glsafe(::glDisable(GL_DEPTH_TEST)); - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - const Size& cnv_size = canvas.get_canvas_size(); float zoom = canvas.get_camera().zoom; float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; @@ -1184,9 +1161,6 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const uvs.right_top = { uv_right, uv_top }; GLTexture::render_sub_texture(m_id, left, right, bottom, top, uvs); - - glsafe(::glPopMatrix()); - glsafe(::glEnable(GL_DEPTH_TEST)); } } @@ -1466,7 +1440,7 @@ BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const BoundingBoxf3 GLCanvas3D::scene_bounding_box() const { BoundingBoxf3 bb = volumes_bounding_box(); - bb.merge(m_bed.get_bounding_box()); + bb.merge(m_bed.get_bounding_box(false)); if (m_config != nullptr) { @@ -1550,7 +1524,7 @@ void GLCanvas3D::allow_multisample(bool allow) void GLCanvas3D::zoom_to_bed() { - _zoom_to_bounding_box(m_bed.get_bounding_box()); + _zoom_to_bounding_box(m_bed.get_bounding_box(false)); } void GLCanvas3D::zoom_to_volumes() @@ -1624,7 +1598,7 @@ void GLCanvas3D::render() } m_camera.apply_view_matrix(); - m_camera.apply_projection(_max_bounding_box()); + m_camera.apply_projection(_max_bounding_box(true)); GLfloat position_cam[4] = { 1.0f, 0.0f, 1.0f, 0.0f }; glsafe(::glLightfv(GL_LIGHT1, GL_POSITION, position_cam)); @@ -1686,16 +1660,7 @@ void GLCanvas3D::render() m_rectangle_selection.render(*this); // draw overlays - _render_gizmos_overlay(); - _render_warning_texture(); - _render_legend_texture(); -#if !ENABLE_SVG_ICONS - _resize_toolbars(); -#endif // !ENABLE_SVG_ICONS - _render_toolbar(); - _render_view_toolbar(); - if ((m_layers_editing.last_object_id >= 0) && (m_layers_editing.object_max_z() > 0.0f)) - m_layers_editing.render_overlay(*this); + _render_overlays(); #if ENABLE_RENDER_STATISTICS ImGuiWrapper& imgui = *wxGetApp().imgui(); @@ -3285,7 +3250,7 @@ void GLCanvas3D::set_camera_zoom(float zoom) zoom = m_camera.zoom / (1.0f - zoom); // Don't allow to zoom too far outside the scene. - float zoom_min = _get_zoom_to_bounding_box_factor(_max_bounding_box()); + float zoom_min = _get_zoom_to_bounding_box_factor(_max_bounding_box(false)); if (zoom_min > 0.0f) zoom = std::max(zoom, zoom_min * 0.7f); @@ -3375,7 +3340,7 @@ Linef3 GLCanvas3D::mouse_ray(const Point& mouse_pos) double GLCanvas3D::get_size_proportional_to_max_bed_size(double factor) const { - return factor * m_bed.get_bounding_box().max_size(); + return factor * m_bed.get_bounding_box(false).max_size(); } void GLCanvas3D::set_cursor(ECursorType type) @@ -3613,10 +3578,10 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) m_dirty = false; } -BoundingBoxf3 GLCanvas3D::_max_bounding_box() const +BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_bed_model) const { BoundingBoxf3 bb = volumes_bounding_box(); - bb.merge(m_bed.get_bounding_box()); + bb.merge(m_bed.get_bounding_box(include_bed_model)); return bb; } @@ -3907,7 +3872,7 @@ void GLCanvas3D::_render_objects() const if (m_config != nullptr) { - const BoundingBoxf3& bed_bb = m_bed.get_bounding_box(); + const BoundingBoxf3& bed_bb = m_bed.get_bounding_box(false); m_volumes.set_print_box((float)bed_bb.min(0), (float)bed_bb.min(1), 0.0f, (float)bed_bb.max(0), (float)bed_bb.max(1), (float)m_config->opt_float("max_print_height")); m_volumes.check_outside_state(m_config, nullptr); } @@ -3989,6 +3954,29 @@ void GLCanvas3D::_render_selection_center() const } #endif // ENABLE_RENDER_SELECTION_CENTER +void GLCanvas3D::_render_overlays() const +{ + glsafe(::glDisable(GL_DEPTH_TEST)); + glsafe(::glPushMatrix()); + glsafe(::glLoadIdentity()); + // ensure the textures are renderered inside the frustrum + glsafe(::glTranslated(0.0, 0.0, -(m_camera.get_near_z() + 0.5))); + + _render_gizmos_overlay(); + _render_warning_texture(); + _render_legend_texture(); +#if !ENABLE_SVG_ICONS + _resize_toolbars(); +#endif // !ENABLE_SVG_ICONS + _render_toolbar(); + _render_view_toolbar(); + + if ((m_layers_editing.last_object_id >= 0) && (m_layers_editing.object_max_z() > 0.0f)) + m_layers_editing.render_overlay(*this); + + glsafe(::glPopMatrix()); +} + void GLCanvas3D::_render_warning_texture() const { m_warning_texture.render(*this); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 51a36cf69f8..a0174dd7f4b 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -635,7 +635,7 @@ private: bool _set_current(); void _resize(unsigned int w, unsigned int h); - BoundingBoxf3 _max_bounding_box() const; + BoundingBoxf3 _max_bounding_box(bool include_bed_model) const; void _zoom_to_bounding_box(const BoundingBoxf3& bbox); float _get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) const; @@ -652,6 +652,7 @@ private: #if ENABLE_RENDER_SELECTION_CENTER void _render_selection_center() const; #endif // ENABLE_RENDER_SELECTION_CENTER + void _render_overlays() const; void _render_warning_texture() const; void _render_legend_texture() const; void _render_volumes_for_picking() const; diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index e00b3a3bea1..0c5c0efbe1e 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -62,6 +62,7 @@ namespace GUI { protected: unsigned int generate_mipmaps(wxImage& image); + private: bool load_from_png(const std::string& filename, bool use_mipmaps); bool load_from_svg(const std::string& filename, bool use_mipmaps, unsigned int max_size_px); diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 00cbdfec715..e73533d37f3 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -390,19 +390,12 @@ void GLToolbar::render(const GLCanvas3D& parent) const generate_icons_texture(); #endif // ENABLE_SVG_ICONS - glsafe(::glDisable(GL_DEPTH_TEST)); - - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - switch (m_layout.type) { default: case Layout::Horizontal: { render_horizontal(parent); break; } case Layout::Vertical: { render_vertical(parent); break; } } - - glsafe(::glPopMatrix()); } bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 1006d2bd1e9..32809c01d33 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -531,18 +531,9 @@ void GLGizmosManager::render_overlay(const GLCanvas3D& canvas, const Selection& generate_icons_texture(); #endif // ENABLE_SVG_ICONS - glsafe(::glDisable(GL_DEPTH_TEST)); - - glsafe(::glPushMatrix()); - glsafe(::glLoadIdentity()); - do_render_overlay(canvas, selection); - - glsafe(::glPopMatrix()); } - - bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt, GLCanvas3D& canvas) { bool processed = false; From d5a17b11c87c52a396163a10d9d8e375c51dafe0 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 14 Jun 2019 15:37:29 +0200 Subject: [PATCH 17/37] Follow-up of 1a91add2e60f3a4d22cdd6c8a10e57dc8095e0a2 -> Improvements to tighter camera frustrum to reduce z-fighting --- src/slic3r/GUI/3DBed.cpp | 20 ++++++-------------- src/slic3r/GUI/3DBed.hpp | 1 - src/slic3r/GUI/3DScene.hpp | 1 + src/slic3r/GUI/Camera.cpp | 9 ++++++++- src/slic3r/GUI/GLCanvas3D.cpp | 4 ++-- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index c82b34f498c..404fb47745c 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -211,7 +211,7 @@ const double Bed3D::Axes::ArrowLength = 5.0; Bed3D::Axes::Axes() : origin(Vec3d::Zero()) -, length(Vec3d::Zero()) +, length(25.0 * Vec3d::Ones()) { m_quadric = ::gluNewQuadric(); if (m_quadric != nullptr) @@ -273,7 +273,6 @@ void Bed3D::Axes::render_axis(double length) const Bed3D::Bed3D() : m_type(Custom) - , m_extended_bounding_box_dirty(true) #if ENABLE_TEXTURES_FROM_SVG , m_vbo_id(0) #endif // ENABLE_TEXTURES_FROM_SVG @@ -314,8 +313,6 @@ bool Bed3D::set_shape(const Pointfs& shape) m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z); m_axes.length = 0.1 * m_bounding_box.max_size() * Vec3d::Ones(); - m_extended_bounding_box_dirty = true; - // Let the calee to update the UI. return true; } @@ -413,17 +410,12 @@ void Bed3D::calc_bounding_boxes() const m_extended_bounding_box = m_bounding_box; - if (m_extended_bounding_box_dirty) - { - // extend to contain Z axis - m_extended_bounding_box.merge(0.1 * m_bounding_box.max_size() * Vec3d::UnitZ()); + // extend to contain axes + m_extended_bounding_box.merge(m_axes.length + Axes::ArrowLength * Vec3d::Ones()); - if (!m_model.get_filename().empty()) - // extend to contain model - m_extended_bounding_box.merge(m_model.get_bounding_box()); - - m_extended_bounding_box_dirty = false; - } + // extend to contain model, if any + if (!m_model.get_filename().empty()) + m_extended_bounding_box.merge(m_model.get_transformed_bounding_box()); } void Bed3D::calc_triangles(const ExPolygon& poly) diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 79e96fdf010..98da0354231 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -87,7 +87,6 @@ private: Pointfs m_shape; mutable BoundingBoxf3 m_bounding_box; mutable BoundingBoxf3 m_extended_bounding_box; - mutable bool m_extended_bounding_box_dirty; Polygon m_polygon; GeometryBuffer m_triangles; GeometryBuffer m_gridlines; diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 2ca11073be9..c0613badd1b 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -555,6 +555,7 @@ public: const std::string& get_filename() const { return m_filename; } const BoundingBoxf3& get_bounding_box() const { return m_volume.bounding_box; } + const BoundingBoxf3& get_transformed_bounding_box() const { return m_volume.transformed_bounding_box(); } void reset(); diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 1fc2f6be360..f6cefc8010d 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -169,6 +169,7 @@ void Camera::debug_render() const Vec3f up = get_dir_up().cast(); float nearZ = (float)m_frustrum_zs.first; float farZ = (float)m_frustrum_zs.second; + float deltaZ = farZ - nearZ; ImGui::InputText("Type", const_cast(type.data()), type.length(), ImGuiInputTextFlags_ReadOnly); ImGui::Separator(); @@ -181,6 +182,7 @@ void Camera::debug_render() const ImGui::Separator(); ImGui::InputFloat("Near Z", &nearZ, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); ImGui::InputFloat("Far Z", &farZ, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); + ImGui::InputFloat("Delta Z", &deltaZ, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); imgui.end(); } #endif // ENABLE_CAMERA_STATISTICS @@ -230,7 +232,12 @@ std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBo // ensure min size if (ret.second - ret.first < FrustrumMinZSize) - ret.second = ret.first + FrustrumMinZSize; + { + double mid_z = 0.5 * (ret.first + ret.second); + double half_size = 0.5 * FrustrumMinZSize; + ret.first = mid_z - half_size; + ret.second = mid_z + half_size; + } assert(ret.first > 0.0); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index faee2727db6..fd77b460961 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1590,8 +1590,8 @@ void GLCanvas3D::render() if (m_camera.requires_zoom_to_bed) { zoom_to_bed(); - const Size& cnv_size = get_canvas_size(); - _resize((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); +// const Size& cnv_size = get_canvas_size(); +// _resize((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); m_camera.requires_zoom_to_bed = false; } From 1f33c9972677c682d9c3a220983fc8ee3bc5abd4 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 19 Jun 2019 13:01:18 +0200 Subject: [PATCH 18/37] Enabled perspective camera --- src/slic3r/GUI/Camera.cpp | 77 +++++++++++++++++++---------------- src/slic3r/GUI/Camera.hpp | 14 ++++--- src/slic3r/GUI/GLCanvas3D.cpp | 2 + 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index f6cefc8010d..1620548ef97 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -22,19 +22,19 @@ static const float VIEW_REAR[2] = { 180.0f, 90.0f }; namespace Slic3r { namespace GUI { -const float Camera::DefaultDistance = 1000.0f; +const double Camera::DefaultDistance = 1000.0; double Camera::FrustrumMinZSize = 50.0; double Camera::FrustrumZMargin = 10.0; Camera::Camera() - : type(Ortho) - , zoom(1.0f) + : zoom(1.0f) , phi(45.0f) - , distance(DefaultDistance) , requires_zoom_to_bed(false) , inverted_phi(false) - , m_theta(45.0f) + , m_type(Ortho) , m_target(Vec3d::Zero()) + , m_theta(45.0f) + , m_distance(DefaultDistance) , m_view_matrix(Transform3d::Identity()) , m_projection_matrix(Transform3d::Identity()) { @@ -42,18 +42,27 @@ Camera::Camera() std::string Camera::get_type_as_string() const { - switch (type) + switch (m_type) { default: case Unknown: return "unknown"; -// case Perspective: -// return "perspective"; + case Perspective: + return "perspective"; case Ortho: return "orthographic"; }; } +void Camera::select_next_type() +{ + unsigned char next = (unsigned char)m_type + 1; + if (next == (unsigned char)Num_types) + next = 1; + + m_type = (EType)next; +} + void Camera::set_target(const Vec3d& target) { m_target = target; @@ -114,7 +123,7 @@ void Camera::apply_view_matrix() const double theta_rad = Geometry::deg2rad(-(double)m_theta); double phi_rad = Geometry::deg2rad((double)phi); double sin_theta = ::sin(theta_rad); - Vec3d camera_pos = m_target + (double)distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad)); + Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad)); glsafe(::glMatrixMode(GL_MODELVIEW)); glsafe(::glLoadIdentity()); @@ -131,27 +140,36 @@ void Camera::apply_projection(const BoundingBoxf3& box) const { m_frustrum_zs = calc_tight_frustrum_zs_around(box); - switch (type) + double w = (double)m_viewport[2]; + double h = (double)m_viewport[3]; + double two_zoom = 2.0 * zoom; + if (two_zoom != 0.0) { + double inv_two_zoom = 1.0 / two_zoom; + w *= inv_two_zoom; + h *= inv_two_zoom; + } + + glsafe(::glMatrixMode(GL_PROJECTION)); + glsafe(::glLoadIdentity()); + + switch (m_type) + { + default: case Ortho: { - double w2 = (double)m_viewport[2]; - double h2 = (double)m_viewport[3]; - double two_zoom = 2.0 * zoom; - if (two_zoom != 0.0) - { - double inv_two_zoom = 1.0 / two_zoom; - w2 *= inv_two_zoom; - h2 *= inv_two_zoom; - } - - apply_ortho_projection(-w2, w2, -h2, h2, m_frustrum_zs.first, m_frustrum_zs.second); + glsafe(::glOrtho(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second)); break; } -// case Perspective: -// { -// } + case Perspective: + { + glsafe(::glFrustum(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second)); + break; } + } + + glsafe(::glGetDoublev(GL_PROJECTION_MATRIX, m_projection_matrix.data())); + glsafe(::glMatrixMode(GL_MODELVIEW)); } #if ENABLE_CAMERA_STATISTICS @@ -187,17 +205,6 @@ void Camera::debug_render() const } #endif // ENABLE_CAMERA_STATISTICS -void Camera::apply_ortho_projection(double x_min, double x_max, double y_min, double y_max, double z_min, double z_max) const -{ - glsafe(::glMatrixMode(GL_PROJECTION)); - glsafe(::glLoadIdentity()); - - glsafe(::glOrtho(x_min, x_max, y_min, y_max, z_min, z_max)); - glsafe(::glGetDoublev(GL_PROJECTION_MATRIX, m_projection_matrix.data())); - - glsafe(::glMatrixMode(GL_MODELVIEW)); -} - std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const { std::pair ret = std::make_pair(DBL_MAX, -DBL_MAX); diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 18dec6083c7..3f8d676b5b2 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -9,29 +9,29 @@ namespace GUI { struct Camera { - static const float DefaultDistance; + static const double DefaultDistance; static double FrustrumMinZSize; static double FrustrumZMargin; enum EType : unsigned char { Unknown, -// Perspective, + Perspective, Ortho, Num_types }; - EType type; float zoom; float phi; - // Distance between camera position and camera target measured along the camera Z axis - float distance; bool requires_zoom_to_bed; bool inverted_phi; private: + EType m_type; Vec3d m_target; float m_theta; + // Distance between camera position and camera target measured along the camera Z axis + double m_distance; mutable std::array m_viewport; mutable Transform3d m_view_matrix; @@ -43,7 +43,10 @@ private: public: Camera(); + EType get_type() const { return m_type; } std::string get_type_as_string() const; + void set_type(EType type) { m_type = type; } + void select_next_type(); const Vec3d& get_target() const { return m_target; } void set_target(const Vec3d& target); @@ -78,7 +81,6 @@ public: #endif // ENABLE_CAMERA_STATISTICS private: - void apply_ortho_projection(double x_min, double x_max, double y_min, double y_max, double z_min, double z_max) const; // returns tight values for nearZ and farZ plane around the given bounding box // the camera MUST be outside of the bounding box in eye coordinate of the given box std::pair calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 021a72dcb08..7f8d9158362 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2365,6 +2365,8 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'a': { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; } case 'B': case 'b': { zoom_to_bed(); break; } + case 'C': + case 'c': { m_camera.select_next_type(); m_dirty = true; break; } case 'I': case 'i': { set_camera_zoom(1.0f); break; } case 'O': From eff108c58b15a6ba2aa88968f718237845a1edfa Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 19 Jun 2019 14:18:51 +0200 Subject: [PATCH 19/37] More camera related functionalities moved from GLCanvas3D to Camera --- src/slic3r/GUI/Camera.cpp | 98 +++++++++++++++++- src/slic3r/GUI/Camera.hpp | 10 +- src/slic3r/GUI/GLCanvas3D.cpp | 116 ++++------------------ src/slic3r/GUI/GLCanvas3D.hpp | 5 +- src/slic3r/GUI/GLSelectionRectangle.cpp | 2 +- src/slic3r/GUI/GLToolbar.cpp | 12 +-- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 2 +- 7 files changed, 131 insertions(+), 114 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index 1620548ef97..a3ecb5e5410 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -27,13 +27,13 @@ double Camera::FrustrumMinZSize = 50.0; double Camera::FrustrumZMargin = 10.0; Camera::Camera() - : zoom(1.0f) - , phi(45.0f) + : phi(45.0f) , requires_zoom_to_bed(false) , inverted_phi(false) , m_type(Ortho) , m_target(Vec3d::Zero()) , m_theta(45.0f) + , m_zoom(1.0) , m_distance(DefaultDistance) , m_view_matrix(Transform3d::Identity()) , m_projection_matrix(Transform3d::Identity()) @@ -83,6 +83,22 @@ void Camera::set_theta(float theta, bool apply_limit) } } +void Camera::set_zoom(double zoom, const BoundingBoxf3& max_box, int canvas_w, int canvas_h) +{ + zoom = std::max(std::min(zoom, 4.0), -4.0) / 10.0; + zoom = m_zoom / (1.0 - zoom); + + // Don't allow to zoom too far outside the scene. + double zoom_min = calc_zoom_to_bounding_box_factor(max_box, canvas_w, canvas_h); + if (zoom_min > 0.0) + zoom = std::max(zoom, zoom_min * 0.7); + + // Don't allow to zoom too close to the scene. + zoom = std::min(zoom, 100.0); + + m_zoom = zoom; +} + bool Camera::select_view(const std::string& direction) { const float* dir_vec = nullptr; @@ -142,7 +158,8 @@ void Camera::apply_projection(const BoundingBoxf3& box) const double w = (double)m_viewport[2]; double h = (double)m_viewport[3]; - double two_zoom = 2.0 * zoom; + + double two_zoom = 2.0 * m_zoom; if (two_zoom != 0.0) { double inv_two_zoom = 1.0 / two_zoom; @@ -172,6 +189,18 @@ void Camera::apply_projection(const BoundingBoxf3& box) const glsafe(::glMatrixMode(GL_MODELVIEW)); } +void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h) +{ + // Calculate the zoom factor needed to adjust the view around the given box. + double zoom = calc_zoom_to_bounding_box_factor(box, canvas_w, canvas_h); + if (zoom > 0.0) + { + m_zoom = zoom; + // center view around box center + m_target = box.center(); + } +} + #if ENABLE_CAMERA_STATISTICS void Camera::debug_render() const { @@ -212,7 +241,7 @@ std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBo Vec3d bb_min = box.min; Vec3d bb_max = box.max; - // bbox vertices in world space + // box vertices in world space std::vector vertices; vertices.reserve(8); vertices.push_back(bb_min); @@ -251,6 +280,67 @@ std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBo return ret; } +double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const +{ + double max_bb_size = box.max_size(); + if (max_bb_size == 0.0) + return -1.0; + + // project the box vertices on a plane perpendicular to the camera forward axis + // then calculates the vertices coordinate on this plane along the camera xy axes + + // ensure that the view matrix is updated + apply_view_matrix(); + + Vec3d right = get_dir_right(); + Vec3d up = get_dir_up(); + Vec3d forward = get_dir_forward(); + + Vec3d bb_min = box.min; + Vec3d bb_max = box.max; + Vec3d bb_center = box.center(); + + // box vertices in world space + std::vector vertices; + vertices.reserve(8); + vertices.push_back(bb_min); + vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2)); + vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2)); + vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2)); + vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2)); + vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2)); + vertices.push_back(bb_max); + vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2)); + + double max_x = 0.0; + double max_y = 0.0; + + // margin factor to give some empty space around the box + double margin_factor = 1.25; + + for (const Vec3d& v : vertices) + { + // project vertex on the plane perpendicular to camera forward axis + Vec3d pos(v(0) - bb_center(0), v(1) - bb_center(1), v(2) - bb_center(2)); + Vec3d proj_on_plane = pos - pos.dot(forward) * forward; + + // calculates vertex coordinate along camera xy axes + double x_on_plane = proj_on_plane.dot(right); + double y_on_plane = proj_on_plane.dot(up); + + max_x = std::max(max_x, std::abs(x_on_plane)); + max_y = std::max(max_y, std::abs(y_on_plane)); + } + + if ((max_x == 0.0) || (max_y == 0.0)) + return -1.0f; + + max_x *= margin_factor; + max_y *= margin_factor; + + return std::min((double)canvas_w / (2.0 * max_x), (double)canvas_h / (2.0 * max_y)); +} + } // GUI } // Slic3r diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 3f8d676b5b2..fe6571b0563 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -21,7 +21,6 @@ struct Camera Num_types }; - float zoom; float phi; bool requires_zoom_to_bed; bool inverted_phi; @@ -30,6 +29,7 @@ private: EType m_type; Vec3d m_target; float m_theta; + double m_zoom; // Distance between camera position and camera target measured along the camera Z axis double m_distance; @@ -54,8 +54,11 @@ public: float get_theta() const { return m_theta; } void set_theta(float theta, bool apply_limit); + double get_zoom() const { return m_zoom; } + void set_zoom(double zoom, const BoundingBoxf3& max_box, int canvas_w, int canvas_h); + const BoundingBoxf3& get_scene_box() const { return m_scene_box; } - void set_scene_box(const BoundingBoxf3& box){ m_scene_box = box; } + void set_scene_box(const BoundingBoxf3& box) { m_scene_box = box; } bool select_view(const std::string& direction); @@ -76,6 +79,8 @@ public: void apply_view_matrix() const; void apply_projection(const BoundingBoxf3& box) const; + void zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h); + #if ENABLE_CAMERA_STATISTICS void debug_render() const; #endif // ENABLE_CAMERA_STATISTICS @@ -84,6 +89,7 @@ private: // returns tight values for nearZ and farZ plane around the given bounding box // the camera MUST be outside of the bounding box in eye coordinate of the given box std::pair calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const; + double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const; }; } // GUI diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 7f8d9158362..d126c54459f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -357,7 +357,7 @@ Rect GLCanvas3D::LayersEditing::get_bar_rect_viewport(const GLCanvas3D& canvas) float half_w = 0.5f * (float)cnv_size.get_width(); float half_h = 0.5f * (float)cnv_size.get_height(); - float zoom = canvas.get_camera().zoom; + float zoom = (float)canvas.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom); @@ -369,7 +369,7 @@ Rect GLCanvas3D::LayersEditing::get_reset_rect_viewport(const GLCanvas3D& canvas float half_w = 0.5f * (float)cnv_size.get_width(); float half_h = 0.5f * (float)cnv_size.get_height(); - float zoom = canvas.get_camera().zoom; + float zoom = (float)canvas.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, (-half_h + reset_button_height(canvas)) * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom); @@ -400,7 +400,7 @@ void GLCanvas3D::LayersEditing::_render_tooltip_texture(const GLCanvas3D& canvas const float width = (float)m_tooltip_texture.get_width() * scale; const float height = (float)m_tooltip_texture.get_height() * scale; - float zoom = canvas.get_camera().zoom; + float zoom = (float)canvas.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; float gap = 10.0f * inv_zoom; @@ -867,7 +867,7 @@ void GLCanvas3D::WarningTexture::render(const GLCanvas3D& canvas) const if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0)) { const Size& cnv_size = canvas.get_canvas_size(); - float zoom = canvas.get_camera().zoom; + float zoom = (float)canvas.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; float left = (-0.5f * (float)m_original_width) * inv_zoom; float top = (-0.5f * (float)cnv_size.get_height() + (float)m_original_height + 2.0f) * inv_zoom; @@ -1140,7 +1140,7 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const if ((m_id > 0) && (m_original_width > 0) && (m_original_height > 0) && (m_width > 0) && (m_height > 0)) { const Size& cnv_size = canvas.get_canvas_size(); - float zoom = canvas.get_camera().zoom; + float zoom = (float)canvas.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; float left = (-0.5f * (float)cnv_size.get_width()) * inv_zoom; float top = (0.5f * (float)cnv_size.get_height()) * inv_zoom; @@ -1523,20 +1523,20 @@ void GLCanvas3D::allow_multisample(bool allow) void GLCanvas3D::zoom_to_bed() { - _zoom_to_bounding_box(m_bed.get_bounding_box(false)); + _zoom_to_box(m_bed.get_bounding_box(false)); } void GLCanvas3D::zoom_to_volumes() { m_apply_zoom_to_volumes_filter = true; - _zoom_to_bounding_box(volumes_bounding_box()); + _zoom_to_box(volumes_bounding_box()); m_apply_zoom_to_volumes_filter = false; } void GLCanvas3D::zoom_to_selection() { if (!m_selection.is_empty()) - _zoom_to_bounding_box(m_selection.get_bounding_box()); + _zoom_to_box(m_selection.get_bounding_box()); } void GLCanvas3D::select_view(const std::string& direction) @@ -2368,9 +2368,9 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'C': case 'c': { m_camera.select_next_type(); m_dirty = true; break; } case 'I': - case 'i': { set_camera_zoom(1.0f); break; } + case 'i': { set_camera_zoom(1.0); break; } case 'O': - case 'o': { set_camera_zoom(-1.0f); break; } + case 'o': { set_camera_zoom(-1.0); break; } case 'Z': case 'z': { m_selection.is_empty() ? zoom_to_volumes() : zoom_to_selection(); break; } default: { evt.Skip(); break; } @@ -2507,7 +2507,7 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) return; // Calculate the zoom delta and apply it to the current zoom factor - set_camera_zoom((float)evt.GetWheelRotation() / (float)evt.GetWheelDelta()); + set_camera_zoom((double)evt.GetWheelRotation() / (double)evt.GetWheelDelta()); } void GLCanvas3D::on_timer(wxTimerEvent& evt) @@ -3259,20 +3259,10 @@ void GLCanvas3D::do_mirror() post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); } -void GLCanvas3D::set_camera_zoom(float zoom) +void GLCanvas3D::set_camera_zoom(double zoom) { - zoom = std::max(std::min(zoom, 4.0f), -4.0f) / 10.0f; - zoom = m_camera.zoom / (1.0f - zoom); - - // Don't allow to zoom too far outside the scene. - float zoom_min = _get_zoom_to_bounding_box_factor(_max_bounding_box(false)); - if (zoom_min > 0.0f) - zoom = std::max(zoom, zoom_min * 0.7f); - - // Don't allow to zoom too close to the scene. - zoom = std::min(zoom, 100.0f); - - m_camera.zoom = zoom; + const Size& cnv_size = get_canvas_size(); + m_camera.set_zoom(zoom, _max_bounding_box(false), cnv_size.get_width(), cnv_size.get_height()); m_dirty = true; } @@ -3600,79 +3590,11 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_bed_model) const return bb; } -void GLCanvas3D::_zoom_to_bounding_box(const BoundingBoxf3& bbox) +void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box) { - // Calculate the zoom factor needed to adjust viewport to bounding box. - float zoom = _get_zoom_to_bounding_box_factor(bbox); - if (zoom > 0.0f) - { - m_camera.zoom = zoom; - // center view around bounding box center - m_camera.set_target(bbox.center()); - m_dirty = true; - } -} - -float GLCanvas3D::_get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) const -{ - float max_bb_size = bbox.max_size(); - if (max_bb_size == 0.0f) - return -1.0f; - - // project the bbox vertices on a plane perpendicular to the camera forward axis - // then calculates the vertices coordinate on this plane along the camera xy axes - - // we need the view matrix, we let opengl calculate it (same as done in render()) - m_camera.apply_view_matrix(); - - Vec3d right = m_camera.get_dir_right(); - Vec3d up = m_camera.get_dir_up(); - Vec3d forward = m_camera.get_dir_forward(); - - Vec3d bb_min = bbox.min; - Vec3d bb_max = bbox.max; - Vec3d bb_center = bbox.center(); - - // bbox vertices in world space - std::vector vertices; - vertices.reserve(8); - vertices.push_back(bb_min); - vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2)); - vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2)); - vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2)); - vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2)); - vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2)); - vertices.push_back(bb_max); - vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2)); - - double max_x = 0.0; - double max_y = 0.0; - - // margin factor to give some empty space around the bbox - double margin_factor = 1.25; - - for (const Vec3d& v : vertices) - { - // project vertex on the plane perpendicular to camera forward axis - Vec3d pos(v(0) - bb_center(0), v(1) - bb_center(1), v(2) - bb_center(2)); - Vec3d proj_on_plane = pos - pos.dot(forward) * forward; - - // calculates vertex coordinate along camera xy axes - double x_on_plane = proj_on_plane.dot(right); - double y_on_plane = proj_on_plane.dot(up); - - max_x = std::max(max_x, margin_factor * std::abs(x_on_plane)); - max_y = std::max(max_y, margin_factor * std::abs(y_on_plane)); - } - - if ((max_x == 0.0) || (max_y == 0.0)) - return -1.0f; - - max_x *= 2.0; - max_y *= 2.0; - const Size& cnv_size = get_canvas_size(); - return (float)std::min((double)cnv_size.get_width() / max_x, (double)cnv_size.get_height() / max_y); + m_camera.zoom_to_box(box, cnv_size.get_width(), cnv_size.get_height()); + m_dirty = true; } void GLCanvas3D::_refresh_if_shown_on_screen() @@ -4088,7 +4010,7 @@ void GLCanvas3D::_render_toolbar() const #endif // ENABLE_RETINA_GL Size cnv_size = get_canvas_size(); - float zoom = m_camera.zoom; + float zoom = (float)m_camera.get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; GLToolbar::Layout::EOrientation orientation = m_toolbar.get_layout_orientation(); @@ -4156,7 +4078,7 @@ void GLCanvas3D::_render_view_toolbar() const #endif // ENABLE_RETINA_GL Size cnv_size = get_canvas_size(); - float zoom = m_camera.zoom; + float zoom = (float)m_camera.get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; // places the toolbar on the bottom-left corner of the 3d scene diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index d751ecf24fa..423e6077640 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -598,7 +598,7 @@ public: void do_flatten(); void do_mirror(); - void set_camera_zoom(float zoom); + void set_camera_zoom(double zoom); void update_gizmos_on_off_state(); void reset_all_gizmos() { m_gizmos.reset_all_states(); } @@ -638,8 +638,7 @@ private: BoundingBoxf3 _max_bounding_box(bool include_bed_model) const; - void _zoom_to_bounding_box(const BoundingBoxf3& bbox); - float _get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) const; + void _zoom_to_box(const BoundingBoxf3& box); void _refresh_if_shown_on_screen(); diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index 9684bb5ec93..327cb1fde85 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -68,7 +68,7 @@ namespace GUI { if (!is_dragging()) return; - float zoom = canvas.get_camera().zoom; + float zoom = (float)canvas.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; Size cnv_size = canvas.get_canvas_size(); diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index e73533d37f3..1b8cfc4e8a8 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -607,7 +607,7 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC { // NB: mouse_pos is already scaled appropriately - float zoom = parent.get_camera().zoom; + float zoom = (float)parent.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; #if ENABLE_SVG_ICONS float factor = m_layout.scale * inv_zoom; @@ -712,7 +712,7 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan { // NB: mouse_pos is already scaled appropriately - float zoom = parent.get_camera().zoom; + float zoom = (float)parent.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; #if ENABLE_SVG_ICONS float factor = m_layout.scale * inv_zoom; @@ -829,7 +829,7 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3 { // NB: mouse_pos is already scaled appropriately - float zoom = parent.get_camera().zoom; + float zoom = (float)parent.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; #if ENABLE_SVG_ICONS float factor = m_layout.scale * inv_zoom; @@ -912,7 +912,7 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& { // NB: mouse_pos is already scaled appropriately - float zoom = parent.get_camera().zoom; + float zoom = (float)parent.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; #if ENABLE_SVG_ICONS float factor = m_layout.scale * inv_zoom; @@ -1008,7 +1008,7 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const return; #endif // !ENABLE_SVG_ICONS - float zoom = parent.get_camera().zoom; + float zoom = (float)parent.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; #if ENABLE_SVG_ICONS float factor = inv_zoom * m_layout.scale; @@ -1163,7 +1163,7 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const return; #endif // !ENABLE_SVG_ICONS - float zoom = parent.get_camera().zoom; + float zoom = (float)parent.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; #if ENABLE_SVG_ICONS float factor = inv_zoom * m_layout.scale; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 32809c01d33..e4b386eb409 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -930,7 +930,7 @@ void GLGizmosManager::do_render_overlay(const GLCanvas3D& canvas, const Selectio float cnv_w = (float)canvas.get_canvas_size().get_width(); float cnv_h = (float)canvas.get_canvas_size().get_height(); - float zoom = canvas.get_camera().zoom; + float zoom = (float)canvas.get_camera().get_zoom(); float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f; float height = get_total_overlay_height(); From 3ddfef73474006cc3629c8e859903a202beb71c0 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 19 Jun 2019 14:33:09 +0200 Subject: [PATCH 20/37] Key K set as camera type toggle and updated keyboard shortcuts dialog --- src/slic3r/GUI/GLCanvas3D.cpp | 4 ++-- src/slic3r/GUI/KBShortcutsDialog.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d126c54459f..efebfa4a52c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2365,10 +2365,10 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'a': { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; } case 'B': case 'b': { zoom_to_bed(); break; } - case 'C': - case 'c': { m_camera.select_next_type(); m_dirty = true; break; } case 'I': case 'i': { set_camera_zoom(1.0); break; } + case 'K': + case 'k': { m_camera.select_next_type(); m_dirty = true; break; } case 'O': case 'o': { set_camera_zoom(-1.0); break; } case 'Z': diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 347dac13eaa..1af658ed367 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -147,6 +147,7 @@ void KBShortcutsDialog::fill_shortcuts() plater_shortcuts.push_back(Shortcut("F", L("Press to scale selection to fit print volume\nin Gizmo scale"))); plater_shortcuts.push_back(Shortcut(alt, L("Press to activate deselection rectangle\nor to scale or rotate selected objects\naround their own center"))); plater_shortcuts.push_back(Shortcut(ctrl, L("Press to activate one direction scaling in Gizmo scale"))); + plater_shortcuts.push_back(Shortcut("K", L("Change camera type"))); plater_shortcuts.push_back(Shortcut("B", L("Zoom to Bed"))); plater_shortcuts.push_back(Shortcut("Z", L("Zoom to all objects in scene, if none selected"))); plater_shortcuts.push_back(Shortcut("Z", L("Zoom to selected object"))); From 0e3b1d0a2fe88aaac6d21a44065579f51557625e Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 20 Jun 2019 10:02:52 +0200 Subject: [PATCH 21/37] Serialized camera type and fixed Mac build --- src/slic3r/GUI/AppConfig.cpp | 3 +++ src/slic3r/GUI/Camera.cpp | 28 ++++++++++++++++++++++++---- src/slic3r/GUI/Camera.hpp | 8 ++++++-- src/slic3r/GUI/GLCanvas3D.cpp | 7 +++---- src/slic3r/GUI/Plater.cpp | 3 +++ 5 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index d4970880b55..edc9845a13d 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -73,6 +73,9 @@ void AppConfig::set_defaults() if (get("custom_toolbar_size").empty()) set("custom_toolbar_size", "100"); + if (get("camera_type").empty()) + set("camera_type", "1"); + // Remove legacy window positions/sizes erase("", "main_frame_maximized"); erase("", "main_frame_pos"); diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index a3ecb5e5410..b8c182ef4a7 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -2,9 +2,8 @@ #include "Camera.hpp" #include "3DScene.hpp" -#if ENABLE_CAMERA_STATISTICS #include "GUI_App.hpp" -#endif // ENABLE_CAMERA_STATISTICS +#include "AppConfig.hpp" #include @@ -44,23 +43,44 @@ std::string Camera::get_type_as_string() const { switch (m_type) { - default: case Unknown: return "unknown"; case Perspective: return "perspective"; + default: case Ortho: return "orthographic"; }; } +void Camera::set_type(EType type) +{ + if (m_type != type) + { + m_type = type; + + wxGetApp().app_config->set("camera_type", std::to_string(m_type)); + wxGetApp().app_config->save(); + } +} + +void Camera::set_type(const std::string& type) +{ + if (!type.empty() && (type != "1")) + { + unsigned char type_id = atoi(type.c_str()); + if (((unsigned char)Ortho < type_id) && (type_id < (unsigned char)Num_types)) + set_type((Camera::EType)type_id); + } +} + void Camera::select_next_type() { unsigned char next = (unsigned char)m_type + 1; if (next == (unsigned char)Num_types) next = 1; - m_type = (EType)next; + set_type((EType)next); } void Camera::set_target(const Vec3d& target) diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index fe6571b0563..a64b194f3a9 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -16,8 +16,8 @@ struct Camera enum EType : unsigned char { Unknown, - Perspective, Ortho, + Perspective, Num_types }; @@ -45,7 +45,8 @@ public: EType get_type() const { return m_type; } std::string get_type_as_string() const; - void set_type(EType type) { m_type = type; } + void set_type(EType type); + void set_type(const std::string& type); void select_next_type(); const Vec3d& get_target() const { return m_target; } @@ -56,6 +57,9 @@ public: double get_zoom() const { return m_zoom; } void set_zoom(double zoom, const BoundingBoxf3& max_box, int canvas_w, int canvas_h); +#if ENABLE_RETINA_GL + void set_zoom(double zoom) { m_zoom = zoom; } +#endif // ENABLE_RETINA_GL const BoundingBoxf3& get_scene_box() const { return m_scene_box; } void set_scene_box(const BoundingBoxf3& box) { m_scene_box = box; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9216eff944a..d9a8a870cee 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1593,8 +1593,8 @@ void GLCanvas3D::render() if (m_camera.requires_zoom_to_bed) { zoom_to_bed(); -// const Size& cnv_size = get_canvas_size(); -// _resize((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); + const Size& cnv_size = get_canvas_size(); + _resize((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); m_camera.requires_zoom_to_bed = false; } @@ -3304,8 +3304,7 @@ void GLCanvas3D::update_ui_from_settings() if (new_scaling != orig_scaling) { BOOST_LOG_TRIVIAL(debug) << "GLCanvas3D: Scaling factor: " << new_scaling; - m_camera.zoom /= orig_scaling; - m_camera.zoom *= new_scaling; + m_camera.set_zoom(m_camera.get_zoom() * new_scaling / orig_scaling); _refresh_if_shown_on_screen(); } #endif diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f8385c0b586..c2456db800b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1772,6 +1772,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) q->Layout(); set_current_panel(view3D); + + // updates camera type from .ini file + camera.set_type(get_config("camera_type")); } void Plater::priv::update(bool force_full_scene_refresh) From 90ffd289cb54cd00add641223bde55183d99b49f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 20 Jun 2019 11:05:05 +0200 Subject: [PATCH 22/37] Fixed build on MacOS --- src/slic3r/GUI/Camera.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index a64b194f3a9..6a2f65a30ee 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -57,9 +57,9 @@ public: double get_zoom() const { return m_zoom; } void set_zoom(double zoom, const BoundingBoxf3& max_box, int canvas_w, int canvas_h); -#if ENABLE_RETINA_GL + // this method does not check if the given zoom is valid, use instead the other set_zoom() method + // called only by: void GLCanvas3D::update_ui_from_settings() void set_zoom(double zoom) { m_zoom = zoom; } -#endif // ENABLE_RETINA_GL const BoundingBoxf3& get_scene_box() const { return m_scene_box; } void set_scene_box(const BoundingBoxf3& box) { m_scene_box = box; } From a997a0180306a1cfb4ebe9a6605c9a409a9fbe1b Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 7 Jun 2019 17:01:19 +0200 Subject: [PATCH 23/37] Firmware updater: Prevent empty flashing jobs --- src/slic3r/GUI/FirmwareDialog.cpp | 57 ++++++++++++++++++++++------ src/slic3r/GUI/ProgressStatusBar.hpp | 1 + src/slic3r/Utils/Serial.hpp | 3 ++ 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp index b400e27eaec..9e209faedd2 100644 --- a/src/slic3r/GUI/FirmwareDialog.cpp +++ b/src/slic3r/GUI/FirmwareDialog.cpp @@ -5,11 +5,14 @@ #include #include #include -#include -#include +#include #include #include +#if _WIN32 + #include +#endif + #include "libslic3r/Utils.hpp" #include "avrdude/avrdude-slic3r.hpp" #include "GUI.hpp" @@ -159,6 +162,7 @@ struct FirmwareDialog::priv void flashing_start(unsigned tasks); void flashing_done(AvrDudeComplete complete); void enable_port_picker(bool enable); + void update_flash_enabled(); void load_hex_file(const wxString &path); void queue_event(AvrdudeEvent aevt, wxString message); @@ -171,6 +175,7 @@ struct FirmwareDialog::priv void prepare_mk2(); void prepare_mk3(); void prepare_avr109(Avr109Pid usb_pid); + bool get_serial_port(); void perform_upload(); void user_cancel(); @@ -286,6 +291,14 @@ void FirmwareDialog::priv::enable_port_picker(bool enable) fit_no_shrink(); } +void FirmwareDialog::priv::update_flash_enabled() +{ + const bool hex_exists = wxFileExists(hex_picker->GetPath()); + const bool port_valid = get_serial_port(); + + btn_flash->Enable(hex_exists && port_valid); +} + void FirmwareDialog::priv::load_hex_file(const wxString &path) { hex_file = HexFile(path.wx_str()); @@ -553,6 +566,31 @@ void FirmwareDialog::priv::prepare_avr109(Avr109Pid usb_pid) } +bool FirmwareDialog::priv::get_serial_port() +{ + const int selection = port_picker->GetSelection(); + if (selection != wxNOT_FOUND) { + port = this->ports[selection]; + } else { + // User has supplied a custom filename + + std::string path_u8 = GUI::into_u8(port_picker->GetValue()); +#ifdef _WIN32 + static const std::regex com_pattern("COM[0-9]+", std::regex::icase); + std::smatch matches; + if (std::regex_match(path_u8, matches, com_pattern)) { +#else + if (fs::is_other(fs::path(path_u8))) { +#endif + port = SerialPortInfo(std::move(path_u8)); + } else { + port = boost::none; + } + } + + return !!port; +} + void FirmwareDialog::priv::perform_upload() { auto filename = hex_picker->GetPath(); @@ -560,14 +598,8 @@ void FirmwareDialog::priv::perform_upload() load_hex_file(filename); // Might already be loaded, but we want to make sure it's fresh - int selection = port_picker->GetSelection(); - if (selection != wxNOT_FOUND) { - port = this->ports[selection]; - - // Verify whether the combo box list selection equals to the combo box edit value. - if (wxString::FromUTF8(port->friendly_name.data()) != port_picker->GetValue()) { - return; - } + if (! get_serial_port()) { + return; } const bool extra_verbose = false; // For debugging @@ -836,10 +868,13 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : p->hex_picker->Bind(wxEVT_FILEPICKER_CHANGED, [this](wxFileDirPickerEvent& evt) { if (wxFileExists(evt.GetPath())) { this->p->load_hex_file(evt.GetPath()); - this->p->btn_flash->Enable(); } + p->update_flash_enabled(); }); + p->port_picker->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &) { p->update_flash_enabled(); }); + p->port_picker->Bind(wxEVT_TEXT, [this](wxCommandEvent &) { p->update_flash_enabled(); }); + p->spoiler->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, [=](wxCollapsiblePaneEvent &evt) { if (evt.GetCollapsed()) { this->SetMinSize(wxSize(p->min_width, p->min_height)); diff --git a/src/slic3r/GUI/ProgressStatusBar.hpp b/src/slic3r/GUI/ProgressStatusBar.hpp index 7d624af90bd..413c6ffee54 100644 --- a/src/slic3r/GUI/ProgressStatusBar.hpp +++ b/src/slic3r/GUI/ProgressStatusBar.hpp @@ -2,6 +2,7 @@ #define PROGRESSSTATUSBAR_HPP #include +#include #include #include diff --git a/src/slic3r/Utils/Serial.hpp b/src/slic3r/Utils/Serial.hpp index e4a28de09d3..67d64b4ec12 100644 --- a/src/slic3r/Utils/Serial.hpp +++ b/src/slic3r/Utils/Serial.hpp @@ -17,6 +17,9 @@ struct SerialPortInfo { std::string friendly_name; bool is_printer = false; + SerialPortInfo() {} + SerialPortInfo(std::string port) : port(port), friendly_name(std::move(port)) {} + bool id_match(unsigned id_vendor, unsigned id_product) const { return id_vendor == this->id_vendor && id_product == this->id_product; } }; From 96ebd8c90c0b912578ecc06a6a2f9ad8e9436f46 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 11 Jun 2019 12:44:12 +0200 Subject: [PATCH 24/37] Firmware updater: Fix MMU flashing in GUI --- src/slic3r/GUI/FirmwareDialog.cpp | 34 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/slic3r/GUI/FirmwareDialog.cpp b/src/slic3r/GUI/FirmwareDialog.cpp index 9e209faedd2..15a09aa7160 100644 --- a/src/slic3r/GUI/FirmwareDialog.cpp +++ b/src/slic3r/GUI/FirmwareDialog.cpp @@ -107,7 +107,7 @@ struct FirmwareDialog::priv // GUI elements wxComboBox *port_picker; - wxStaticText *port_autodetect; + wxStaticText *txt_port_autodetect; wxFilePickerCtrl *hex_picker; wxStaticText *txt_status; wxGauge *progressbar; @@ -134,6 +134,7 @@ struct FirmwareDialog::priv // Data std::vector ports; optional port; + bool port_autodetect; HexFile hex_file; // This is a shared pointer holding the background AvrDude task @@ -150,6 +151,7 @@ struct FirmwareDialog::priv btn_flash_label_flashing(_(L("Cancel"))), label_status_flashing(_(L("Flashing in progress. Please do not disconnect the printer!"))), timer_pulse(q), + port_autodetect(false), progress_tasks_done(0), progress_tasks_bar(0), user_cancelled(false), @@ -161,7 +163,7 @@ struct FirmwareDialog::priv void set_txt_status(const wxString &label); void flashing_start(unsigned tasks); void flashing_done(AvrDudeComplete complete); - void enable_port_picker(bool enable); + void set_autodetect(bool autodetect); void update_flash_enabled(); void load_hex_file(const wxString &path); void queue_event(AvrdudeEvent aevt, wxString message); @@ -216,8 +218,10 @@ void FirmwareDialog::priv::find_serial_ports() idx = i; break; } - if (idx != -1) + if (idx != -1) { port_picker->SetSelection(idx); + update_flash_enabled(); + } } } } @@ -282,11 +286,13 @@ void FirmwareDialog::priv::flashing_done(AvrDudeComplete complete) } } -void FirmwareDialog::priv::enable_port_picker(bool enable) +void FirmwareDialog::priv::set_autodetect(bool autodetect) { - port_picker->Show(enable); - btn_rescan->Show(enable); - port_autodetect->Show(! enable); + port_autodetect = autodetect; + + port_picker->Show(!autodetect); + btn_rescan->Show(!autodetect); + txt_port_autodetect->Show(autodetect); q->Layout(); fit_no_shrink(); } @@ -294,7 +300,7 @@ void FirmwareDialog::priv::enable_port_picker(bool enable) void FirmwareDialog::priv::update_flash_enabled() { const bool hex_exists = wxFileExists(hex_picker->GetPath()); - const bool port_valid = get_serial_port(); + const bool port_valid = port_autodetect || get_serial_port(); btn_flash->Enable(hex_exists && port_valid); } @@ -302,8 +308,8 @@ void FirmwareDialog::priv::update_flash_enabled() void FirmwareDialog::priv::load_hex_file(const wxString &path) { hex_file = HexFile(path.wx_str()); - const bool auto_lookup = hex_file.device == HexFile::DEV_MM_CONTROL || hex_file.device == HexFile::DEV_CW1; - enable_port_picker(! auto_lookup); + const bool autodetect = hex_file.device == HexFile::DEV_MM_CONTROL || hex_file.device == HexFile::DEV_CW1; + set_autodetect(autodetect); } void FirmwareDialog::priv::queue_event(AvrdudeEvent aevt, wxString message) @@ -598,7 +604,7 @@ void FirmwareDialog::priv::perform_upload() load_hex_file(filename); // Might already be loaded, but we want to make sure it's fresh - if (! get_serial_port()) { + if (!port_autodetect && !get_serial_port()) { return; } @@ -801,13 +807,13 @@ FirmwareDialog::FirmwareDialog(wxWindow *parent) : auto *label_port_picker = new wxStaticText(panel, wxID_ANY, _(L("Serial port:"))); p->port_picker = new wxComboBox(panel, wxID_ANY); - p->port_autodetect = new wxStaticText(panel, wxID_ANY, _(L("Autodetected"))); + p->txt_port_autodetect = new wxStaticText(panel, wxID_ANY, _(L("Autodetected"))); p->btn_rescan = new wxButton(panel, wxID_ANY, _(L("Rescan"))); auto *port_sizer = new wxBoxSizer(wxHORIZONTAL); port_sizer->Add(p->port_picker, 1, wxEXPAND | wxRIGHT, SPACING); port_sizer->Add(p->btn_rescan, 0); - port_sizer->Add(p->port_autodetect, 1, wxEXPAND); - p->enable_port_picker(true); + port_sizer->Add(p->txt_port_autodetect, 1, wxEXPAND); + p->set_autodetect(false); auto *label_progress = new wxStaticText(panel, wxID_ANY, _(L("Progress:"))); p->progressbar = new wxGauge(panel, wxID_ANY, 1, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL | wxGA_SMOOTH); From b233222d5a0307f4ff8a2ee51b9d35ebb5d9fad2 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 3 Jun 2019 11:31:32 +0200 Subject: [PATCH 25/37] Updating: Index installation Prevents cancelled updates from popping up repeatedly on each application startup --- src/slic3r/Config/Version.cpp | 1 + src/slic3r/Config/Version.hpp | 4 ++ src/slic3r/GUI/GUI_App.cpp | 6 +-- src/slic3r/Utils/PresetUpdater.cpp | 86 ++++++++++++++++++------------ src/slic3r/Utils/Semver.hpp | 5 ++ 5 files changed, 65 insertions(+), 37 deletions(-) diff --git a/src/slic3r/Config/Version.cpp b/src/slic3r/Config/Version.cpp index fe3adfd7f14..865884c6fee 100644 --- a/src/slic3r/Config/Version.cpp +++ b/src/slic3r/Config/Version.cpp @@ -192,6 +192,7 @@ size_t Index::load(const boost::filesystem::path &path) { m_configs.clear(); m_vendor = path.stem().string(); + m_path = path; boost::nowide::ifstream ifs(path.string()); std::string line; diff --git a/src/slic3r/Config/Version.hpp b/src/slic3r/Config/Version.hpp index e689286af81..560bc29c217 100644 --- a/src/slic3r/Config/Version.hpp +++ b/src/slic3r/Config/Version.hpp @@ -72,6 +72,9 @@ public: // if the index is valid. const_iterator recommended() const; + // Returns the filesystem path from which this index has originally been loaded + const boost::filesystem::path& path() const { return m_path; } + // Load all vendor specific indices. // Throws Slic3r::file_parser_error and the standard std file access exceptions. static std::vector load_db(); @@ -79,6 +82,7 @@ public: private: std::string m_vendor; std::vector m_configs; + boost::filesystem::path m_path; }; } // namespace Config diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 3aada45f39a..4f1c3adc8bf 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -265,10 +265,8 @@ bool GUI_App::on_init_inner() } CallAfter([this] { - if (!config_wizard_startup(app_conf_exists)) { - // Only notify if there was no wizard so as not to bother too much ... - preset_updater->slic3r_update_notify(); - } + config_wizard_startup(app_conf_exists); + preset_updater->slic3r_update_notify(); preset_updater->sync(preset_bundle); }); } diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index f34cd8db197..8c3ced31a29 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -45,10 +46,25 @@ static const char *INDEX_FILENAME = "index.idx"; static const char *TMP_EXTENSION = ".download"; +void copy_file_fix(const fs::path &source, const fs::path &target) +{ + static const auto perms = fs::owner_read | fs::owner_write | fs::group_read | fs::others_read; // aka 644 + + BOOST_LOG_TRIVIAL(debug) << boost::format("PresetUpdater: Copying %1% -> %2%") % source % target; + + // Make sure the file has correct permission both before and after we copy over it + if (fs::exists(target)) { + fs::permissions(target, perms); + } + fs::copy_file(source, target, fs::copy_option::overwrite_if_exists); + fs::permissions(target, perms); +} + struct Update { fs::path source; fs::path target; + Version version; std::string vendor; std::string changelog_url; @@ -61,7 +77,13 @@ struct Update , changelog_url(std::move(changelog_url)) {} - friend std::ostream& operator<<(std::ostream& os , const Update &self) { + void install() const + { + copy_file_fix(source, target); + } + + friend std::ostream& operator<<(std::ostream& os, const Update &self) + { os << "Update(" << self.source.string() << " -> " << self.target.string() << ')'; return os; } @@ -115,7 +137,6 @@ struct PresetUpdater::priv bool enabled_version_check; bool enabled_config_update; std::string version_check_url; - bool had_config_update; fs::path cache_path; fs::path rsrc_path; @@ -135,13 +156,10 @@ struct PresetUpdater::priv void check_install_indices() const; Updates get_config_updates() const; void perform_updates(Updates &&updates, bool snapshot = true) const; - - static void copy_file(const fs::path &from, const fs::path &to); }; PresetUpdater::priv::priv() : ver_slic3r(get_slic3r_version()) - , had_config_update(false) , cache_path(fs::path(Slic3r::data_dir()) / "cache") , rsrc_path(fs::path(resources_dir()) / "profiles") , vendor_path(fs::path(Slic3r::data_dir()) / "vendor") @@ -273,7 +291,7 @@ void PresetUpdater::priv::sync_config(const std::set vendors) try { new_index.load(idx_path_temp); } catch (const std::exception & /* err */) { - BOOST_LOG_TRIVIAL(error) << boost::format("Failed loading a downloaded index %1% for vendor %2%: invalid index?") % idx_path_temp % vendor.name; + BOOST_LOG_TRIVIAL(error) << boost::format("Could not load downloaded index %1% for vendor %2%: invalid index?") % idx_path_temp % vendor.name; continue; } if (new_index.version() < index.version()) { @@ -323,7 +341,7 @@ void PresetUpdater::priv::check_install_indices() const if (! fs::exists(path_in_cache)) { BOOST_LOG_TRIVIAL(info) << "Install index from resources: " << path.filename(); - copy_file(path, path_in_cache); + copy_file_fix(path, path_in_cache); } else { Index idx_rsrc, idx_cache; idx_rsrc.load(path); @@ -331,7 +349,7 @@ void PresetUpdater::priv::check_install_indices() const if (idx_cache.version() < idx_rsrc.version()) { BOOST_LOG_TRIVIAL(info) << "Update index from resources: " << path.filename(); - copy_file(path, path_in_cache); + copy_file_fix(path, path_in_cache); } } } @@ -346,6 +364,7 @@ Updates PresetUpdater::priv::get_config_updates() const for (const auto idx : index_db) { auto bundle_path = vendor_path / (idx.vendor() + ".ini"); + auto bundle_path_idx = vendor_path / idx.path().filename(); if (! fs::exists(bundle_path)) { BOOST_LOG_TRIVIAL(info) << "Bundle not present for index, skipping: " << idx.vendor(); @@ -360,8 +379,31 @@ Updates PresetUpdater::priv::get_config_updates() const const auto recommended = idx.recommended(); if (recommended == idx.end()) { BOOST_LOG_TRIVIAL(error) << boost::format("No recommended version for vendor: %1%, invalid index?") % idx.vendor(); + // XXX: what should be done here? + continue; } + // Load 'installed' idx, if any. + // 'Installed' indices are kept alongside the bundle in the `vendor` subdir + // for bookkeeping to remember a cancelled update and not offer it again. + if (fs::exists(bundle_path_idx)) { + Index existing_idx; + try { + existing_idx.load(bundle_path_idx); + + const auto existing_recommended = existing_idx.recommended(); + if (existing_recommended != existing_idx.end() && recommended->config_version == existing_recommended->config_version) { + // The user has already seen (and presumably rejected) this update + BOOST_LOG_TRIVIAL(info) << boost::format("Downloaded index for `%1%` is the same as installed one, not offering an update.") % idx.vendor(); + continue; + } + } catch (const std::exception & /* err */) { + BOOST_LOG_TRIVIAL(error) << boost::format("Could nto load installed index %1%") % bundle_path_idx; + } + } + + copy_file_fix(idx.path(), bundle_path_idx); + const auto ver_current = idx.find(vp.config_version); const bool ver_current_found = ver_current != idx.end(); if (! ver_current_found) { @@ -453,10 +495,10 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons for (const auto &update : updates.updates) { BOOST_LOG_TRIVIAL(info) << '\t' << update; - copy_file(update.source, update.target); + update.install(); PresetBundle bundle; - bundle.load_configbundle(update.target.string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); + bundle.load_configbundle(update.source.string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); BOOST_LOG_TRIVIAL(info) << boost::format("Deleting %1% conflicting presets") % (bundle.prints.size() + bundle.filaments.size() + bundle.printers.size()); @@ -491,19 +533,6 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons } } -void PresetUpdater::priv::copy_file(const fs::path &source, const fs::path &target) -{ - static const auto perms = fs::owner_read | fs::owner_write | fs::group_read | fs::others_read; // aka 644 - - // Make sure the file has correct permission both before and after we copy over it - if (fs::exists(target)) { - fs::permissions(target, perms); - } - fs::copy_file(source, target, fs::copy_option::overwrite_if_exists); - fs::permissions(target, perms); -} - - PresetUpdater::PresetUpdater() : p(new priv()) {} @@ -542,11 +571,6 @@ void PresetUpdater::slic3r_update_notify() { if (! p->enabled_version_check) { return; } - if (p->had_config_update) { - BOOST_LOG_TRIVIAL(info) << "New Slic3r version available, but there was a configuration update, notification won't be displayed"; - return; - } - auto* app_config = GUI::wxGetApp().app_config; const auto ver_online_str = app_config->get("version_online"); const auto ver_online = Semver::parse(ver_online_str); @@ -594,8 +618,6 @@ PresetUpdater::UpdateResult PresetUpdater::config_update() const incompats_map.emplace(std::make_pair(incompat.vendor, std::move(restrictions))); } - p->had_config_update = true; // This needs to be done before a dialog is shown because of OnIdle() + CallAfter() in Perl - GUI::MsgDataIncompatible dlg(std::move(incompats_map)); const auto res = dlg.ShowModal(); if (res == wxID_REPLACE) { @@ -620,8 +642,6 @@ PresetUpdater::UpdateResult PresetUpdater::config_update() const updates_msg.emplace_back(update.vendor, update.version.config_version, update.version.comment, std::move(changelog_url)); } - p->had_config_update = true; // Ditto, see above - GUI::MsgUpdateConfig dlg(updates_msg); const auto res = dlg.ShowModal(); @@ -631,7 +651,7 @@ PresetUpdater::UpdateResult PresetUpdater::config_update() const // Reload global configuration auto *app_config = GUI::wxGetApp().app_config; - GUI::wxGetApp().preset_bundle->load_presets(*app_config); + GUI::wxGetApp().preset_bundle->load_presets(*app_config); GUI::wxGetApp().load_current_presets(); return R_UPDATE_INSTALLED; } else { diff --git a/src/slic3r/Utils/Semver.hpp b/src/slic3r/Utils/Semver.hpp index 2fb4e3f4bfb..a755becaa5a 100644 --- a/src/slic3r/Utils/Semver.hpp +++ b/src/slic3r/Utils/Semver.hpp @@ -137,6 +137,11 @@ public: Semver operator-(const Minor &b) const { Semver res(*this); return res -= b; } Semver operator-(const Patch &b) const { Semver res(*this); return res -= b; } + // Stream output + friend std::ostream& operator<<(std::ostream& os, const Semver &self) { + os << self.to_string(); + return os; + } private: semver_t ver; From 9ec4fdb682d4ee4664fb2ca9181ed3d9b2b4dc7c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 24 Jun 2019 09:27:19 +0200 Subject: [PATCH 26/37] ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION set as default --- src/libslic3r/Technologies.hpp | 3 - src/slic3r/GUI/3DBed.cpp | 16 ------ src/slic3r/GUI/3DScene.cpp | 4 -- src/slic3r/GUI/GLCanvas3D.cpp | 2 - src/slic3r/GUI/GLCanvas3DManager.cpp | 85 ---------------------------- src/slic3r/GUI/GLCanvas3DManager.hpp | 28 --------- 6 files changed, 138 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index d7e5aed768e..657dab95f82 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -49,7 +49,4 @@ // Enable saving textures on GPU in compressed format #define ENABLE_COMPRESSED_TEXTURES 1 -// Enable texture max size to be dependent on detected OpenGL version -#define ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION 1 - #endif // _technologies_h_ diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 04ab4e2da2f..d63e054c561 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -546,7 +546,6 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const std::string model_path = resources_dir() + "/models/" + key; -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION #if !ENABLE_COMPRESSED_TEXTURES // use anisotropic filter if graphic card allows GLfloat max_anisotropy = GLCanvas3DManager::get_gl_info().get_max_anisotropy(); @@ -554,21 +553,6 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const // use higher resolution images if graphic card and opengl version allow GLint max_tex_size = GLCanvas3DManager::get_gl_info().get_max_tex_size(); -#else -#if !ENABLE_COMPRESSED_TEXTURES - // use anisotropic filter if graphic card allows - GLfloat max_anisotropy = 0.0f; - if (glewIsSupported("GL_EXT_texture_filter_anisotropic")) - glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy)); -#endif // !ENABLE_COMPRESSED_TEXTURES - - // use higher resolution images if graphic card allows - GLint max_tex_size; - glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size)); - - // clamp or the texture generation becomes too slow - max_tex_size = std::min(max_tex_size, 8192); -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION std::string filename = tex_path + ".svg"; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 2e30f00cae5..f9a79f2d8c3 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -2015,11 +2015,7 @@ bool GLBed::on_init_from_file(const std::string& filename, bool useVBOs) std::string _3DScene::get_gl_info(bool format_as_html, bool extensions) { -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION return Slic3r::GUI::GLCanvas3DManager::get_gl_info().to_string(format_as_html, extensions); -#else - return s_canvas_mgr.get_gl_info(format_as_html, extensions); -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION } bool _3DScene::add_canvas(wxGLCanvas* canvas, GUI::Bed3D& bed, GUI::Camera& camera, GUI::GLToolbar& view_toolbar) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a71c030967b..973fd1dd94a 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1756,11 +1756,9 @@ void GLCanvas3D::render() ImGui::SameLine(); imgui.text(GLCanvas3DManager::are_compressed_textures_supported() ? "supported" : "not supported"); #endif // ENABLE_COMPRESSED_TEXTURES -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION imgui.text("Max texture size: "); ImGui::SameLine(); imgui.text(std::to_string(GLCanvas3DManager::get_gl_info().get_max_tex_size())); -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION imgui.end(); #endif // ENABLE_RENDER_STATISTICS diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index d213990ba36..a123fcfa7cc 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -15,17 +15,14 @@ #include #include -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION #ifdef __APPLE__ #include "../Utils/MacDarkMode.hpp" #endif // __APPLE__ -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION namespace Slic3r { namespace GUI { GLCanvas3DManager::GLInfo::GLInfo() -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION : m_detected(false) , m_version("") , m_glsl_version("") @@ -33,16 +30,9 @@ GLCanvas3DManager::GLInfo::GLInfo() , m_renderer("") , m_max_tex_size(0) , m_max_anisotropy(0.0f) -#else - : version("") - , glsl_version("") - , vendor("") - , renderer("") -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION { } -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION const std::string& GLCanvas3DManager::GLInfo::get_version() const { if (!m_detected) @@ -123,28 +113,7 @@ void GLCanvas3DManager::GLInfo::detect() const m_detected = true; } -#else -void GLCanvas3DManager::GLInfo::detect() -{ - const char* data = (const char*)::glGetString(GL_VERSION); - if (data != nullptr) - version = data; - data = (const char*)::glGetString(GL_SHADING_LANGUAGE_VERSION); - if (data != nullptr) - glsl_version = data; - - data = (const char*)::glGetString(GL_VENDOR); - if (data != nullptr) - vendor = data; - - data = (const char*)::glGetString(GL_RENDERER); - if (data != nullptr) - renderer = data; -} -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION - -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION bool GLCanvas3DManager::GLInfo::is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const { if (!m_detected) @@ -175,42 +144,11 @@ bool GLCanvas3DManager::GLInfo::is_version_greater_or_equal_to(unsigned int majo else return gl_minor >= minor; } -#else -bool GLCanvas3DManager::GLInfo::is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const -{ - std::vector tokens; - boost::split(tokens, version, boost::is_any_of(" "), boost::token_compress_on); - - if (tokens.empty()) - return false; - - std::vector numbers; - boost::split(numbers, tokens[0], boost::is_any_of("."), boost::token_compress_on); - - unsigned int gl_major = 0; - unsigned int gl_minor = 0; - - if (numbers.size() > 0) - gl_major = ::atoi(numbers[0].c_str()); - - if (numbers.size() > 1) - gl_minor = ::atoi(numbers[1].c_str()); - - if (gl_major < major) - return false; - else if (gl_major > major) - return true; - else - return gl_minor >= minor; -} -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool extensions) const { -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION if (!m_detected) detect(); -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION std::stringstream out; @@ -221,17 +159,10 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten std::string line_end = format_as_html ? "
" : "\n"; out << h2_start << "OpenGL installation" << h2_end << line_end; -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION out << b_start << "GL version: " << b_end << (m_version.empty() ? "N/A" : m_version) << line_end; out << b_start << "Vendor: " << b_end << (m_vendor.empty() ? "N/A" : m_vendor) << line_end; out << b_start << "Renderer: " << b_end << (m_renderer.empty() ? "N/A" : m_renderer) << line_end; out << b_start << "GLSL version: " << b_end << (m_glsl_version.empty() ? "N/A" : m_glsl_version) << line_end; -#else - out << b_start << "GL version: " << b_end << (version.empty() ? "N/A" : version) << line_end; - out << b_start << "Vendor: " << b_end << (vendor.empty() ? "N/A" : vendor) << line_end; - out << b_start << "Renderer: " << b_end << (renderer.empty() ? "N/A" : renderer) << line_end; - out << b_start << "GLSL version: " << b_end << (glsl_version.empty() ? "N/A" : glsl_version) << line_end; -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION if (extensions) { @@ -258,9 +189,7 @@ GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas #if ENABLE_COMPRESSED_TEXTURES bool GLCanvas3DManager::s_compressed_textures_supported = false; #endif // ENABLE_COMPRESSED_TEXTURES -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info; -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION GLCanvas3DManager::GLCanvas3DManager() : m_context(nullptr) @@ -340,16 +269,9 @@ void GLCanvas3DManager::init_gl() if (!m_gl_initialized) { glewInit(); -#if !ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION - m_gl_info.detect(); -#endif // !ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION const AppConfig* config = GUI::get_app_config(); m_use_legacy_opengl = (config == nullptr) || (config->get("use_legacy_opengl") == "1"); -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION m_use_VBOs = !m_use_legacy_opengl && s_gl_info.is_version_greater_or_equal_to(2, 0); -#else - m_use_VBOs = !m_use_legacy_opengl && m_gl_info.is_version_greater_or_equal_to(2, 0); -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION m_gl_initialized = true; #if ENABLE_COMPRESSED_TEXTURES if (GLEW_EXT_texture_compression_s3tc) @@ -360,13 +282,6 @@ void GLCanvas3DManager::init_gl() } } -#if !ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION -std::string GLCanvas3DManager::get_gl_info(bool format_as_html, bool extensions) const -{ - return m_gl_info.to_string(format_as_html, extensions); -} -#endif // !ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION - bool GLCanvas3DManager::init(wxGLCanvas* canvas) { CanvasesMap::const_iterator it = do_get_canvas(canvas); diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index 3ad30411c29..e6e12ca5d65 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -29,7 +29,6 @@ struct Camera; class GLCanvas3DManager { -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION public: class GLInfo { @@ -61,26 +60,8 @@ public: private: void detect() const; }; -#else - struct GLInfo - { - std::string version; - std::string glsl_version; - std::string vendor; - std::string renderer; - GLInfo(); - - void detect(); - bool is_version_greater_or_equal_to(unsigned int major, unsigned int minor) const; - - std::string to_string(bool format_as_html, bool extensions) const; - }; -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION - -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION private: -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION enum EMultisampleState : unsigned char { MS_Unknown, @@ -92,11 +73,7 @@ private: CanvasesMap m_canvases; wxGLContext* m_context; -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION static GLInfo s_gl_info; -#else - GLInfo m_gl_info; -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION bool m_gl_initialized; bool m_use_legacy_opengl; bool m_use_VBOs; @@ -116,9 +93,6 @@ public: unsigned int count() const; void init_gl(); -#if !ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION - std::string get_gl_info(bool format_as_html, bool extensions) const; -#endif // !ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION bool init(wxGLCanvas* canvas); @@ -131,9 +105,7 @@ public: static wxGLCanvas* create_wxglcanvas(wxWindow *parent); -#if ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION static const GLInfo& get_gl_info() { return s_gl_info; } -#endif // ENABLE_TEXTURES_MAXSIZE_DEPENDENT_ON_OPENGL_VERSION private: CanvasesMap::iterator do_get_canvas(wxGLCanvas* canvas); From 8e3b785b61e8a2bd16a0d9e034b6957de925872f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 24 Jun 2019 09:38:46 +0200 Subject: [PATCH 27/37] Adaptive perspective camera frustrum --- src/slic3r/GUI/Camera.cpp | 100 +++++++++++++++++++++++++++++----- src/slic3r/GUI/Camera.hpp | 12 +++- src/slic3r/GUI/GLCanvas3D.cpp | 5 +- 3 files changed, 99 insertions(+), 18 deletions(-) diff --git a/src/slic3r/GUI/Camera.cpp b/src/slic3r/GUI/Camera.cpp index b8c182ef4a7..1f8513ac29c 100644 --- a/src/slic3r/GUI/Camera.cpp +++ b/src/slic3r/GUI/Camera.cpp @@ -24,6 +24,8 @@ namespace GUI { const double Camera::DefaultDistance = 1000.0; double Camera::FrustrumMinZSize = 50.0; double Camera::FrustrumZMargin = 10.0; +double Camera::FovMinDeg = 5.0; +double Camera::FovMaxDeg = 75.0; Camera::Camera() : phi(45.0f) @@ -34,6 +36,7 @@ Camera::Camera() , m_theta(45.0f) , m_zoom(1.0) , m_distance(DefaultDistance) + , m_gui_scale(1.0) , m_view_matrix(Transform3d::Identity()) , m_projection_matrix(Transform3d::Identity()) { @@ -148,6 +151,18 @@ bool Camera::select_view(const std::string& direction) return false; } +double Camera::get_fov() const +{ + switch (m_type) + { + case Perspective: + return 2.0 * Geometry::rad2deg(std::atan(1.0 / m_projection_matrix.matrix()(1, 1))); + default: + case Ortho: + return 0.0; + }; +} + void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) const { glsafe(::glViewport(0, 0, w, h)); @@ -174,17 +189,67 @@ void Camera::apply_view_matrix() const void Camera::apply_projection(const BoundingBoxf3& box) const { - m_frustrum_zs = calc_tight_frustrum_zs_around(box); + m_distance = DefaultDistance; + double w = 0.0; + double h = 0.0; - double w = (double)m_viewport[2]; - double h = (double)m_viewport[3]; - - double two_zoom = 2.0 * m_zoom; - if (two_zoom != 0.0) + while (true) { - double inv_two_zoom = 1.0 / two_zoom; - w *= inv_two_zoom; - h *= inv_two_zoom; + m_frustrum_zs = calc_tight_frustrum_zs_around(box); + + w = (double)m_viewport[2]; + h = (double)m_viewport[3]; + + double two_zoom = 2.0 * m_zoom; + if (two_zoom != 0.0) + { + double inv_two_zoom = 1.0 / two_zoom; + w *= inv_two_zoom; + h *= inv_two_zoom; + } + + switch (m_type) + { + default: + case Ortho: + { + m_gui_scale = 1.0; + break; + } + case Perspective: + { + // scale near plane to keep w and h constant on the plane at z = m_distance + double scale = m_frustrum_zs.first / m_distance; + w *= scale; + h *= scale; + m_gui_scale = scale; + break; + } + } + + if (m_type == Perspective) + { + double fov_rad = 2.0 * std::atan(h / m_frustrum_zs.first); + double fov_deg = Geometry::rad2deg(fov_rad); + + // adjust camera distance to keep fov in a limited range + if (fov_deg > FovMaxDeg + 0.001) + { + double new_near_z = h / ::tan(0.5 * Geometry::deg2rad(FovMaxDeg)); + m_distance += (new_near_z - m_frustrum_zs.first); + apply_view_matrix(); + } + else if (fov_deg < FovMinDeg - 0.001) + { + double new_near_z = h / ::tan(0.5 * Geometry::deg2rad(FovMinDeg)); + m_distance += (new_near_z - m_frustrum_zs.first); + apply_view_matrix(); + } + else + break; + } + else + break; } glsafe(::glMatrixMode(GL_PROJECTION)); @@ -231,17 +296,22 @@ void Camera::debug_render() const std::string type = get_type_as_string(); Vec3f position = get_position().cast(); Vec3f target = m_target.cast(); + float distance = (float)get_distance(); Vec3f forward = get_dir_forward().cast(); Vec3f right = get_dir_right().cast(); Vec3f up = get_dir_up().cast(); float nearZ = (float)m_frustrum_zs.first; float farZ = (float)m_frustrum_zs.second; float deltaZ = farZ - nearZ; + float zoom = (float)m_zoom; + float fov = (float)get_fov(); + float gui_scale = (float)get_gui_scale(); ImGui::InputText("Type", const_cast(type.data()), type.length(), ImGuiInputTextFlags_ReadOnly); ImGui::Separator(); ImGui::InputFloat3("Position", position.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); ImGui::InputFloat3("Target", target.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); + ImGui::InputFloat("Distance", &distance, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); ImGui::Separator(); ImGui::InputFloat3("Forward", forward.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); ImGui::InputFloat3("Right", right.data(), "%.6f", ImGuiInputTextFlags_ReadOnly); @@ -250,6 +320,11 @@ void Camera::debug_render() const ImGui::InputFloat("Near Z", &nearZ, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); ImGui::InputFloat("Far Z", &farZ, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); ImGui::InputFloat("Delta Z", &deltaZ, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); + ImGui::Separator(); + ImGui::InputFloat("Zoom", &zoom, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); + ImGui::InputFloat("Fov", &fov, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); + ImGui::Separator(); + ImGui::InputFloat("GUI scale", &gui_scale, 0.0f, 0.0f, "%.6f", ImGuiInputTextFlags_ReadOnly); imgui.end(); } #endif // ENABLE_CAMERA_STATISTICS @@ -273,11 +348,10 @@ std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBo vertices.push_back(bb_max); vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2)); - // set the Z range in eye coordinates (only negative Zs are in front of the camera) + // set the Z range in eye coordinates (negative Zs are in front of the camera) for (const Vec3d& v : vertices) { - // ensure non-negative values - double z = std::max(-(m_view_matrix * v)(2), 0.0); + double z = -(m_view_matrix * v)(2); ret.first = std::min(ret.first, z); ret.second = std::max(ret.second, z); } @@ -295,8 +369,6 @@ std::pair Camera::calc_tight_frustrum_zs_around(const BoundingBo ret.second = mid_z + half_size; } - assert(ret.first > 0.0); - return ret; } diff --git a/src/slic3r/GUI/Camera.hpp b/src/slic3r/GUI/Camera.hpp index 6a2f65a30ee..bd2541ce2f5 100644 --- a/src/slic3r/GUI/Camera.hpp +++ b/src/slic3r/GUI/Camera.hpp @@ -12,6 +12,8 @@ struct Camera static const double DefaultDistance; static double FrustrumMinZSize; static double FrustrumZMargin; + static double FovMinDeg; + static double FovMaxDeg; enum EType : unsigned char { @@ -31,7 +33,8 @@ private: float m_theta; double m_zoom; // Distance between camera position and camera target measured along the camera Z axis - double m_distance; + mutable double m_distance; + mutable double m_gui_scale; mutable std::array m_viewport; mutable Transform3d m_view_matrix; @@ -52,13 +55,14 @@ public: const Vec3d& get_target() const { return m_target; } void set_target(const Vec3d& target); + double get_distance() const { return m_distance; } + double get_gui_scale() const { return m_gui_scale; } + float get_theta() const { return m_theta; } void set_theta(float theta, bool apply_limit); double get_zoom() const { return m_zoom; } void set_zoom(double zoom, const BoundingBoxf3& max_box, int canvas_w, int canvas_h); - // this method does not check if the given zoom is valid, use instead the other set_zoom() method - // called only by: void GLCanvas3D::update_ui_from_settings() void set_zoom(double zoom) { m_zoom = zoom; } const BoundingBoxf3& get_scene_box() const { return m_scene_box; } @@ -79,6 +83,8 @@ public: double get_near_z() const { return m_frustrum_zs.first; } double get_far_z() const { return m_frustrum_zs.second; } + double get_fov() const; + void apply_viewport(int x, int y, unsigned int w, unsigned int h) const; void apply_view_matrix() const; void apply_projection(const BoundingBoxf3& box) const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index d9a8a870cee..2bb284fd4ea 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3902,8 +3902,11 @@ void GLCanvas3D::_render_overlays() const glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glPushMatrix()); glsafe(::glLoadIdentity()); - // ensure the textures are renderered inside the frustrum + // ensure that the textures are renderered inside the frustrum glsafe(::glTranslated(0.0, 0.0, -(m_camera.get_near_z() + 0.5))); + // ensure that the overlay fits the frustrum near z plane + double gui_scale = m_camera.get_gui_scale(); + glsafe(::glScaled(gui_scale, gui_scale, 1.0)); _render_gizmos_overlay(); _render_warning_texture(); From 0af66cfe823a7bd562be3d02d8dc5c096b8defba Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 24 Jun 2019 09:54:58 +0200 Subject: [PATCH 28/37] ENABLE_COMPRESSED_TEXTURES set as default --- src/libslic3r/Technologies.hpp | 3 - src/slic3r/GUI/3DBed.cpp | 76 ---------------------- src/slic3r/GUI/3DBed.hpp | 12 ---- src/slic3r/GUI/GLCanvas3D.cpp | 48 -------------- src/slic3r/GUI/GLCanvas3D.hpp | 12 ---- src/slic3r/GUI/GLCanvas3DManager.cpp | 4 -- src/slic3r/GUI/GLCanvas3DManager.hpp | 4 -- src/slic3r/GUI/GLTexture.cpp | 78 +---------------------- src/slic3r/GUI/GLTexture.hpp | 24 ------- src/slic3r/GUI/GLToolbar.cpp | 8 --- src/slic3r/GUI/Gizmos/GLGizmosManager.cpp | 8 --- src/slic3r/GUI/ImGuiWrapper.cpp | 12 ---- src/slic3r/GUI/ImGuiWrapper.hpp | 4 -- 13 files changed, 2 insertions(+), 291 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 657dab95f82..bffc45cde7e 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -46,7 +46,4 @@ #define ENABLE_SVG_ICONS (1 && ENABLE_1_42_0_ALPHA8 && ENABLE_TEXTURES_FROM_SVG) -// Enable saving textures on GPU in compressed format -#define ENABLE_COMPRESSED_TEXTURES 1 - #endif // _technologies_h_ diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index d63e054c561..6ffcdcbe874 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -9,9 +9,7 @@ #include "GUI_App.hpp" #include "PresetBundle.hpp" #include "Gizmos/GLGizmoBase.hpp" -#if ENABLE_COMPRESSED_TEXTURES #include "GLCanvas3D.hpp" -#endif // ENABLE_COMPRESSED_TEXTURES #include @@ -276,9 +274,7 @@ void Bed3D::Axes::render_axis(double length) const Bed3D::Bed3D() : m_type(Custom) -#if ENABLE_COMPRESSED_TEXTURES , m_requires_canvas_update(false) -#endif // ENABLE_COMPRESSED_TEXTURES #if ENABLE_TEXTURES_FROM_SVG , m_vbo_id(0) #endif // ENABLE_TEXTURES_FROM_SVG @@ -334,18 +330,13 @@ Point Bed3D::point_projection(const Point& point) const } #if ENABLE_TEXTURES_FROM_SVG -#if ENABLE_COMPRESSED_TEXTURES void Bed3D::render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_factor) const -#else -void Bed3D::render(float theta, bool useVBOs, float scale_factor) const -#endif // ENABLE_COMPRESSED_TEXTURES { m_scale_factor = scale_factor; EType type = useVBOs ? m_type : Custom; switch (type) { -#if ENABLE_COMPRESSED_TEXTURES case MK2: { render_prusa(canvas, "mk2", theta > 90.0f); @@ -361,23 +352,6 @@ void Bed3D::render(float theta, bool useVBOs, float scale_factor) const render_prusa(canvas, "sl1", theta > 90.0f); break; } -#else - case MK2: - { - render_prusa("mk2", theta > 90.0f); - break; - } - case MK3: - { - render_prusa("mk3", theta > 90.0f); - break; - } - case SL1: - { - render_prusa("sl1", theta > 90.0f); - break; - } -#endif // ENABLE_COMPRESSED_TEXTURES default: case Custom: { @@ -387,11 +361,7 @@ void Bed3D::render(float theta, bool useVBOs, float scale_factor) const } } #else -#if ENABLE_COMPRESSED_TEXTURES void Bed3D::render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_factor) const -#else -void Bed3D::render(float theta, bool useVBOs, float scale_factor) const -#endif // ENABLE_COMPRESSED_TEXTURES { m_scale_factor = scale_factor; @@ -400,7 +370,6 @@ void Bed3D::render(float theta, bool useVBOs, float scale_factor) const switch (m_type) { -#if ENABLE_COMPRESSED_TEXTURES case MK2: { render_prusa(canvas, "mk2", theta, useVBOs); @@ -416,23 +385,6 @@ void Bed3D::render(float theta, bool useVBOs, float scale_factor) const render_prusa(canvas, "sl1", theta, useVBOs); break; } -#else - case MK2: - { - render_prusa("mk2", theta, useVBOs); - break; - } - case MK3: - { - render_prusa("mk3", theta, useVBOs); - break; - } - case SL1: - { - render_prusa("sl1", theta, useVBOs); - break; - } -#endif // ENABLE_COMPRESSED_TEXTURES default: case Custom: { @@ -536,21 +488,12 @@ Bed3D::EType Bed3D::detect_type(const Pointfs& shape) const } #if ENABLE_TEXTURES_FROM_SVG -#if ENABLE_COMPRESSED_TEXTURES void Bed3D::render_prusa(GLCanvas3D* canvas, const std::string &key, bool bottom) const -#else -void Bed3D::render_prusa(const std::string &key, bool bottom) const -#endif // ENABLE_COMPRESSED_TEXTURES { std::string tex_path = resources_dir() + "/icons/bed/" + key; std::string model_path = resources_dir() + "/models/" + key; -#if !ENABLE_COMPRESSED_TEXTURES - // use anisotropic filter if graphic card allows - GLfloat max_anisotropy = GLCanvas3DManager::get_gl_info().get_max_anisotropy(); -#endif // !ENABLE_COMPRESSED_TEXTURES - // use higher resolution images if graphic card and opengl version allow GLint max_tex_size = GLCanvas3DManager::get_gl_info().get_max_tex_size(); @@ -558,7 +501,6 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const if ((m_texture.get_id() == 0) || (m_texture.get_source() != filename)) { -#if ENABLE_COMPRESSED_TEXTURES // generate a temporary lower resolution texture to show while no main texture levels have been compressed if (!m_temp_texture.load_from_svg_file(filename, false, false, false, max_tex_size / 8)) { @@ -568,24 +510,11 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const // starts generating the main texture, compression will run asynchronously if (!m_texture.load_from_svg_file(filename, true, true, true, max_tex_size)) -#else - if (!m_texture.load_from_svg_file(filename, true, max_tex_size)) -#endif // ENABLE_COMPRESSED_TEXTURES { render_custom(); return; } - -#if !ENABLE_COMPRESSED_TEXTURES - if (max_anisotropy > 0.0f) - { - glsafe(::glBindTexture(GL_TEXTURE_2D, m_texture.get_id())); - glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); - glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); - } -#endif // !ENABLE_COMPRESSED_TEXTURES } -#if ENABLE_COMPRESSED_TEXTURES else if (m_texture.unsent_compressed_data_available()) { // sends to gpu the already available compressed levels of the main texture @@ -604,7 +533,6 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const m_requires_canvas_update = false; } -#endif // ENABLE_COMPRESSED_TEXTURES if (!bottom) { @@ -677,16 +605,12 @@ void Bed3D::render_prusa_shader(bool transparent) const GLint position_id = m_shader.get_attrib_location("v_position"); GLint tex_coords_id = m_shader.get_attrib_location("v_tex_coords"); -#if ENABLE_COMPRESSED_TEXTURES // show the temporary texture while no compressed data is available GLuint tex_id = (GLuint)m_temp_texture.get_id(); if (tex_id == 0) tex_id = (GLuint)m_texture.get_id(); glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id)); -#else - glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_texture.get_id())); -#endif // ENABLE_COMPRESSED_TEXTURES glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); if (position_id != -1) diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 401f1232f30..a10042cccf9 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -13,9 +13,7 @@ typedef class GLUquadric GLUquadricObj; namespace Slic3r { namespace GUI { -#if ENABLE_COMPRESSED_TEXTURES class GLCanvas3D; -#endif // ENABLE_COMPRESSED_TEXTURES class GeometryBuffer { @@ -95,12 +93,10 @@ private: GeometryBuffer m_gridlines; #if ENABLE_TEXTURES_FROM_SVG mutable GLTexture m_texture; -#if ENABLE_COMPRESSED_TEXTURES // temporary texture shown until the main texture has still no levels compressed mutable GLTexture m_temp_texture; // used to trigger 3D scene update once all compressed textures have been sent to GPU mutable bool m_requires_canvas_update; -#endif // ENABLE_COMPRESSED_TEXTURES mutable Shader m_shader; mutable unsigned int m_vbo_id; #else @@ -131,11 +127,7 @@ public: bool contains(const Point& point) const; Point point_projection(const Point& point) const; -#if ENABLE_COMPRESSED_TEXTURES void render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_factor) const; -#else - void render(float theta, bool useVBOs, float scale_factor) const; -#endif // ENABLE_COMPRESSED_TEXTURES void render_axes() const; private: @@ -144,11 +136,7 @@ private: void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); EType detect_type(const Pointfs& shape) const; #if ENABLE_TEXTURES_FROM_SVG -#if ENABLE_COMPRESSED_TEXTURES void render_prusa(GLCanvas3D* canvas, const std::string& key, bool bottom) const; -#else - void render_prusa(const std::string& key, bool bottom) const; -#endif // ENABLE_COMPRESSED_TEXTURES void render_prusa_shader(bool transparent) const; #else void render_prusa(const std::string &key, float theta, bool useVBOs) const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 973fd1dd94a..c8559cb5d45 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -401,11 +401,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 ENABLE_COMPRESSED_TEXTURES if (!m_tooltip_texture.load_from_file(filename, false, true)) -#else - if (!m_tooltip_texture.load_from_file(filename, false)) -#endif // ENABLE_COMPRESSED_TEXTURES return; } @@ -437,11 +433,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 ENABLE_COMPRESSED_TEXTURES if (!m_reset_texture.load_from_file(filename, false, true)) -#else - if (!m_reset_texture.load_from_file(filename, false)) -#endif // ENABLE_COMPRESSED_TEXTURES return; } @@ -736,11 +728,7 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool } } -#if ENABLE_COMPRESSED_TEXTURES generate(text, canvas, true, red_colored); // GUI::GLTexture::reset() is called at the beginning of generate(...) -#else - _generate(text, canvas, red_colored); // GUI::GLTexture::reset() is called at the beginning of generate(...) -#endif // ENABLE_COMPRESSED_TEXTURES // save information for rescaling m_msg_text = text; @@ -801,11 +789,7 @@ static void msw_disable_cleartype(wxFont &font) } #endif /* __WXMSW__ */ -#if ENABLE_COMPRESSED_TEXTURES bool GLCanvas3D::WarningTexture::generate(const std::string& msg_utf8, const GLCanvas3D& canvas, bool compress, bool red_colored/* = false*/) -#else -bool GLCanvas3D::WarningTexture::_generate(const std::string& msg_utf8, const GLCanvas3D& canvas, const bool red_colored/* = false*/) -#endif // ENABLE_COMPRESSED_TEXTURES { reset(); @@ -879,14 +863,10 @@ bool GLCanvas3D::WarningTexture::_generate(const std::string& msg_utf8, const GL glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); glsafe(::glGenTextures(1, &m_id)); glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id)); -#if ENABLE_COMPRESSED_TEXTURES if (compress && GLEW_EXT_texture_compression_s3tc) glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); else glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); -#else - glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); -#endif // ENABLE_COMPRESSED_TEXTURES glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); @@ -937,11 +917,7 @@ void GLCanvas3D::WarningTexture::msw_rescale(const GLCanvas3D& canvas) if (m_msg_text.empty()) return; -#if ENABLE_COMPRESSED_TEXTURES generate(m_msg_text, canvas, true, m_is_colored_red); -#else - _generate(m_msg_text, canvas, m_is_colored_red); -#endif // ENABLE_COMPRESSED_TEXTURES } const unsigned char GLCanvas3D::LegendTexture::Squares_Border_Color[3] = { 64, 64, 64 }; @@ -984,11 +960,7 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_values(const GCodePrevie } } -#if ENABLE_COMPRESSED_TEXTURES bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector& tool_colors, const GLCanvas3D& canvas, bool compress) -#else -bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, const std::vector& tool_colors, const GLCanvas3D& canvas) -#endif // ENABLE_COMPRESSED_TEXTURES { reset(); @@ -1177,14 +1149,10 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); glsafe(::glGenTextures(1, &m_id)); glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_id)); -#if ENABLE_COMPRESSED_TEXTURES if (compress && GLEW_EXT_texture_compression_s3tc) glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); else glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); -#else - glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); -#endif // ENABLE_COMPRESSED_TEXTURES glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); @@ -1267,9 +1235,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar #endif // ENABLE_SVG_ICONS , m_use_clipping_planes(false) , m_sidebar_field("") -#if ENABLE_COMPRESSED_TEXTURES , m_keep_dirty(false) -#endif // ENABLE_COMPRESSED_TEXTURES , m_config(nullptr) , m_process(nullptr) , m_model(nullptr) @@ -1487,10 +1453,8 @@ void GLCanvas3D::bed_shape_changed() m_camera.set_scene_box(scene_bounding_box()); m_camera.requires_zoom_to_bed = true; m_dirty = true; -#if ENABLE_COMPRESSED_TEXTURES if (m_bed.is_prusa()) start_keeping_dirty(); -#endif // ENABLE_COMPRESSED_TEXTURES } void GLCanvas3D::set_color_by(const std::string& value) @@ -1750,12 +1714,10 @@ void GLCanvas3D::render() imgui.text(std::to_string(m_render_stats.last_frame)); ImGui::SameLine(); imgui.text(" ms"); -#if ENABLE_COMPRESSED_TEXTURES ImGui::Separator(); imgui.text("Compressed textures: "); ImGui::SameLine(); imgui.text(GLCanvas3DManager::are_compressed_textures_supported() ? "supported" : "not supported"); -#endif // ENABLE_COMPRESSED_TEXTURES imgui.text("Max texture size: "); ImGui::SameLine(); imgui.text(std::to_string(GLCanvas3DManager::get_gl_info().get_max_tex_size())); @@ -2366,10 +2328,8 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt) _refresh_if_shown_on_screen(); -#if ENABLE_COMPRESSED_TEXTURES if (m_keep_dirty) m_dirty = true; -#endif // ENABLE_COMPRESSED_TEXTURES } void GLCanvas3D::on_char(wxKeyEvent& evt) @@ -4002,11 +3962,7 @@ void GLCanvas3D::_render_bed(float theta) const #if ENABLE_RETINA_GL scale_factor = m_retina_helper->get_scale_factor(); #endif // ENABLE_RETINA_GL -#if ENABLE_COMPRESSED_TEXTURES m_bed.render(const_cast(this), theta, m_use_VBOs, scale_factor); -#else - m_bed.render(theta, m_use_VBOs, scale_factor); -#endif // ENABLE_COMPRESSED_TEXTURES } void GLCanvas3D::_render_axes() const @@ -5762,11 +5718,7 @@ std::vector GLCanvas3D::_parse_colors(const std::vector& col void GLCanvas3D::_generate_legend_texture(const GCodePreviewData& preview_data, const std::vector& tool_colors) { -#if ENABLE_COMPRESSED_TEXTURES m_legend_texture.generate(preview_data, tool_colors, *this, true); -#else - m_legend_texture.generate(preview_data, tool_colors, *this); -#endif // ENABLE_COMPRESSED_TEXTURES } void GLCanvas3D::_set_warning_texture(WarningTexture::Warning warning, bool state) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 4b97124afb9..9520fae0e03 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -376,11 +376,7 @@ class GLCanvas3D std::vector m_warnings; // Generates the texture with given text. -#if ENABLE_COMPRESSED_TEXTURES bool generate(const std::string& msg, const GLCanvas3D& canvas, bool compress, bool red_colored = false); -#else - bool _generate(const std::string& msg, const GLCanvas3D& canvas, const bool red_colored = false); -#endif // ENABLE_COMPRESSED_TEXTURES }; class LegendTexture : public GUI::GLTexture @@ -403,11 +399,7 @@ class GLCanvas3D void fill_color_print_legend_values(const GCodePreviewData& preview_data, const GLCanvas3D& canvas, std::vector>& cp_legend_values); -#if ENABLE_COMPRESSED_TEXTURES bool generate(const GCodePreviewData& preview_data, const std::vector& tool_colors, const GLCanvas3D& canvas, bool compress); -#else - bool generate(const GCodePreviewData& preview_data, const std::vector& tool_colors, const GLCanvas3D& canvas); -#endif // ENABLE_COMPRESSED_TEXTURES void render(const GLCanvas3D& canvas) const; }; @@ -451,9 +443,7 @@ private: bool m_use_clipping_planes; mutable SlaCap m_sla_caps[2]; std::string m_sidebar_field; -#if ENABLE_COMPRESSED_TEXTURES bool m_keep_dirty; -#endif // ENABLE_COMPRESSED_TEXTURES mutable GLVolumeCollection m_volumes; Selection m_selection; @@ -640,10 +630,8 @@ public: void set_cursor(ECursorType type); void msw_rescale(); -#if ENABLE_COMPRESSED_TEXTURES void start_keeping_dirty() { m_keep_dirty = true; } void stop_keeping_dirty() { m_keep_dirty = false; } -#endif // ENABLE_COMPRESSED_TEXTURES private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index a123fcfa7cc..4f64b4e8772 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -186,9 +186,7 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten } GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown; -#if ENABLE_COMPRESSED_TEXTURES bool GLCanvas3DManager::s_compressed_textures_supported = false; -#endif // ENABLE_COMPRESSED_TEXTURES GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info; GLCanvas3DManager::GLCanvas3DManager() @@ -273,12 +271,10 @@ void GLCanvas3DManager::init_gl() m_use_legacy_opengl = (config == nullptr) || (config->get("use_legacy_opengl") == "1"); m_use_VBOs = !m_use_legacy_opengl && s_gl_info.is_version_greater_or_equal_to(2, 0); m_gl_initialized = true; -#if ENABLE_COMPRESSED_TEXTURES if (GLEW_EXT_texture_compression_s3tc) s_compressed_textures_supported = true; else s_compressed_textures_supported = false; -#endif // ENABLE_COMPRESSED_TEXTURES } } diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index e6e12ca5d65..26c2558d07a 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -78,9 +78,7 @@ private: bool m_use_legacy_opengl; bool m_use_VBOs; static EMultisampleState s_multisample; -#if ENABLE_COMPRESSED_TEXTURES static bool s_compressed_textures_supported; -#endif // ENABLE_COMPRESSED_TEXTURES public: GLCanvas3DManager(); @@ -99,9 +97,7 @@ public: GLCanvas3D* get_canvas(wxGLCanvas* canvas); static bool can_multisample() { return s_multisample == MS_Enabled; } -#if ENABLE_COMPRESSED_TEXTURES static bool are_compressed_textures_supported() { return s_compressed_textures_supported; } -#endif // ENABLE_COMPRESSED_TEXTURES static wxGLCanvas* create_wxglcanvas(wxWindow *parent); diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 9b373440a16..171a5c88518 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -12,12 +12,10 @@ #include #include -#if ENABLE_COMPRESSED_TEXTURES #include #define STB_DXT_IMPLEMENTATION #include "stb_dxt/stb_dxt.h" -#endif // ENABLE_COMPRESSED_TEXTURES #include "nanosvg/nanosvg.h" #include "nanosvg/nanosvgrast.h" @@ -27,7 +25,6 @@ namespace Slic3r { namespace GUI { -#if ENABLE_COMPRESSED_TEXTURES void GLTexture::Compressor::reset() { // force compression completion, if any @@ -120,7 +117,6 @@ void GLTexture::Compressor::compress() m_is_compressing = false; m_abort_compressing = false; } -#endif // ENABLE_COMPRESSED_TEXTURES GLTexture::Quad_UVs GLTexture::FullTextureUVs = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f } }; @@ -129,9 +125,7 @@ GLTexture::GLTexture() , m_width(0) , m_height(0) , m_source("") -#if ENABLE_COMPRESSED_TEXTURES , m_compressor(*this) -#endif // ENABLE_COMPRESSED_TEXTURES { } @@ -140,11 +134,7 @@ GLTexture::~GLTexture() reset(); } -#if ENABLE_COMPRESSED_TEXTURES bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps, bool compress) -#else -bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps) -#endif // ENABLE_COMPRESSED_TEXTURES { reset(); @@ -152,20 +142,12 @@ bool GLTexture::load_from_file(const std::string& filename, bool use_mipmaps) return false; if (boost::algorithm::iends_with(filename, ".png")) -#if ENABLE_COMPRESSED_TEXTURES return load_from_png(filename, use_mipmaps, compress); -#else - return load_from_png(filename, use_mipmaps); -#endif // ENABLE_COMPRESSED_TEXTURES else return false; } -#if ENABLE_COMPRESSED_TEXTURES bool GLTexture::load_from_svg_file(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px) -#else -bool GLTexture::load_from_svg_file(const std::string& filename, bool use_mipmaps, unsigned int max_size_px) -#endif // ENABLE_COMPRESSED_TEXTURES { reset(); @@ -173,20 +155,12 @@ bool GLTexture::load_from_svg_file(const std::string& filename, bool use_mipmaps return false; if (boost::algorithm::iends_with(filename, ".svg")) -#if ENABLE_COMPRESSED_TEXTURES return load_from_svg(filename, use_mipmaps, compress, apply_anisotropy, max_size_px); -#else - return load_from_svg(filename, use_mipmaps, max_size_px); -#endif // ENABLE_COMPRESSED_TEXTURES else return false; } -#if ENABLE_COMPRESSED_TEXTURES bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector& filenames, const std::vector>& states, unsigned int sprite_size_px, bool compress) -#else -bool GLTexture::load_from_svg_files_as_sprites_array(const std::vector& filenames, const std::vector>& states, unsigned int sprite_size_px) -#endif // ENABLE_COMPRESSED_TEXTURES { reset(); @@ -302,14 +276,10 @@ bool GLTexture::load_from_svg_files_as_sprites_array(const std::vectorwidth); m_height = (int)(scale * image->height); -#if ENABLE_COMPRESSED_TEXTURES if (compression_enabled) { // the stb_dxt compression library seems to like only texture sizes which are a multiple of 4 @@ -553,7 +494,6 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns if (height_rem != 0) m_height += (4 - height_rem); } -#endif // ENABLE_COMPRESSED_TEXTURES int n_pixels = m_width * m_height; @@ -581,7 +521,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); glsafe(::glGenTextures(1, &m_id)); glsafe(::glBindTexture(GL_TEXTURE_2D, m_id)); -#if ENABLE_COMPRESSED_TEXTURES + if (apply_anisotropy) { GLfloat max_anisotropy = GLCanvas3DManager::get_gl_info().get_max_anisotropy(); @@ -598,9 +538,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns } else glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); -#else - glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); -#endif // ENABLE_COMPRESSED_TEXTURES + if (use_mipmaps) { // we manually generate mipmaps because glGenerateMipmap() function is not reliable on all graphics cards @@ -616,12 +554,9 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns lod_h = std::max(lod_h / 2, 1); scale /= 2.0f; -#if ENABLE_COMPRESSED_TEXTURES data.resize(lod_w * lod_h * 4); -#endif // ENABLE_COMPRESSED_TEXTURES nsvgRasterize(rast, image, 0, 0, scale, data.data(), lod_w, lod_h, lod_w * 4); -#if ENABLE_COMPRESSED_TEXTURES if (compression_enabled) { // initializes the texture on GPU @@ -631,20 +566,13 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns } else glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); -#else - glsafe(::glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, (GLsizei)lod_w, (GLsizei)lod_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*)data.data())); -#endif // ENABLE_COMPRESSED_TEXTURES } -#if ENABLE_COMPRESSED_TEXTURES if (!compression_enabled) { -#endif // ENABLE_COMPRESSED_TEXTURES glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)); -#if ENABLE_COMPRESSED_TEXTURES } -#endif // ENABLE_COMPRESSED_TEXTURES } else { @@ -657,11 +585,9 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns m_source = filename; -#if ENABLE_COMPRESSED_TEXTURES if (compression_enabled) // start asynchronous compression m_compressor.start_compressing(); -#endif // ENABLE_COMPRESSED_TEXTURES nsvgDeleteRasterizer(rast); nsvgDelete(image); diff --git a/src/slic3r/GUI/GLTexture.hpp b/src/slic3r/GUI/GLTexture.hpp index 5df6189b6f8..f4dc05a1686 100644 --- a/src/slic3r/GUI/GLTexture.hpp +++ b/src/slic3r/GUI/GLTexture.hpp @@ -11,7 +11,6 @@ namespace GUI { class GLTexture { -#if ENABLE_COMPRESSED_TEXTURES class Compressor { struct Level @@ -47,7 +46,6 @@ namespace GUI { private: void compress(); }; -#endif // ENABLE_COMPRESSED_TEXTURES public: struct UV @@ -71,21 +69,14 @@ namespace GUI { int m_width; int m_height; std::string m_source; -#if ENABLE_COMPRESSED_TEXTURES Compressor m_compressor; -#endif // ENABLE_COMPRESSED_TEXTURES public: GLTexture(); virtual ~GLTexture(); -#if ENABLE_COMPRESSED_TEXTURES bool load_from_file(const std::string& filename, bool use_mipmaps, bool compress); bool load_from_svg_file(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px); -#else - bool load_from_file(const std::string& filename, bool use_mipmaps); - bool load_from_svg_file(const std::string& filename, bool use_mipmaps, unsigned int max_size_px); -#endif // ENABLE_COMPRESSED_TEXTURES // meanings of states: (std::pair) // first field (int): // 0 -> no changes @@ -94,11 +85,7 @@ namespace GUI { // second field (bool): // false -> no changes // true -> add background color -#if ENABLE_COMPRESSED_TEXTURES bool load_from_svg_files_as_sprites_array(const std::vector& filenames, const std::vector>& states, unsigned int sprite_size_px, bool compress); -#else - bool load_from_svg_files_as_sprites_array(const std::vector& filenames, const std::vector>& states, unsigned int sprite_size_px); -#endif // ENABLE_COMPRESSED_TEXTURES void reset(); unsigned int get_id() const { return m_id; } @@ -107,32 +94,21 @@ namespace GUI { const std::string& get_source() const { return m_source; } -#if ENABLE_COMPRESSED_TEXTURES bool unsent_compressed_data_available() const { return m_compressor.unsent_compressed_data_available(); } void send_compressed_data_to_gpu() { m_compressor.send_compressed_data_to_gpu(); } bool all_compressed_data_sent_to_gpu() const { return m_compressor.all_compressed_data_sent_to_gpu(); } -#endif // ENABLE_COMPRESSED_TEXTURES static void render_texture(unsigned int tex_id, float left, float right, float bottom, float top); static void render_sub_texture(unsigned int tex_id, float left, float right, float bottom, float top, const Quad_UVs& uvs); protected: -#if ENABLE_COMPRESSED_TEXTURES unsigned int generate_mipmaps(wxImage& image, bool compress); -#else - unsigned int generate_mipmaps(wxImage& image); -#endif // ENABLE_COMPRESSED_TEXTURES private: -#if ENABLE_COMPRESSED_TEXTURES bool load_from_png(const std::string& filename, bool use_mipmaps, bool compress); bool load_from_svg(const std::string& filename, bool use_mipmaps, bool compress, bool apply_anisotropy, unsigned int max_size_px); friend class Compressor; -#else - bool load_from_png(const std::string& filename, bool use_mipmaps); - bool load_from_svg(const std::string& filename, bool use_mipmaps, unsigned int max_size_px); -#endif // ENABLE_COMPRESSED_TEXTURES }; } // namespace GUI diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 813a319b807..5a5596ab4bb 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -194,11 +194,7 @@ bool GLToolbar::init(const ItemsIconsTexture::Metadata& icons_texture, const Bac #endif // ENABLE_SVG_ICONS if (!background_texture.filename.empty()) -#if ENABLE_COMPRESSED_TEXTURES res = m_background_texture.texture.load_from_file(path + background_texture.filename, false, true); -#else - res = m_background_texture.texture.load_from_file(path + background_texture.filename, false); -#endif // ENABLE_COMPRESSED_TEXTURES if (res) m_background_texture.metadata = background_texture; @@ -1342,11 +1338,7 @@ bool GLToolbar::generate_icons_texture() const states.push_back(std::make_pair(1, true)); } -#if ENABLE_COMPRESSED_TEXTURES bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, (unsigned int)(m_layout.icons_size * m_layout.scale), true); -#else - bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, (unsigned int)(m_layout.icons_size * m_layout.scale)); -#endif // ENABLE_COMPRESSED_TEXTURES if (res) m_icons_texture_dirty = false; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index c254f5796d9..203a928dd61 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -65,11 +65,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent) if (!m_background_texture.metadata.filename.empty()) { -#if ENABLE_COMPRESSED_TEXTURES if (!m_background_texture.texture.load_from_file(resources_dir() + "/icons/" + m_background_texture.metadata.filename, false, true)) -#else - if (!m_background_texture.texture.load_from_file(resources_dir() + "/icons/" + m_background_texture.metadata.filename, false)) -#endif // ENABLE_COMPRESSED_TEXTURES { reset(); return false; @@ -1164,11 +1160,7 @@ bool GLGizmosManager::generate_icons_texture() const states.push_back(std::make_pair(0, false)); states.push_back(std::make_pair(0, true)); -#if ENABLE_COMPRESSED_TEXTURES bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, (unsigned int)(m_overlay_icons_size * m_overlay_scale), true); -#else - bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, (unsigned int)(m_overlay_icons_size * m_overlay_scale)); -#endif // ENABLE_COMPRESSED_TEXTURES if (res) m_icons_texture_dirty = false; diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 7267da2956a..ca1538bf72a 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -206,11 +206,7 @@ void ImGuiWrapper::new_frame() } if (m_font_texture == 0) { -#if ENABLE_COMPRESSED_TEXTURES init_font(true); -#else - init_font(); -#endif // ENABLE_COMPRESSED_TEXTURES } ImGui::NewFrame(); @@ -387,11 +383,7 @@ bool ImGuiWrapper::want_any_input() const return io.WantCaptureMouse || io.WantCaptureKeyboard || io.WantTextInput; } -#if ENABLE_COMPRESSED_TEXTURES void ImGuiWrapper::init_font(bool compress) -#else -void ImGuiWrapper::init_font() -#endif // ENABLE_COMPRESSED_TEXTURES { destroy_font(); @@ -420,14 +412,10 @@ void ImGuiWrapper::init_font() glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); -#if ENABLE_COMPRESSED_TEXTURES if (compress && GLEW_EXT_texture_compression_s3tc) glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); else glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); -#else - glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); -#endif // ENABLE_COMPRESSED_TEXTURES // Store our identifier io.Fonts->TexID = (ImTextureID)(intptr_t)m_font_texture; diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index a1e4048ac6f..0479e474345 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -77,11 +77,7 @@ public: bool want_any_input() const; private: -#if ENABLE_COMPRESSED_TEXTURES void init_font(bool compress); -#else - void init_font(); -#endif // ENABLE_COMPRESSED_TEXTURES void init_input(); void init_style(); void render_draw_data(ImDrawData *draw_data); From e5393cd84e3ee618ce7dff3b147be185b01366eb Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 24 Jun 2019 11:23:25 +0200 Subject: [PATCH 29/37] Disabled ENABLE_CAMERA_STATISTICS --- src/libslic3r/Technologies.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index fe4d28a7c35..a5f93b24f23 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -14,7 +14,7 @@ // Shows an imgui dialog with render related data #define ENABLE_RENDER_STATISTICS 0 // Shows an imgui dialog with camera related data -#define ENABLE_CAMERA_STATISTICS 1 +#define ENABLE_CAMERA_STATISTICS 0 //==================== From 6d37e444da7be68c310cc70d9f62721a52786e7c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 24 Jun 2019 12:26:11 +0200 Subject: [PATCH 30/37] #2428 1) Reworked logic for pasting volumes 2) Fixed paste of volumes into different objects 3) Do not apply offset when pasting into the copied object 4) Keep source transformation matrix and relative positions when copy/pasting volumes into another object --- src/libslic3r/Geometry.cpp | 57 ++++++++++++++++++++++++++++ src/libslic3r/Geometry.hpp | 5 +++ src/slic3r/GUI/GUI_ObjectList.cpp | 62 +------------------------------ src/slic3r/GUI/Selection.cpp | 46 ++++++++++++++++++++--- 4 files changed, 103 insertions(+), 67 deletions(-) diff --git a/src/libslic3r/Geometry.cpp b/src/libslic3r/Geometry.cpp index ccc629723e1..accb4e2863d 100644 --- a/src/libslic3r/Geometry.cpp +++ b/src/libslic3r/Geometry.cpp @@ -1409,6 +1409,63 @@ Transformation Transformation::operator * (const Transformation& other) const return Transformation(get_matrix() * other.get_matrix()); } +Transformation Transformation::volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox) +{ + Transformation out; + + if (instance_transformation.is_scaling_uniform()) { + // No need to run the non-linear least squares fitting for uniform scaling. + // Just set the inverse. + out.set_from_transform(instance_transformation.get_matrix(true).inverse()); + } + else if (is_rotation_ninety_degrees(instance_transformation.get_rotation())) + { + // Anisotropic scaling, rotation by multiples of ninety degrees. + Eigen::Matrix3d instance_rotation_trafo = + (Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) * + Eigen::AngleAxisd(instance_transformation.get_rotation().y(), Vec3d::UnitY()) * + Eigen::AngleAxisd(instance_transformation.get_rotation().x(), Vec3d::UnitX())).toRotationMatrix(); + Eigen::Matrix3d volume_rotation_trafo = + (Eigen::AngleAxisd(-instance_transformation.get_rotation().x(), Vec3d::UnitX()) * + Eigen::AngleAxisd(-instance_transformation.get_rotation().y(), Vec3d::UnitY()) * + Eigen::AngleAxisd(-instance_transformation.get_rotation().z(), Vec3d::UnitZ())).toRotationMatrix(); + + // 8 corners of the bounding box. + auto pts = Eigen::MatrixXd(8, 3); + pts(0, 0) = bbox.min.x(); pts(0, 1) = bbox.min.y(); pts(0, 2) = bbox.min.z(); + pts(1, 0) = bbox.min.x(); pts(1, 1) = bbox.min.y(); pts(1, 2) = bbox.max.z(); + pts(2, 0) = bbox.min.x(); pts(2, 1) = bbox.max.y(); pts(2, 2) = bbox.min.z(); + pts(3, 0) = bbox.min.x(); pts(3, 1) = bbox.max.y(); pts(3, 2) = bbox.max.z(); + pts(4, 0) = bbox.max.x(); pts(4, 1) = bbox.min.y(); pts(4, 2) = bbox.min.z(); + pts(5, 0) = bbox.max.x(); pts(5, 1) = bbox.min.y(); pts(5, 2) = bbox.max.z(); + pts(6, 0) = bbox.max.x(); pts(6, 1) = bbox.max.y(); pts(6, 2) = bbox.min.z(); + pts(7, 0) = bbox.max.x(); pts(7, 1) = bbox.max.y(); pts(7, 2) = bbox.max.z(); + + // Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier. + auto qs = pts * + (instance_rotation_trafo * + Eigen::Scaling(instance_transformation.get_scaling_factor().cwiseProduct(instance_transformation.get_mirror())) * + volume_rotation_trafo).inverse().transpose(); + // Fill in scaling based on least squares fitting of the bounding box corners. + Vec3d scale; + for (int i = 0; i < 3; ++i) + scale(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i)); + + out.set_rotation(Geometry::extract_euler_angles(volume_rotation_trafo)); + out.set_scaling_factor(Vec3d(std::abs(scale(0)), std::abs(scale(1)), std::abs(scale(2)))); + out.set_mirror(Vec3d(scale(0) > 0 ? 1. : -1, scale(1) > 0 ? 1. : -1, scale(2) > 0 ? 1. : -1)); + } + else + { + // General anisotropic scaling, general rotation. + // Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world. + // Scale it to get the required size. + out.set_scaling_factor(instance_transformation.get_scaling_factor().cwiseInverse()); + } + + return out; +} + Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) { return diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 033c24a8463..bcbe80a0d85 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -258,6 +258,11 @@ public: const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const; Transformation operator * (const Transformation& other) const; + + // Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity + // as possible in least squares norm in regard to the 8 corners of bbox. + // Bounding box is expected to be centered around zero in all axes. + static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox); }; // Rotation when going from the first coordinate system with rotation rot_xyz_from applied diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index a95b71bcb3c..d7d1a1af7b3 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1485,66 +1485,6 @@ void ObjectList::load_part( ModelObject* model_object, } -// Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity -// as possible in least squares norm in regard to the 8 corners of bbox. -// Bounding box is expected to be centered around zero in all axes. -Geometry::Transformation volume_to_bed_transformation(const Geometry::Transformation &instance_transformation, const BoundingBoxf3 &bbox) -{ - Geometry::Transformation out; - - if (instance_transformation.is_scaling_uniform()) { - // No need to run the non-linear least squares fitting for uniform scaling. - // Just set the inverse. - out.set_from_transform(instance_transformation.get_matrix(true).inverse()); - } - else if (Geometry::is_rotation_ninety_degrees(instance_transformation.get_rotation())) - { - // Anisotropic scaling, rotation by multiples of ninety degrees. - Eigen::Matrix3d instance_rotation_trafo = - (Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) * - Eigen::AngleAxisd(instance_transformation.get_rotation().y(), Vec3d::UnitY()) * - Eigen::AngleAxisd(instance_transformation.get_rotation().x(), Vec3d::UnitX())).toRotationMatrix(); - Eigen::Matrix3d volume_rotation_trafo = - (Eigen::AngleAxisd(-instance_transformation.get_rotation().x(), Vec3d::UnitX()) * - Eigen::AngleAxisd(-instance_transformation.get_rotation().y(), Vec3d::UnitY()) * - Eigen::AngleAxisd(-instance_transformation.get_rotation().z(), Vec3d::UnitZ())).toRotationMatrix(); - - // 8 corners of the bounding box. - auto pts = Eigen::MatrixXd(8, 3); - pts(0, 0) = bbox.min.x(); pts(0, 1) = bbox.min.y(); pts(0, 2) = bbox.min.z(); - pts(1, 0) = bbox.min.x(); pts(1, 1) = bbox.min.y(); pts(1, 2) = bbox.max.z(); - pts(2, 0) = bbox.min.x(); pts(2, 1) = bbox.max.y(); pts(2, 2) = bbox.min.z(); - pts(3, 0) = bbox.min.x(); pts(3, 1) = bbox.max.y(); pts(3, 2) = bbox.max.z(); - pts(4, 0) = bbox.max.x(); pts(4, 1) = bbox.min.y(); pts(4, 2) = bbox.min.z(); - pts(5, 0) = bbox.max.x(); pts(5, 1) = bbox.min.y(); pts(5, 2) = bbox.max.z(); - pts(6, 0) = bbox.max.x(); pts(6, 1) = bbox.max.y(); pts(6, 2) = bbox.min.z(); - pts(7, 0) = bbox.max.x(); pts(7, 1) = bbox.max.y(); pts(7, 2) = bbox.max.z(); - - // Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier. - auto qs = pts * - (instance_rotation_trafo * - Eigen::Scaling(instance_transformation.get_scaling_factor().cwiseProduct(instance_transformation.get_mirror())) * - volume_rotation_trafo).inverse().transpose(); - // Fill in scaling based on least squares fitting of the bounding box corners. - Vec3d scale; - for (int i = 0; i < 3; ++ i) - scale(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i)); - - out.set_rotation(Geometry::extract_euler_angles(volume_rotation_trafo)); - out.set_scaling_factor(Vec3d(std::abs(scale(0)), std::abs(scale(1)), std::abs(scale(2)))); - out.set_mirror(Vec3d(scale(0) > 0 ? 1. : -1, scale(1) > 0 ? 1. : -1, scale(2) > 0 ? 1. : -1)); - } - else - { - // General anisotropic scaling, general rotation. - // Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world. - // Scale it to get the required size. - out.set_scaling_factor(instance_transformation.get_scaling_factor().cwiseInverse()); - } - - return out; -} - void ObjectList::load_generic_subobject(const std::string& type_name, const ModelVolumeType type) { const auto obj_idx = get_selected_obj_idx(); @@ -1598,7 +1538,7 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); // Transform the new modifier to be aligned with the print bed. const BoundingBoxf3 mesh_bb = new_volume->mesh().bounding_box(); - new_volume->set_transformation(volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb)); + new_volume->set_transformation(Geometry::Transformation::volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb)); // Set the modifier position. auto offset = (type_name == "Slab") ? // Slab: Lift to print bed diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 480b59ba030..6e80783ccd5 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1893,25 +1893,59 @@ bool Selection::is_from_fully_selected_instance(unsigned int volume_idx) const void Selection::paste_volumes_from_clipboard() { - int obj_idx = get_object_idx(); - if ((obj_idx < 0) || ((int)m_model->objects.size() <= obj_idx)) + int dst_obj_idx = get_object_idx(); + if ((dst_obj_idx < 0) || ((int)m_model->objects.size() <= dst_obj_idx)) + return; + + ModelObject* dst_object = m_model->objects[dst_obj_idx]; + + int dst_inst_idx = get_instance_idx(); + if ((dst_inst_idx < 0) || ((int)dst_object->instances.size() <= dst_inst_idx)) return; ModelObject* src_object = m_clipboard.get_object(0); if (src_object != nullptr) { - ModelObject* dst_object = m_model->objects[obj_idx]; + ModelInstance* dst_instance = dst_object->instances[dst_inst_idx]; + BoundingBoxf3 dst_instance_bb = dst_object->instance_bounding_box(dst_inst_idx); + Transform3d src_matrix = src_object->instances[0]->get_transformation().get_matrix(true); + Transform3d dst_matrix = dst_instance->get_transformation().get_matrix(true); + bool from_same_object = (src_object->input_file == dst_object->input_file) && src_matrix.isApprox(dst_matrix); + + // used to keep relative position of multivolume selections when pasting from another object + BoundingBoxf3 total_bb; ModelVolumePtrs volumes; for (ModelVolume* src_volume : src_object->volumes) { ModelVolume* dst_volume = dst_object->add_volume(*src_volume); dst_volume->set_new_unique_id(); - double offset = wxGetApp().plater()->canvas3D()->get_size_proportional_to_max_bed_size(0.05); - dst_volume->translate(offset, offset, 0.0); + if (from_same_object) + { +// // if the volume comes from the same object, apply the offset in world system +// double offset = wxGetApp().plater()->canvas3D()->get_size_proportional_to_max_bed_size(0.05); +// dst_volume->translate(dst_matrix.inverse() * Vec3d(offset, offset, 0.0)); + } + else + { + // if the volume comes from another object, apply the offset as done when adding modifiers + // see ObjectList::load_generic_subobject() + total_bb.merge(dst_volume->mesh().bounding_box().transformed(src_volume->get_matrix())); + } + volumes.push_back(dst_volume); } - wxGetApp().obj_list()->paste_volumes_into_list(obj_idx, volumes); + + // keeps relative position of multivolume selections + if (!from_same_object) + { + for (ModelVolume* v : volumes) + { + v->set_offset((v->get_offset() - total_bb.center()) + dst_matrix.inverse() * (Vec3d(dst_instance_bb.max(0), dst_instance_bb.min(1), dst_instance_bb.min(2)) + 0.5 * total_bb.size() - dst_instance->get_transformation().get_offset())); + } + } + + wxGetApp().obj_list()->paste_volumes_into_list(dst_obj_idx, volumes); } } From 1797bd1591512d56d9c2ffb3263621b00e71ca9f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 24 Jun 2019 12:35:20 +0200 Subject: [PATCH 31/37] #2433 - Time Estimator: clamp accelerate/decelerate distances to avoid them to become negative --- src/libslic3r/GCodeTimeEstimator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 60d7a4cdf43..b87305da873 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -125,8 +125,8 @@ namespace Slic3r { trapezoid.distance = distance; trapezoid.feedrate = feedrate; - float accelerate_distance = estimate_acceleration_distance(feedrate.entry, feedrate.cruise, acceleration); - float decelerate_distance = estimate_acceleration_distance(feedrate.cruise, feedrate.exit, -acceleration); + float accelerate_distance = std::max(0.0f, estimate_acceleration_distance(feedrate.entry, feedrate.cruise, acceleration)); + float decelerate_distance = std::max(0.0f, estimate_acceleration_distance(feedrate.cruise, feedrate.exit, -acceleration)); float cruise_distance = distance - accelerate_distance - decelerate_distance; // Not enough space to reach the nominal feedrate. From ed02acee95d344acc187d289088ed4283208369a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 24 Jun 2019 12:43:18 +0200 Subject: [PATCH 32/37] #2395 - Reworked logic of method Model::convert_multipart_object() --- src/libslic3r/Model.cpp | 52 ++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 8e879a3e682..596f8067100 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -489,21 +489,57 @@ void Model::convert_multipart_object(unsigned int max_extruders) reset_auto_extruder_id(); + bool is_single_object = (this->objects.size() == 1); + for (const ModelObject* o : this->objects) + { for (const ModelVolume* v : o->volumes) { - ModelVolume* new_v = object->add_volume(*v); - if (new_v != nullptr) + if (is_single_object) { - new_v->name = o->name; - new_v->config.set_deserialize("extruder", get_auto_extruder_id_as_string(max_extruders)); - new_v->translate(-o->origin_translation); + // If there is only one object, just copy the volumes + ModelVolume* new_v = object->add_volume(*v); + if (new_v != nullptr) + { + new_v->name = o->name; + new_v->config.set_deserialize("extruder", get_auto_extruder_id_as_string(max_extruders)); + new_v->translate(-o->origin_translation); + } + } + else + { + // If there are more than one object, put all volumes together + // Each object may contain any number of volumes and instances + // The volumes transformations are relative to the object containing them... + int counter = 1; + for (const ModelInstance* i : o->instances) + { + ModelVolume* new_v = object->add_volume(*v); + if (new_v != nullptr) + { + new_v->name = o->name + "_" + std::to_string(counter++); + new_v->config.set_deserialize("extruder", get_auto_extruder_id_as_string(max_extruders)); + new_v->translate(-o->origin_translation); + // ...so, transform everything to a common reference system (world) + new_v->set_transformation(i->get_transformation() * v->get_transformation()); + } + } } } + } + + if (is_single_object) + { + // If there is only one object, keep its instances + for (const ModelInstance* i : this->objects.front()->instances) + { + object->add_instance(*i); + } + } + else + // If there are more than one object, create a single instance + object->add_instance(); - for (const ModelInstance* i : this->objects.front()->instances) - object->add_instance(*i); - this->clear_objects(); this->objects.push_back(object); } From e907da2d6657067a983f652aca7ccf6988e06da6 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 24 Jun 2019 13:01:52 +0200 Subject: [PATCH 33/37] Print bed not considered as object in arrange anymore. --- src/libslic3r/MTUtils.hpp | 9 +++++++++ src/libslic3r/ModelArrange.cpp | 31 ++++++++++++++----------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/libslic3r/MTUtils.hpp b/src/libslic3r/MTUtils.hpp index 0afe3563f9e..f6bff2b1f8f 100644 --- a/src/libslic3r/MTUtils.hpp +++ b/src/libslic3r/MTUtils.hpp @@ -191,6 +191,15 @@ template bool all_of(const C &container) { }); } +template inline X ceil_i(X x, Y y) +{ + static_assert(std::is_integral::value && + std::is_integral::value && sizeof(X) >= sizeof(Y), + ""); + + return (x % y) ? x / y + 1 : x / y; +} + } #endif // MTUTILS_HPP diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index a440c3999d2..36f7e397100 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -2,6 +2,7 @@ #include "Model.hpp" #include "Geometry.hpp" #include "SVG.hpp" +#include "MTUtils.hpp" #include @@ -820,15 +821,13 @@ bool arrange(Model &model, // The model with the geometries BoundingBox bbb(bed); auto& cfn = stopcondition; + + coord_t md = ceil_i(min_obj_distance, 2) - SCALED_EPSILON; - auto binbb = Box({ - static_cast(bbb.min(0)), - static_cast(bbb.min(1)) - }, - { - static_cast(bbb.max(0)), - static_cast(bbb.max(1)) - }); + auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md, + libnest2d::Coord{bbb.min(1)} - md}, + {libnest2d::Coord{bbb.max(0)} + md, + libnest2d::Coord{bbb.max(1)} + md}); switch(bedhint.type) { case BedShapeType::BOX: { @@ -916,15 +915,13 @@ void find_new_position(const Model &model, BedShapeHint bedhint = bedShape(bed); BoundingBox bbb(bed); - - auto binbb = Box({ - static_cast(bbb.min(0)), - static_cast(bbb.min(1)) - }, - { - static_cast(bbb.max(0)), - static_cast(bbb.max(1)) - }); + + coord_t md = ceil_i(min_obj_distance, 2) - SCALED_EPSILON; + + auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md, + libnest2d::Coord{bbb.min(1)} - md}, + {libnest2d::Coord{bbb.max(0)} + md, + libnest2d::Coord{bbb.max(1)} + md}); for(auto it = shapemap.begin(); it != shapemap.end(); ++it) { if(std::find(toadd.begin(), toadd.end(), it->first) == toadd.end()) { From 81ade624f4bf261506d4fd9d2275f5f0b582d8ff Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 24 Jun 2019 13:03:46 +0200 Subject: [PATCH 34/37] Reformatted MTUtils with some refined directives. Only whitespace changes in MTUtils.hpp ! --- .clang-format | 8 +- src/libslic3r/MTUtils.hpp | 200 +++++++++++++++++++++++--------------- 2 files changed, 128 insertions(+), 80 deletions(-) diff --git a/.clang-format b/.clang-format index d5740f68949..9cbcf26f264 100644 --- a/.clang-format +++ b/.clang-format @@ -18,7 +18,7 @@ AllowShortLoopsOnASingleLine: true AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: Yes +AlwaysBreakTemplateDeclarations: false BinPackArguments: false BinPackParameters: false BraceWrapping: @@ -37,18 +37,18 @@ BraceWrapping: SplitEmptyFunction: false SplitEmptyRecord: false SplitEmptyNamespace: false -BreakBeforeBinaryOperators: All +BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom BreakBeforeInheritanceComma: false BreakInheritanceList: BeforeColon -BreakBeforeTernaryOperators: true +BreakBeforeTernaryOperators: false BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeComma BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true ColumnLimit: 75 CommentPragmas: '^ IWYU pragma:' -CompactNamespaces: false +CompactNamespaces: true ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 diff --git a/src/libslic3r/MTUtils.hpp b/src/libslic3r/MTUtils.hpp index f6bff2b1f8f..b261a79be81 100644 --- a/src/libslic3r/MTUtils.hpp +++ b/src/libslic3r/MTUtils.hpp @@ -1,172 +1,218 @@ #ifndef MTUTILS_HPP #define MTUTILS_HPP -#include // for std::atomic_flag and memory orders -#include // for std::lock_guard -#include // for std::function -#include // for std::forward +#include // for std::atomic_flag and memory orders +#include // for std::lock_guard +#include // for std::function +#include // for std::forward #include namespace Slic3r { /// Handy little spin mutex for the cached meshes. /// Implements the "Lockable" concept -class SpinMutex { - std::atomic_flag m_flg; +class SpinMutex +{ + std::atomic_flag m_flg; static const /*constexpr*/ auto MO_ACQ = std::memory_order_acquire; static const /*constexpr*/ auto MO_REL = std::memory_order_release; + public: inline SpinMutex() { m_flg.clear(MO_REL); } - inline void lock() { while(m_flg.test_and_set(MO_ACQ)); } + inline void lock() { while (m_flg.test_and_set(MO_ACQ)) ; } inline bool try_lock() { return !m_flg.test_and_set(MO_ACQ); } inline void unlock() { m_flg.clear(MO_REL); } }; /// A wrapper class around arbitrary object that needs thread safe caching. -template class CachedObject { +template class CachedObject +{ public: // Method type which refreshes the object when it has been invalidated - using Setter = std::function; + using Setter = std::function; + private: - T m_obj; // the object itself - bool m_valid; // invalidation flag - SpinMutex m_lck; // to make the caching thread safe + T m_obj; // the object itself + bool m_valid; // invalidation flag + SpinMutex m_lck; // to make the caching thread safe + + // the setter will be called just before the object's const value is + // about to be retrieved. + std::function m_setter; - // the setter will be called just before the object's const value is about - // to be retrieved. - std::function m_setter; public: - // Forwarded constructor - template inline CachedObject(Setter fn, Args&&...args): - m_obj(std::forward(args)...), m_valid(false), m_setter(fn) {} + template + inline CachedObject(Setter fn, Args &&... args) + : m_obj(std::forward(args)...), m_valid(false), m_setter(fn) + {} - // invalidate the value of the object. The object will be refreshed at the - // next retrieval (Setter will be called). The data that is used in - // the setter function should be guarded as well during modification so the - // modification has to take place in fn. - inline void invalidate(std::function fn) { - std::lock_guard lck(m_lck); fn(); m_valid = false; + // invalidate the value of the object. The object will be refreshed at + // the next retrieval (Setter will be called). The data that is used in + // the setter function should be guarded as well during modification so + // the modification has to take place in fn. + inline void invalidate(std::function fn) + { + std::lock_guard lck(m_lck); + fn(); + m_valid = false; } // Get the const object properly updated. - inline const T& get() { + inline const T &get() + { std::lock_guard lck(m_lck); - if(!m_valid) { m_setter(m_obj); m_valid = true; } + if (!m_valid) { + m_setter(m_obj); + m_valid = true; + } return m_obj; } }; -/// An std compatible random access iterator which uses indices to the source -/// vector thus resistant to invalidation caused by relocations. It also "knows" -/// its container. No comparison is neccesary to the container "end()" iterator. -/// The template can be instantiated with a different value type than that of -/// the container's but the types must be compatible. E.g. a base class of the -/// contained objects is compatible. +/// An std compatible random access iterator which uses indices to the +/// source vector thus resistant to invalidation caused by relocations. It +/// also "knows" its container. No comparison is neccesary to the container +/// "end()" iterator. The template can be instantiated with a different +/// value type than that of the container's but the types must be +/// compatible. E.g. a base class of the contained objects is compatible. /// /// For a constant iterator, one can instantiate this template with a value /// type preceded with 'const'. -template -class IndexBasedIterator { +class IndexBasedIterator +{ static const size_t NONE = size_t(-1); std::reference_wrapper m_index_ref; - size_t m_idx = NONE; -public: + size_t m_idx = NONE; - using value_type = Value; - using pointer = Value *; - using reference = Value &; - using difference_type = long; +public: + using value_type = Value; + using pointer = Value *; + using reference = Value &; + using difference_type = long; using iterator_category = std::random_access_iterator_tag; - inline explicit - IndexBasedIterator(Vector& index, size_t idx): - m_index_ref(index), m_idx(idx) {} + inline explicit IndexBasedIterator(Vector &index, size_t idx) + : m_index_ref(index), m_idx(idx) + {} // Post increment - inline IndexBasedIterator operator++(int) { - IndexBasedIterator cpy(*this); ++m_idx; return cpy; + inline IndexBasedIterator operator++(int) + { + IndexBasedIterator cpy(*this); + ++m_idx; + return cpy; } - inline IndexBasedIterator operator--(int) { - IndexBasedIterator cpy(*this); --m_idx; return cpy; + inline IndexBasedIterator operator--(int) + { + IndexBasedIterator cpy(*this); + --m_idx; + return cpy; } - inline IndexBasedIterator& operator++() { - ++m_idx; return *this; + inline IndexBasedIterator &operator++() + { + ++m_idx; + return *this; } - inline IndexBasedIterator& operator--() { - --m_idx; return *this; + inline IndexBasedIterator &operator--() + { + --m_idx; + return *this; } - inline IndexBasedIterator& operator+=(difference_type l) { - m_idx += size_t(l); return *this; + inline IndexBasedIterator &operator+=(difference_type l) + { + m_idx += size_t(l); + return *this; } - inline IndexBasedIterator operator+(difference_type l) { - auto cpy = *this; cpy += l; return cpy; + inline IndexBasedIterator operator+(difference_type l) + { + auto cpy = *this; + cpy += l; + return cpy; } - inline IndexBasedIterator& operator-=(difference_type l) { - m_idx -= size_t(l); return *this; + inline IndexBasedIterator &operator-=(difference_type l) + { + m_idx -= size_t(l); + return *this; } - inline IndexBasedIterator operator-(difference_type l) { - auto cpy = *this; cpy -= l; return cpy; + inline IndexBasedIterator operator-(difference_type l) + { + auto cpy = *this; + cpy -= l; + return cpy; } operator difference_type() { return difference_type(m_idx); } /// Tesing the end of the container... this is not possible with std /// iterators. - inline bool is_end() const { return m_idx >= m_index_ref.get().size();} + inline bool is_end() const + { + return m_idx >= m_index_ref.get().size(); + } - inline Value & operator*() const { + inline Value &operator*() const + { assert(m_idx < m_index_ref.get().size()); return m_index_ref.get().operator[](m_idx); } - inline Value * operator->() const { + inline Value *operator->() const + { assert(m_idx < m_index_ref.get().size()); return &m_index_ref.get().operator[](m_idx); } /// If both iterators point past the container, they are equal... - inline bool operator ==(const IndexBasedIterator& other) { + inline bool operator==(const IndexBasedIterator &other) + { size_t e = m_index_ref.get().size(); return m_idx == other.m_idx || (m_idx >= e && other.m_idx >= e); } - inline bool operator !=(const IndexBasedIterator& other) { + inline bool operator!=(const IndexBasedIterator &other) + { return !(*this == other); } - inline bool operator <=(const IndexBasedIterator& other) { + inline bool operator<=(const IndexBasedIterator &other) + { return (m_idx < other.m_idx) || (*this == other); } - inline bool operator <(const IndexBasedIterator& other) { + inline bool operator<(const IndexBasedIterator &other) + { return m_idx < other.m_idx && (*this != other); } - inline bool operator >=(const IndexBasedIterator& other) { + inline bool operator>=(const IndexBasedIterator &other) + { return m_idx > other.m_idx || *this == other; } - inline bool operator >(const IndexBasedIterator& other) { + inline bool operator>(const IndexBasedIterator &other) + { return m_idx > other.m_idx && *this != other; } }; /// A very simple range concept implementation with iterator-like objects. -template class Range { +template class Range +{ It from, to; -public: +public: // The class is ready for range based for loops. It begin() const { return from; } It end() const { return to; } @@ -175,15 +221,17 @@ public: using Type = It; Range() = default; - Range(It &&b, It &&e): - from(std::forward(b)), to(std::forward(e)) {} + Range(It &&b, It &&e) + : from(std::forward(b)), to(std::forward(e)) + {} // Some useful container-like methods... inline size_t size() const { return end() - begin(); } - inline bool empty() const { return size() == 0; } + inline bool empty() const { return size() == 0; } }; -template bool all_of(const C &container) { +template bool all_of(const C &container) +{ return std::all_of(container.begin(), container.end(), [](const typename C::value_type &v) { @@ -196,10 +244,10 @@ template inline X ceil_i(X x, Y y) static_assert(std::is_integral::value && std::is_integral::value && sizeof(X) >= sizeof(Y), ""); - + return (x % y) ? x / y + 1 : x / y; } -} +} // namespace Slic3r #endif // MTUTILS_HPP From a34029271711a468ac6d8fcec874c22fd904fb51 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 24 Jun 2019 13:11:18 +0200 Subject: [PATCH 35/37] Color_print issues : - fixed #1933 - implemented thumb moving to the mouse click position - implemented "discard color changes" button --- src/slic3r/GUI/wxExtensions.cpp | 78 +++++++++++++++++++++++++++++---- src/slic3r/GUI/wxExtensions.hpp | 4 ++ 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 406daccf550..ed496a97ec9 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -1583,6 +1583,9 @@ DoubleSlider::DoubleSlider( wxWindow *parent, m_bmp_one_layer_unlock_off = ScalableBitmap(this, "one_layer_unlock_off.png"); m_lock_icon_dim = m_bmp_one_layer_lock_on.bmp().GetSize().x; + m_bmp_revert = ScalableBitmap(this, "undo"); + m_revert_icon_dim = m_bmp_revert.bmp().GetSize().x; + m_selection = ssUndef; // slider events @@ -1638,6 +1641,9 @@ void DoubleSlider::msw_rescale() m_bmp_one_layer_unlock_off.msw_rescale(); m_lock_icon_dim = m_bmp_one_layer_lock_on.bmp().GetSize().x; + m_bmp_revert.msw_rescale(); + m_revert_icon_dim = m_bmp_revert.bmp().GetSize().x; + SLIDER_MARGIN = 4 + Slic3r::GUI::wxGetApp().em_unit(); SetMinSize(get_min_size()); @@ -1874,8 +1880,11 @@ void DoubleSlider::render() //draw color print ticks draw_ticks(dc); - //draw color print ticks + //draw lock/unlock draw_one_layer_icon(dc); + + //draw revert bitmap (if it's shown) + draw_revert_icon(dc); } void DoubleSlider::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoint pt_end) @@ -2102,6 +2111,24 @@ void DoubleSlider::draw_one_layer_icon(wxDC& dc) m_rect_one_layer_icon = wxRect(x_draw, y_draw, m_lock_icon_dim, m_lock_icon_dim); } +void DoubleSlider::draw_revert_icon(wxDC& dc) +{ + if (m_ticks.empty()) + return; + + int width, height; + get_size(&width, &height); + + wxCoord x_draw, y_draw; + is_horizontal() ? x_draw = width-2 : x_draw = 0.25*SLIDER_MARGIN; + is_horizontal() ? y_draw = 0.25*SLIDER_MARGIN: y_draw = height-2; + + dc.DrawBitmap(m_bmp_revert.bmp(), x_draw, y_draw); + + //update rect of the lock/unlock icon + m_rect_revert_icon = wxRect(x_draw, y_draw, m_revert_icon_dim, m_revert_icon_dim); +} + void DoubleSlider::update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection) { const wxRect& rect = wxRect(begin_x, begin_y, m_thumb_size.x, m_thumb_size.y); @@ -2118,8 +2145,8 @@ int DoubleSlider::get_value_from_position(const wxCoord x, const wxCoord y) if (is_horizontal()) return int(double(x - SLIDER_MARGIN) / step + 0.5); - else - return int(m_min_value + double(height - SLIDER_MARGIN - y) / step + 0.5); + + return int(m_min_value + double(height - SLIDER_MARGIN - y) / step + 0.5); } void DoubleSlider::detect_selected_slider(const wxPoint& pt) @@ -2169,7 +2196,10 @@ void DoubleSlider::ChangeOneLayerLock() void DoubleSlider::OnLeftDown(wxMouseEvent& event) { + if (HasCapture()) + return; this->CaptureMouse(); + wxClientDC dc(this); wxPoint pos = event.GetLogicalPosition(dc); if (is_point_in_rect(pos, m_rect_tick_action) && m_is_enabled_tick_manipulation) { @@ -2179,6 +2209,7 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event) m_is_left_down = true; if (is_point_in_rect(pos, m_rect_one_layer_icon)) { + // switch on/off one layer mode m_is_one_layer = !m_is_one_layer; if (!m_is_one_layer) { SetLowerValue(m_min_value); @@ -2187,20 +2218,36 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event) m_selection == ssLower ? correct_lower_value() : correct_higher_value(); if (!m_selection) m_selection = ssHigher; } + else if (is_point_in_rect(pos, m_rect_revert_icon)) { + // discard all color changes + SetLowerValue(m_min_value); + SetHigherValue(m_max_value); + + m_selection == ssLower ? correct_lower_value() : correct_higher_value(); + if (!m_selection) m_selection = ssHigher; + + m_ticks.clear(); + wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); + } else detect_selected_slider(pos); - if (!m_selection && m_is_enabled_tick_manipulation) { - const auto tick = is_point_near_tick(pos); - if (tick >= 0) + if (!m_selection) { + const int tick_val = is_point_near_tick(pos); + /* Set current thumb position to the nearest tick (if it is) + * OR to a value corresponding to the mouse click + * */ + const int mouse_val = tick_val >= 0 && m_is_enabled_tick_manipulation ? tick_val : + get_value_from_position(pos.x, pos.y); + if (mouse_val >= 0) { - if (abs(tick - m_lower_value) < abs(tick - m_higher_value)) { - SetLowerValue(tick); + if (abs(mouse_val - m_lower_value) < abs(mouse_val - m_higher_value)) { + SetLowerValue(mouse_val); correct_lower_value(); m_selection = ssLower; } else { - SetHigherValue(tick); + SetHigherValue(mouse_val); correct_higher_value(); m_selection = ssHigher; } @@ -2240,9 +2287,13 @@ void DoubleSlider::OnMotion(wxMouseEvent& event) const wxClientDC dc(this); const wxPoint pos = event.GetLogicalPosition(dc); + m_is_one_layer_icon_focesed = is_point_in_rect(pos, m_rect_one_layer_icon); + bool is_revert_icon_focused = false; + if (!m_is_left_down && !m_is_one_layer) { m_is_action_icon_focesed = is_point_in_rect(pos, m_rect_tick_action); + is_revert_icon_focused = !m_ticks.empty() && is_point_in_rect(pos, m_rect_revert_icon); } else if (m_is_left_down || m_is_right_down) { if (m_selection == ssLower) { @@ -2262,6 +2313,13 @@ void DoubleSlider::OnMotion(wxMouseEvent& event) Update(); event.Skip(); + // Set tooltips with information for each icon + const wxString tooltip = m_is_one_layer_icon_focesed ? _(L("One layer mode")) : + m_is_action_icon_focesed ? _(L("Add/Del color change")) : + is_revert_icon_focused ? _(L("Discard all color changes")) : + wxEmptyString; + this->SetToolTip(tooltip); + if (action) { wxCommandEvent e(wxEVT_SCROLL_CHANGED); @@ -2412,7 +2470,9 @@ void DoubleSlider::OnChar(wxKeyEvent& event) void DoubleSlider::OnRightDown(wxMouseEvent& event) { + if (HasCapture()) return; this->CaptureMouse(); + const wxClientDC dc(this); detect_selected_slider(event.GetLogicalPosition(dc)); if (!m_selection) diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index dd035690ad2..081c0d48f9c 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -742,6 +742,7 @@ protected: void draw_ticks(wxDC& dc); void draw_colored_band(wxDC& dc); void draw_one_layer_icon(wxDC& dc); + void draw_revert_icon(wxDC& dc); void draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection); void draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, SelectedSlider selection); void draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const; @@ -783,6 +784,7 @@ private: ScalableBitmap m_bmp_one_layer_lock_off; ScalableBitmap m_bmp_one_layer_unlock_on; ScalableBitmap m_bmp_one_layer_unlock_off; + ScalableBitmap m_bmp_revert; SelectedSlider m_selection; bool m_is_left_down = false; bool m_is_right_down = false; @@ -796,9 +798,11 @@ private: wxRect m_rect_higher_thumb; wxRect m_rect_tick_action; wxRect m_rect_one_layer_icon; + wxRect m_rect_revert_icon; wxSize m_thumb_size; int m_tick_icon_dim; int m_lock_icon_dim; + int m_revert_icon_dim; long m_style; float m_label_koef = 1.0; From 0e95ed9aabea74b88ea2c3f3884dae7ed6083039 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 24 Jun 2019 13:21:05 +0200 Subject: [PATCH 36/37] Do not allow to copy/paste volumes when using sla printer --- src/slic3r/GUI/GLCanvas3D.cpp | 4 +-- src/slic3r/GUI/MainFrame.cpp | 4 +-- src/slic3r/GUI/Plater.cpp | 58 ++++++++++++++++++++++------------- src/slic3r/GUI/Plater.hpp | 5 ++- src/slic3r/GUI/Selection.cpp | 34 ++++++++++++++++++++ src/slic3r/GUI/Selection.hpp | 3 ++ 6 files changed, 79 insertions(+), 29 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e0aa670740c..ffaa2d20c54 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3488,7 +3488,7 @@ bool GLCanvas3D::_init_toolbar() item.tooltip = _utf8(L("Copy")) + " [" + GUI::shortkey_ctrl_prefix() + "C]"; item.sprite_id = 4; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_COPY)); }; - item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_copy(); }; + item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_copy_to_clipboard(); }; if (!m_toolbar.add_item(item)) return false; @@ -3499,7 +3499,7 @@ bool GLCanvas3D::_init_toolbar() item.tooltip = _utf8(L("Paste")) + " [" + GUI::shortkey_ctrl_prefix() + "V]"; item.sprite_id = 5; item.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_PASTE)); }; - item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_paste(); }; + item.enabled_state_callback = []()->bool { return wxGetApp().plater()->can_paste_from_clipboard(); }; if (!m_toolbar.add_item(item)) return false; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 667dcd899dc..d800f6f3801 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -505,10 +505,10 @@ void MainFrame::init_menubar() editMenu->AppendSeparator(); append_menu_item(editMenu, wxID_ANY, _(L("&Copy")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "C", _(L("Copy selection to clipboard")), [this](wxCommandEvent&) { m_plater->copy_selection_to_clipboard(); }, - menu_icon("copy_menu"), nullptr, [this](){return m_plater->can_copy(); }, this); + menu_icon("copy_menu"), nullptr, [this](){return m_plater->can_copy_to_clipboard(); }, this); append_menu_item(editMenu, wxID_ANY, _(L("&Paste")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "V", _(L("Paste clipboard")), [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); }, - menu_icon("paste_menu"), nullptr, [this](){return m_plater->can_paste(); }, this); + menu_icon("paste_menu"), nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this); } // Window menu diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c2456db800b..f68267cef0c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4187,30 +4187,14 @@ void Plater::update_object_menu() { p->update_object_menu(); } void Plater::copy_selection_to_clipboard() { - p->view3D->get_canvas3d()->get_selection().copy_to_clipboard(); + if (can_copy_to_clipboard()) + p->view3D->get_canvas3d()->get_selection().copy_to_clipboard(); } void Plater::paste_from_clipboard() { - p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); -} - -bool Plater::can_paste_from_clipboard() const -{ - const Selection& selection = p->view3D->get_canvas3d()->get_selection(); - const Selection::Clipboard& clipboard = selection.get_clipboard(); - Selection::EMode mode = clipboard.get_mode(); - - if (clipboard.is_empty()) - return false; - - if ((mode == Selection::Volume) && !selection.is_from_single_instance()) - return false; - - if ((mode == Selection::Instance) && (selection.get_mode() != Selection::Instance)) - return false; - - return true; + if (can_paste_from_clipboard()) + p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); } void Plater::msw_rescale() @@ -4237,7 +4221,37 @@ bool Plater::can_split_to_objects() const { return p->can_split_to_objects(); } bool Plater::can_split_to_volumes() const { return p->can_split_to_volumes(); } bool Plater::can_arrange() const { return p->can_arrange(); } bool Plater::can_layers_editing() const { return p->can_layers_editing(); } -bool Plater::can_copy() const { return !is_selection_empty(); } -bool Plater::can_paste() const { return can_paste_from_clipboard(); } +bool Plater::can_paste_from_clipboard() const +{ + const Selection& selection = p->view3D->get_canvas3d()->get_selection(); + const Selection::Clipboard& clipboard = selection.get_clipboard(); + + if (clipboard.is_empty()) + return false; + + if ((wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) && !clipboard.is_sla_compliant()) + return false; + + Selection::EMode mode = clipboard.get_mode(); + if ((mode == Selection::Volume) && !selection.is_from_single_instance()) + return false; + + if ((mode == Selection::Instance) && (selection.get_mode() != Selection::Instance)) + return false; + + return true; +} + +bool Plater::can_copy_to_clipboard() const +{ + if (is_selection_empty()) + return false; + + const Selection& selection = p->view3D->get_canvas3d()->get_selection(); + if ((wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) && !selection.is_sla_compliant()) + return false; + + return true; +} }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 761bf7a052f..2851af65441 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -200,7 +200,6 @@ public: void copy_selection_to_clipboard(); void paste_from_clipboard(); - bool can_paste_from_clipboard() const; bool can_delete() const; bool can_delete_all() const; @@ -212,8 +211,8 @@ public: bool can_split_to_volumes() const; bool can_arrange() const; bool can_layers_editing() const; - bool can_copy() const; - bool can_paste() const; + bool can_paste_from_clipboard() const; + bool can_copy_to_clipboard() const; void msw_rescale(); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 6e80783ccd5..97168ee045b 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -47,6 +47,26 @@ Selection::VolumeCache::VolumeCache(const Geometry::Transformation& volume_trans { } +bool Selection::Clipboard::is_sla_compliant() const +{ + if (m_mode == Selection::Volume) + return false; + + for (const ModelObject* o : m_model.objects) + { + if (o->is_multiparts()) + return false; + + for (const ModelVolume* v : o->volumes) + { + if (v->is_modifier()) + return false; + } + } + + return true; +} + Selection::Selection() : m_volumes(nullptr) , m_model(nullptr) @@ -385,6 +405,20 @@ bool Selection::is_from_single_object() const return (0 <= idx) && (idx < 1000); } +bool Selection::is_sla_compliant() const +{ + if (m_mode == Volume) + return false; + + for (unsigned int i : m_list) + { + if ((*m_volumes)[i]->is_modifier) + return false; + } + + return true; +} + bool Selection::requires_uniform_scale() const { if (is_single_full_instance() || is_single_modifier() || is_single_volume()) diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 5da1e477bc7..802f8d2847a 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -152,6 +152,8 @@ public: void reset() { m_model.clear_objects(); } bool is_empty() const { return m_model.objects.empty(); } + bool is_sla_compliant() const; + ModelObject* add_object() { return m_model.add_object(); } ModelObject* get_object(unsigned int id) { return (id < (unsigned int)m_model.objects.size()) ? m_model.objects[id] : nullptr; } const ModelObjectPtrs& get_objects() const { return m_model.objects; } @@ -257,6 +259,7 @@ public: bool is_mixed() const { return m_type == Mixed; } bool is_from_single_instance() const { return get_instance_idx() != -1; } bool is_from_single_object() const; + bool is_sla_compliant() const; bool contains_volume(unsigned int volume_idx) const { return m_list.find(volume_idx) != m_list.end(); } bool requires_uniform_scale() const; From 72e8ea2a877088468ec23dbc7eae8e42f8bc2e46 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 24 Jun 2019 13:45:35 +0200 Subject: [PATCH 37/37] Fix of OSX build --- src/slic3r/GUI/wxExtensions.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index ed496a97ec9..aed4236749b 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2316,8 +2316,7 @@ void DoubleSlider::OnMotion(wxMouseEvent& event) // Set tooltips with information for each icon const wxString tooltip = m_is_one_layer_icon_focesed ? _(L("One layer mode")) : m_is_action_icon_focesed ? _(L("Add/Del color change")) : - is_revert_icon_focused ? _(L("Discard all color changes")) : - wxEmptyString; + is_revert_icon_focused ? _(L("Discard all color changes")) : ""; this->SetToolTip(tooltip); if (action)