diff --git a/resources/shaders/gouraud.fs b/resources/shaders/gouraud.fs index 09003f407..dce033d7b 100644 --- a/resources/shaders/gouraud.fs +++ b/resources/shaders/gouraud.fs @@ -1,6 +1,21 @@ #version 110 const vec3 ZERO = vec3(0.0, 0.0, 0.0); +const vec3 GREEN = vec3(0.0, 0.7, 0.0); +const vec3 YELLOW = vec3(0.5, 0.7, 0.0); +const vec3 RED = vec3(0.7, 0.0, 0.0); +const float EPSILON = 0.0001; + +struct SlopeDetection +{ + bool active; + // x = yellow, y = red + vec2 z_range; + mat3 volume_world_normal_matrix; +}; + +uniform vec4 uniform_color; +uniform SlopeDetection slope; varying vec3 clipping_planes_dots; @@ -10,14 +25,20 @@ varying vec2 intensity; varying vec3 delta_box_min; varying vec3 delta_box_max; -uniform vec4 uniform_color; +varying float world_normal_z; +vec3 slope_color() +{ + float gradient_range = slope.z_range.x - slope.z_range.y; + return (world_normal_z > slope.z_range.x - EPSILON) ? GREEN : ((gradient_range == 0.0) ? RED : mix(RED, YELLOW, clamp((world_normal_z - slope.z_range.y) / gradient_range, 0.0, 1.0))); +} void main() { if (any(lessThan(clipping_planes_dots, ZERO))) discard; + vec3 color = slope.active ? slope_color() : uniform_color.rgb; // if the fragment is outside the print volume -> use darker color - vec3 color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(uniform_color.rgb, ZERO, 0.3333) : uniform_color.rgb; + color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + color * intensity.x, uniform_color.a); } diff --git a/resources/shaders/gouraud.vs b/resources/shaders/gouraud.vs index cc54c1c44..72d6c18b3 100644 --- a/resources/shaders/gouraud.vs +++ b/resources/shaders/gouraud.vs @@ -20,13 +20,22 @@ const vec3 ZERO = vec3(0.0, 0.0, 0.0); struct PrintBoxDetection { + bool active; vec3 min; vec3 max; - bool volume_detection; mat4 volume_world_matrix; }; +struct SlopeDetection +{ + bool active; + // x = yellow, y = red + vec2 z_range; + mat3 volume_world_normal_matrix; +}; + uniform PrintBoxDetection print_box; +uniform SlopeDetection slope; // Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane. uniform vec2 z_range; @@ -41,6 +50,8 @@ varying vec3 delta_box_max; varying vec3 clipping_planes_dots; +varying float world_normal_z; + void main() { // First transform the normal into camera space and normalize the result. @@ -61,7 +72,7 @@ void main() intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; // compute deltas for out of print volume detection (world coordinates) - if (print_box.volume_detection) + if (print_box.active) { vec3 v = (print_box.volume_world_matrix * gl_Vertex).xyz; delta_box_min = v - print_box.min; @@ -73,6 +84,9 @@ void main() delta_box_max = ZERO; } + // z component of normal vector in world coordinate used for slope shading + world_normal_z = slope.active ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0; + gl_Position = ftransform(); // Point in homogenous coordinates. vec4 world_pos = print_box.volume_world_matrix * gl_Vertex; diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index f758709b8..9270d3887 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -531,8 +531,10 @@ int CLI::run(int argc, char **argv) gui->mainframe->load_config(m_extra_config); }); int result = wxEntry(argc, argv); +#if !ENABLE_NON_STATIC_CANVAS_MANAGER //FIXME this is a workaround for the PrusaSlicer 2.1 release. _3DScene::destroy(); +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER return result; #else /* SLIC3R_GUI */ // No GUI support. Just print out a help. diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 6806f4f54..674410388 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -464,7 +464,7 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src, void ConfigBase::set_deserialize(const t_config_option_key &opt_key_src, const std::string &value_src, bool append) { if (! this->set_deserialize_nothrow(opt_key_src, value_src, append)) - throw BadOptionTypeException("ConfigBase::set_deserialize() failed"); + throw BadOptionTypeException((boost::format("ConfigBase::set_deserialize() failed for parameter \"%1%\", value \"%2%\"") % opt_key_src % value_src).str()); } void ConfigBase::set_deserialize(std::initializer_list<SetDeserializeItem> items) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index f02caf226..87e020898 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -56,10 +56,9 @@ public: class BadOptionTypeException : public std::runtime_error { public: - BadOptionTypeException() : - std::runtime_error("Bad option type exception") {} - BadOptionTypeException(const char* message) : - std::runtime_error(message) {} + BadOptionTypeException() : std::runtime_error("Bad option type exception") {} + BadOptionTypeException(const std::string &message) : std::runtime_error(message) {} + BadOptionTypeException(const char* message) : std::runtime_error(message) {} }; // Type of a configuration value. diff --git a/src/libslic3r/GCode/ToolOrdering.cpp b/src/libslic3r/GCode/ToolOrdering.cpp index 9bdda3a4c..db398f06c 100644 --- a/src/libslic3r/GCode/ToolOrdering.cpp +++ b/src/libslic3r/GCode/ToolOrdering.cpp @@ -94,7 +94,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude // Reorder the extruders to minimize tool switches. this->reorder_extruders(first_extruder); - this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height); + this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, object.config().layer_height); this->collect_extruder_statistics(prime_multi_material); } @@ -107,6 +107,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool // Initialize the print layers for all objects and all layers. coordf_t object_bottom_z = 0.; + coordf_t max_layer_height = 0.; { std::vector<coordf_t> zs; for (auto object : print.objects()) { @@ -122,6 +123,8 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool object_bottom_z = layer->print_z - layer->height; break; } + + max_layer_height = std::max(max_layer_height, object->config().layer_height.value); } this->initialize_layers(zs); } @@ -144,7 +147,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool // Reorder the extruders to minimize tool switches. this->reorder_extruders(first_extruder); - this->fill_wipe_tower_partitions(print.config(), object_bottom_z); + this->fill_wipe_tower_partitions(print.config(), object_bottom_z, max_layer_height); this->collect_extruder_statistics(prime_multi_material); } @@ -318,7 +321,7 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id) } } -void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z) +void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_object_layer_height) { if (m_layer_tools.empty()) return; @@ -351,6 +354,10 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_ mlh = 0.75 * config.nozzle_diameter.values[i]; max_layer_height = std::min(max_layer_height, mlh); } + // The Prusa3D Fast (0.35mm layer height) print profile sets a higher layer height than what is normally allowed + // by the nozzle. This is a hack and it works by increasing extrusion width. + max_layer_height = std::max(max_layer_height, max_object_layer_height); + for (size_t i = 0; i + 1 < m_layer_tools.size(); ++ i) { const LayerTools < = m_layer_tools[i]; const LayerTools <_next = m_layer_tools[i + 1]; @@ -393,21 +400,47 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_ // and maybe other problems. We will therefore go through layer_tools and detect and fix this. // So, if there is a non-object layer starting with different extruder than the last one ended with (or containing more than one extruder), // we'll mark it with has_wipe tower. - for (unsigned int i=0; i+1<m_layer_tools.size(); ++i) { - LayerTools& lt = m_layer_tools[i]; - LayerTools& lt_next = m_layer_tools[i+1]; - if (lt.extruders.empty() || lt_next.extruders.empty()) - break; - if (!lt_next.has_wipe_tower && (lt_next.extruders.front() != lt.extruders.back() || lt_next.extruders.size() > 1)) - lt_next.has_wipe_tower = true; - // We should also check that the next wipe tower layer is no further than max_layer_height: - unsigned int j = i+1; - double last_wipe_tower_print_z = lt_next.print_z; - while (++j < m_layer_tools.size()-1 && !m_layer_tools[j].has_wipe_tower) - if (m_layer_tools[j+1].print_z - last_wipe_tower_print_z > max_layer_height) { - m_layer_tools[j].has_wipe_tower = true; - last_wipe_tower_print_z = m_layer_tools[j].print_z; + assert(! m_layer_tools.empty() && m_layer_tools.front().has_wipe_tower); + if (! m_layer_tools.empty() && m_layer_tools.front().has_wipe_tower) { + for (size_t i = 0; i + 1 < m_layer_tools.size();) { + const LayerTools < = m_layer_tools[i]; + assert(lt.has_wipe_tower); + assert(! lt.extruders.empty()); + // Find the next layer with wipe tower or mark a layer as such. + size_t j = i + 1; + for (; j < m_layer_tools.size() && ! m_layer_tools[j].has_wipe_tower; ++ j) { + LayerTools <_next = m_layer_tools[j]; + if (lt_next.extruders.empty()) { + //FIXME Vojtech: Lukasi, proc? + j = m_layer_tools.size(); + break; + } + if (lt_next.extruders.front() != lt.extruders.back() || lt_next.extruders.size() > 1) { + // Support only layer, soluble layers? Otherwise the layer should have been already marked as having wipe tower. + assert(lt_next.has_support && ! lt_next.has_object); + lt_next.has_wipe_tower = true; + break; + } } + if (j == m_layer_tools.size()) + // No wipe tower above layer i, therefore no need to add any wipe tower layer above i. + break; + // We should also check that the next wipe tower layer is no further than max_layer_height. + // This algorith may in theory create very thin wipe layer j if layer closely below j is marked as wipe tower. + // This may happen if printing with non-soluble break away supports. + // On the other side it should not hurt as there will be no wipe, just perimeter and sparse infill printed + // at that particular wipe tower layer without extruder change. + double last_wipe_tower_print_z = lt.print_z; + assert(m_layer_tools[j].has_wipe_tower); + for (size_t k = i + 1; k < j; ++k) { + assert(! m_layer_tools[k].has_wipe_tower); + if (m_layer_tools[k + 1].print_z - last_wipe_tower_print_z > max_layer_height + EPSILON) { + m_layer_tools[k].has_wipe_tower = true; + last_wipe_tower_print_z = m_layer_tools[k].print_z; + } + } + i = j; + } } // Calculate the wipe_tower_layer_height values. diff --git a/src/libslic3r/GCode/ToolOrdering.hpp b/src/libslic3r/GCode/ToolOrdering.hpp index a82db2d04..5fe27516d 100644 --- a/src/libslic3r/GCode/ToolOrdering.hpp +++ b/src/libslic3r/GCode/ToolOrdering.hpp @@ -166,7 +166,7 @@ private: void initialize_layers(std::vector<coordf_t> &zs); void collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches); void reorder_extruders(unsigned int last_extruder_id); - void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z); + void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height); void collect_extruder_statistics(bool prime_multi_material); std::vector<LayerTools> m_layer_tools; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 3895a87a1..c66cca8ea 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -44,5 +44,21 @@ // Enable fix for dragging mouse event handling for gizmobar #define ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX (1 && ENABLE_2_2_0_FINAL) +//============ +// 2.3.0 techs +//============ +#define ENABLE_2_3_0 1 + +// Enable rendering of objects colored by facets' slope +#define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_3_0) + +//=================== +// 2.3.0.alpha1 techs +//=================== +#define ENABLE_2_3_0_ALPHA1 1 + +// Moves GLCanvas3DManager from being a static member of _3DScene to be a normal member of GUI_App +#define ENABLE_NON_STATIC_CANVAS_MANAGER (1 && ENABLE_2_3_0_ALPHA1) + #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index bf6f23cac..c13c1b937 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -394,6 +394,7 @@ void GLVolume::render() const glFrontFace(GL_CCW); } +#if !ENABLE_SLOPE_RENDERING void GLVolume::render(int color_id, int detection_id, int worldmatrix_id) const { if (color_id >= 0) @@ -409,6 +410,7 @@ void GLVolume::render(int color_id, int detection_id, int worldmatrix_id) const render(); } +#endif // !ENABLE_SLOPE_RENDERING bool GLVolume::is_sla_support() const { return this->composite_id.volume_id == -int(slaposSupportTree); } bool GLVolume::is_sla_pad() const { return this->composite_id.volume_id == -int(slaposPad); } @@ -650,28 +652,64 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1; GLint z_range_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "z_range") : -1; GLint clipping_plane_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "clipping_plane") : -1; + GLint print_box_min_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.min") : -1; GLint print_box_max_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.max") : -1; - GLint print_box_detection_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_detection") : -1; + GLint print_box_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.active") : -1; GLint print_box_worldmatrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_world_matrix") : -1; + +#if ENABLE_SLOPE_RENDERING + GLint slope_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.active") : -1; + GLint slope_normal_matrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.volume_world_normal_matrix") : -1; + GLint slope_z_range_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.z_range") : -1; +#endif // ENABLE_SLOPE_RENDERING glcheck(); if (print_box_min_id != -1) - glsafe(::glUniform3fv(print_box_min_id, 1, (const GLfloat*)print_box_min)); + glsafe(::glUniform3fv(print_box_min_id, 1, (const GLfloat*)m_print_box_min)); if (print_box_max_id != -1) - glsafe(::glUniform3fv(print_box_max_id, 1, (const GLfloat*)print_box_max)); + glsafe(::glUniform3fv(print_box_max_id, 1, (const GLfloat*)m_print_box_max)); if (z_range_id != -1) - glsafe(::glUniform2fv(z_range_id, 1, (const GLfloat*)z_range)); + glsafe(::glUniform2fv(z_range_id, 1, (const GLfloat*)m_z_range)); if (clipping_plane_id != -1) - glsafe(::glUniform4fv(clipping_plane_id, 1, (const GLfloat*)clipping_plane)); + glsafe(::glUniform4fv(clipping_plane_id, 1, (const GLfloat*)m_clipping_plane)); + +#if ENABLE_SLOPE_RENDERING + if (slope_z_range_id != -1) + glsafe(::glUniform2fv(slope_z_range_id, 1, (const GLfloat*)m_slope.z_range.data())); +#endif // ENABLE_SLOPE_RENDERING GLVolumeWithIdAndZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); for (GLVolumeWithIdAndZ& volume : to_render) { volume.first->set_render_color(); +#if ENABLE_SLOPE_RENDERING + if (color_id >= 0) + glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)volume.first->render_color)); + else + glsafe(::glColor4fv(volume.first->render_color)); + + if (print_box_active_id != -1) + glsafe(::glUniform1i(print_box_active_id, volume.first->shader_outside_printer_detection_enabled ? 1 : 0)); + + if (print_box_worldmatrix_id != -1) + glsafe(::glUniformMatrix4fv(print_box_worldmatrix_id, 1, GL_FALSE, (const GLfloat*)volume.first->world_matrix().cast<float>().data())); + + if (slope_active_id != -1) + glsafe(::glUniform1i(slope_active_id, m_slope.active && !volume.first->is_modifier && !volume.first->is_wipe_tower ? 1 : 0)); + + if (slope_normal_matrix_id != -1) + { + Matrix3f normal_matrix = volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>(); + glsafe(::glUniformMatrix3fv(slope_normal_matrix_id, 1, GL_FALSE, (const GLfloat*)normal_matrix.data())); + } + + volume.first->render(); +#else volume.first->render(color_id, print_box_detection_id, print_box_worldmatrix_id); +#endif // ENABLE_SLOPE_RENDERING } glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); @@ -1816,7 +1854,9 @@ void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height thick_point_to_verts(point, width, height, volume); } +#if !ENABLE_NON_STATIC_CANVAS_MANAGER GUI::GLCanvas3DManager _3DScene::s_canvas_mgr; +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER GLModel::GLModel() : m_filename("") @@ -1885,7 +1925,16 @@ void GLModel::render() const GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1; glcheck(); +#if ENABLE_SLOPE_RENDERING + if (color_id >= 0) + glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)m_volume.render_color)); + else + glsafe(::glColor4fv(m_volume.render_color)); + + m_volume.render(); +#else m_volume.render(color_id, -1, -1); +#endif // ENABLE_SLOPE_RENDERING glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); @@ -2099,6 +2148,7 @@ bool GLBed::on_init_from_file(const std::string& filename) return true; } +#if !ENABLE_NON_STATIC_CANVAS_MANAGER std::string _3DScene::get_gl_info(bool format_as_html, bool extensions) { return Slic3r::GUI::GLCanvas3DManager::get_gl_info().to_string(format_as_html, extensions); @@ -2133,5 +2183,6 @@ GUI::GLCanvas3D* _3DScene::get_canvas(wxGLCanvas* canvas) { return s_canvas_mgr.get_canvas(canvas); } +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER } // namespace Slic3r diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 1fc8308f7..70d6fb016 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -7,7 +7,9 @@ #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/Model.hpp" +#if !ENABLE_NON_STATIC_CANVAS_MANAGER #include "slic3r/GUI/GLCanvas3DManager.hpp" +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER #include <functional> @@ -443,7 +445,9 @@ public: void set_range(double low, double high); void render() const; +#if !ENABLE_SLOPE_RENDERING void render(int color_id, int detection_id, int worldmatrix_id) const; +#endif // !ENABLE_SLOPE_RENDERING void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); } void release_geometry() { this->indexed_vertex_array.release_geometry(); } @@ -479,20 +483,36 @@ public: private: // min and max vertex of the print box volume - float print_box_min[3]; - float print_box_max[3]; + float m_print_box_min[3]; + float m_print_box_max[3]; // z range for clipping in shaders - float z_range[2]; + float m_z_range[2]; // plane coeffs for clipping in shaders - float clipping_plane[4]; + float m_clipping_plane[4]; + +#if ENABLE_SLOPE_RENDERING + struct Slope + { + // toggle for slope rendering + bool active{ false }; + // [0] = yellow, [1] = red + std::array<float, 2> z_range; + }; + + Slope m_slope; +#endif // ENABLE_SLOPE_RENDERING public: GLVolumePtrs volumes; - GLVolumeCollection() {}; - ~GLVolumeCollection() { clear(); }; +#if ENABLE_SLOPE_RENDERING + GLVolumeCollection() { set_default_slope_z_range(); } +#else + GLVolumeCollection() = default; +#endif // ENABLE_SLOPE_RENDERING + ~GLVolumeCollection() { clear(); } std::vector<int> load_object( const ModelObject *model_object, @@ -543,12 +563,21 @@ public: void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); } void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z) { - print_box_min[0] = min_x; print_box_min[1] = min_y; print_box_min[2] = min_z; - print_box_max[0] = max_x; print_box_max[1] = max_y; print_box_max[2] = max_z; + m_print_box_min[0] = min_x; m_print_box_min[1] = min_y; m_print_box_min[2] = min_z; + m_print_box_max[0] = max_x; m_print_box_max[1] = max_y; m_print_box_max[2] = max_z; } - void set_z_range(float min_z, float max_z) { z_range[0] = min_z; z_range[1] = max_z; } - void set_clipping_plane(const double* coeffs) { clipping_plane[0] = coeffs[0]; clipping_plane[1] = coeffs[1]; clipping_plane[2] = coeffs[2]; clipping_plane[3] = coeffs[3]; } + void set_z_range(float min_z, float max_z) { m_z_range[0] = min_z; m_z_range[1] = max_z; } + void set_clipping_plane(const double* coeffs) { m_clipping_plane[0] = coeffs[0]; m_clipping_plane[1] = coeffs[1]; m_clipping_plane[2] = coeffs[2]; m_clipping_plane[3] = coeffs[3]; } + +#if ENABLE_SLOPE_RENDERING + bool is_slope_active() const { return m_slope.active; } + void set_slope_active(bool active) { m_slope.active = active; } + + const std::array<float, 2>& get_slope_z_range() const { return m_slope.z_range; } + void set_slope_z_range(const std::array<float, 2>& range) { m_slope.z_range = range; } + void set_default_slope_z_range() { m_slope.z_range = { -::cos(Geometry::deg2rad(90.0f - 45.0f)), -::cos(Geometry::deg2rad(90.0f - 70.0f)) }; } +#endif // ENABLE_SLOPE_RENDERING // returns true if all the volumes are completely contained in the print volume // returns the containment state in the given out_state, if non-null @@ -639,10 +668,17 @@ protected: bool on_init_from_file(const std::string& filename) override; }; +#if ENABLE_NON_STATIC_CANVAS_MANAGER +struct _3DScene +#else class _3DScene +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { +#if !ENABLE_NON_STATIC_CANVAS_MANAGER static GUI::GLCanvas3DManager s_canvas_mgr; +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER +#if !ENABLE_NON_STATIC_CANVAS_MANAGER public: static std::string get_gl_info(bool format_as_html, bool extensions); @@ -654,6 +690,7 @@ public: static void destroy(); static GUI::GLCanvas3D* get_canvas(wxGLCanvas* canvas); +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume); static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 3cd1319b5..f67fea7a5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -20,6 +20,9 @@ #include "slic3r/GUI/PresetBundle.hpp" #include "slic3r/GUI/Tab.hpp" #include "slic3r/GUI/GUI_Preview.hpp" +#if ENABLE_NON_STATIC_CANVAS_MANAGER +#include "slic3r/GUI/GLCanvas3DManager.hpp" +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #include "slic3r/GUI/3DBed.hpp" #include "slic3r/GUI/Camera.hpp" @@ -359,7 +362,11 @@ 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(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER return Rect((half_w - thickness_bar_width(canvas)) * inv_zoom, half_h * inv_zoom, half_w * inv_zoom, -half_h * inv_zoom); } @@ -774,6 +781,13 @@ bool GLCanvas3D::WarningTexture::generate(const std::string& msg_utf8, const GLC #else // select default font const float scale = canvas.get_canvas_size().get_scale_factor(); +#if ENABLE_RETINA_GL + // For non-visible or non-created window getBackingScaleFactor function return 0.0 value. + // And using of the zero scale causes a crash, when we trying to draw text to the (0,0) rectangle + // https://github.com/prusa3d/PrusaSlicer/issues/3916 + if (scale <= 0.0f) + return false; +#endif wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scale(scale); #endif @@ -851,7 +865,11 @@ 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(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER 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; float right = left + (float)m_original_width * inv_zoom; @@ -1218,7 +1236,11 @@ 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(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float inv_zoom = (float)canvas.get_camera().get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER float left = (-0.5f * (float)cnv_size.get_width()) * inv_zoom; float top = (0.5f * (float)cnv_size.get_height()) * inv_zoom; float right = left + (float)m_original_width * inv_zoom; @@ -1244,7 +1266,11 @@ void GLCanvas3D::Labels::render(const std::vector<const ModelInstance*>& sorted_ if (!m_enabled || !is_shown()) return; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const Camera& camera = wxGetApp().plater()->get_camera(); +#else const Camera& camera = m_canvas.get_camera(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER const Model* model = m_canvas.get_model(); if (model == nullptr) return; @@ -1426,6 +1452,62 @@ void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas } #endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI +#if ENABLE_SLOPE_RENDERING +void GLCanvas3D::Slope::render() const +{ + if (is_shown()) + { + const std::array<float, 2>& z_range = m_volumes.get_slope_z_range(); + std::array<float, 2> angle_range = { Geometry::rad2deg(::acos(z_range[0])) - 90.0f, Geometry::rad2deg(::acos(z_range[1])) - 90.0f }; + bool modified = false; + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + const Size& cnv_size = m_canvas.get_canvas_size(); + imgui.set_next_window_pos((float)cnv_size.get_width(), (float)cnv_size.get_height(), ImGuiCond_Always, 1.0f, 1.0f); + imgui.begin(_(L("Slope visualization")), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + + imgui.text(_(L("Facets' normal angle range (degrees)")) + ":"); + + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.75f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 1.0f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.85f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.25f, 0.0f, 1.0f)); + if (ImGui::SliderFloat("##yellow", &angle_range[0], 0.0f, 90.0f, "%.1f")) + { + modified = true; + if (angle_range[1] < angle_range[0]) + angle_range[1] = angle_range[0]; + } + ImGui::PopStyleColor(4); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.0f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 0.0f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.0f, 0.0f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.0f, 0.0f, 1.0f)); + if (ImGui::SliderFloat("##red", &angle_range[1], 0.0f, 90.0f, "%.1f")) + { + modified = true; + if (angle_range[0] > angle_range[1]) + angle_range[0] = angle_range[1]; + } + ImGui::PopStyleColor(4); + + ImGui::Separator(); + + if (imgui.button(_(L("Default")))) + m_volumes.set_default_slope_z_range(); + + // to let the dialog immediately showup without waiting for a mouse move + if (ImGui::GetWindowContentRegionWidth() + 2.0f * ImGui::GetStyle().WindowPadding.x != ImGui::CalcWindowExpectedSize(ImGui::GetCurrentWindow()).x) + m_canvas.request_extra_frame(); + + imgui.end(); + + if (modified) + m_volumes.set_slope_z_range({ -::cos(Geometry::deg2rad(90.0f - angle_range[0])), -::cos(Geometry::deg2rad(90.0f - angle_range[1])) }); + } + } +#endif // ENABLE_SLOPE_RENDERING + wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent); @@ -1458,16 +1540,22 @@ wxDEFINE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent); const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25; +#if ENABLE_NON_STATIC_CANVAS_MANAGER +GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) +#else GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar) +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER : m_canvas(canvas) , m_context(nullptr) #if ENABLE_RETINA_GL , m_retina_helper(nullptr) #endif , m_in_render(false) +#if !ENABLE_NON_STATIC_CANVAS_MANAGER , m_bed(bed) , m_camera(camera) , m_view_toolbar(view_toolbar) +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER , m_main_toolbar(GLToolbar::Normal, "Top") , m_undoredo_toolbar(GLToolbar::Normal, "Top") , m_gizmos(*this) @@ -1495,14 +1583,19 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar #endif // ENABLE_RENDER_PICKING_PASS , m_render_sla_auxiliaries(true) , m_labels(*this) +#if ENABLE_SLOPE_RENDERING + , m_slope(*this, m_volumes) +#endif // ENABLE_SLOPE_RENDERING { if (m_canvas != nullptr) { m_timer.SetOwner(m_canvas); #if ENABLE_RETINA_GL m_retina_helper.reset(new RetinaHelper(canvas)); +#if !ENABLE_NON_STATIC_CANVAS_MANAGER // set default view_toolbar icons size equal to GLGizmosManager::Default_Icons_Size m_view_toolbar.set_icons_size(GLGizmosManager::Default_Icons_Size); -#endif +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER +#endif // ENABLE_RETINA_GL } m_selection.set_volumes(&m_volumes.volumes); @@ -1615,6 +1708,18 @@ void GLCanvas3D::reset_volumes() if (!m_initialized) return; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + if (m_volumes.empty()) + return; + + _set_current(); + + m_selection.clear(); + m_volumes.clear(); + m_dirty = true; + + _set_warning_texture(WarningTexture::ObjectOutside, false); +#else _set_current(); if (!m_volumes.empty()) @@ -1625,6 +1730,7 @@ void GLCanvas3D::reset_volumes() } _set_warning_texture(WarningTexture::ObjectOutside, false); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } int GLCanvas3D::check_volumes_outside_state() const @@ -1706,7 +1812,11 @@ void GLCanvas3D::set_model(Model* model) void GLCanvas3D::bed_shape_changed() { refresh_camera_scene_box(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + wxGetApp().plater()->get_camera().requires_zoom_to_bed = true; +#else m_camera.requires_zoom_to_bed = true; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER m_dirty = true; } @@ -1715,6 +1825,15 @@ void GLCanvas3D::set_color_by(const std::string& value) m_color_by = value; } +void GLCanvas3D::refresh_camera_scene_box() +{ +#if ENABLE_NON_STATIC_CANVAS_MANAGER + wxGetApp().plater()->get_camera().set_scene_box(scene_bounding_box()); +#else + m_camera.set_scene_box(scene_bounding_box()); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER +} + BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const { BoundingBoxf3 bb; @@ -1729,7 +1848,11 @@ BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const BoundingBoxf3 GLCanvas3D::scene_bounding_box() const { BoundingBoxf3 bb = volumes_bounding_box(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + bb.merge(wxGetApp().plater()->get_bed().get_bounding_box(true)); +#else bb.merge(m_bed.get_bounding_box(true)); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER if (m_config != nullptr) { @@ -1782,6 +1905,11 @@ bool GLCanvas3D::is_reload_delayed() const void GLCanvas3D::enable_layers_editing(bool enable) { +#if ENABLE_SLOPE_RENDERING + if (enable && m_slope.is_shown()) + m_slope.show(false); +#endif // ENABLE_SLOPE_RENDERING + m_layers_editing.set_enabled(enable); const Selection::IndicesList& idxs = m_selection.get_volume_idxs(); for (unsigned int idx : idxs) @@ -1842,7 +1970,11 @@ void GLCanvas3D::allow_multisample(bool allow) void GLCanvas3D::zoom_to_bed() { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + _zoom_to_box(wxGetApp().plater()->get_bed().get_bounding_box(false)); +#else _zoom_to_box(m_bed.get_bounding_box(false)); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } void GLCanvas3D::zoom_to_volumes() @@ -1860,7 +1992,11 @@ void GLCanvas3D::zoom_to_selection() void GLCanvas3D::select_view(const std::string& direction) { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + wxGetApp().plater()->get_camera().select_view(direction); +#else m_camera.select_view(direction); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER if (m_canvas != nullptr) m_canvas->Refresh(); } @@ -1888,14 +2024,26 @@ void GLCanvas3D::render() return; // ensures this canvas is current and initialized +#if ENABLE_NON_STATIC_CANVAS_MANAGER + if (!_is_shown_on_screen() || !_set_current() || !wxGetApp().init_opengl()) + return; + + if (!is_initialized() && !init()) + return; +#else if (! _is_shown_on_screen() || !_set_current() || !_3DScene::init(m_canvas)) return; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #if ENABLE_RENDER_STATISTICS auto start_time = std::chrono::high_resolution_clock::now(); #endif // ENABLE_RENDER_STATISTICS +#if ENABLE_NON_STATIC_CANVAS_MANAGER + if (wxGetApp().plater()->get_bed().get_shape().empty()) +#else if (m_bed.get_shape().empty()) +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { // this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE post_event(SimpleEvent(EVT_GLCANVAS_UPDATE_BED_SHAPE)); @@ -1907,6 +2055,20 @@ void GLCanvas3D::render() // to preview, this was called before canvas had its final size. It reported zero width // and the viewport was set incorrectly, leading to tripping glAsserts further down // the road (in apply_projection). That's why the minimum size is forced to 10. +#if ENABLE_NON_STATIC_CANVAS_MANAGER + Camera& camera = wxGetApp().plater()->get_camera(); + camera.apply_viewport(0, 0, std::max(10u, (unsigned int)cnv_size.get_width()), std::max(10u, (unsigned int)cnv_size.get_height())); + + if (camera.requires_zoom_to_bed) + { + zoom_to_bed(); + _resize((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height()); + camera.requires_zoom_to_bed = false; + } + + camera.apply_view_matrix(); + camera.apply_projection(_max_bounding_box(true, true)); +#else m_camera.apply_viewport(0, 0, std::max(10u, (unsigned int)cnv_size.get_width()), std::max(10u, (unsigned int)cnv_size.get_height())); if (m_camera.requires_zoom_to_bed) @@ -1918,6 +2080,7 @@ void GLCanvas3D::render() m_camera.apply_view_matrix(); m_camera.apply_projection(_max_bounding_box(true, true)); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER GLfloat position_cam[4] = { 1.0f, 0.0f, 1.0f, 0.0f }; glsafe(::glLightfv(GL_LIGHT1, GL_POSITION, position_cam)); @@ -1947,7 +2110,11 @@ void GLCanvas3D::render() _render_objects(); _render_sla_slices(); _render_selection(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + _render_bed(!camera.is_looking_downward(), true); +#else _render_bed(!m_camera.is_looking_downward(), true); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #if ENABLE_RENDER_SELECTION_CENTER _render_selection_center(); @@ -2016,8 +2183,12 @@ void GLCanvas3D::render() tooltip = m_undoredo_toolbar.get_tooltip(); if (tooltip.empty()) - tooltip = m_view_toolbar.get_tooltip(); - } +#if ENABLE_NON_STATIC_CANVAS_MANAGER + tooltip = wxGetApp().plater()->get_view_toolbar().get_tooltip(); +#else + tooltip = m_view_toolbar.get_tooltip(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + } set_tooltip(tooltip); @@ -2061,8 +2232,13 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, { switch (GLCanvas3DManager::get_framebuffers_type()) { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + case GLCanvas3DManager::EFramebufferType::Arb: { _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; } + case GLCanvas3DManager::EFramebufferType::Ext: { _render_thumbnail_framebuffer_ext(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; } +#else case GLCanvas3DManager::FB_Arb: { _render_thumbnail_framebuffer(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; } case GLCanvas3DManager::FB_Ext: { _render_thumbnail_framebuffer_ext(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; } +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER default: { _render_thumbnail_legacy(thumbnail_data, w, h, printable_only, parts_only, show_bed, transparent_background); break; } } } @@ -2167,8 +2343,15 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if ((m_canvas == nullptr) || (m_config == nullptr) || (m_model == nullptr)) return; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + if (!m_initialized) + return; + + _set_current(); +#else if (m_initialized) _set_current(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER struct ModelVolumeState { ModelVolumeState(const GLVolume* volume) : @@ -2764,8 +2947,13 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt) m_dirty |= m_main_toolbar.update_items_state(); m_dirty |= m_undoredo_toolbar.update_items_state(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + m_dirty |= wxGetApp().plater()->get_view_toolbar().update_items_state(); + bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(wxGetApp().plater()->get_camera()); +#else m_dirty |= m_view_toolbar.update_items_state(); bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(m_camera); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER m_dirty |= mouse3d_controller_applied; if (!m_dirty) @@ -2906,12 +3094,27 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'a': { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; } case 'B': case 'b': { zoom_to_bed(); break; } +#if ENABLE_SLOPE_RENDERING + case 'D': + case 'd': { + if (!is_layers_editing_enabled()) + { + m_slope.show(!m_slope.is_shown()); + m_dirty = true; + } + break; + } +#endif // ENABLE_SLOPE_RENDERING case 'E': case 'e': { m_labels.show(!m_labels.is_shown()); m_dirty = true; break; } case 'I': case 'i': { _update_camera_zoom(1.0); break; } case 'K': +#if ENABLE_NON_STATIC_CANVAS_MANAGER + case 'k': { wxGetApp().plater()->get_camera().select_next_type(); m_dirty = true; break; } +#else case 'k': { m_camera.select_next_type(); m_dirty = true; break; } +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER case 'O': case 'o': { _update_camera_zoom(-1.0); break; } #if ENABLE_RENDER_PICKING_PASS @@ -3038,7 +3241,11 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) Vec3d displacement; if (camera_space) { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + Eigen::Matrix<double, 3, 3, Eigen::DontAlign> inv_view_3x3 = wxGetApp().plater()->get_camera().get_view_matrix().inverse().matrix().block(0, 0, 3, 3); +#else Eigen::Matrix<double, 3, 3, Eigen::DontAlign> inv_view_3x3 = m_camera.get_view_matrix().inverse().matrix().block(0, 0, 3, 3); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER displacement = multiplier * (inv_view_3x3 * direction); displacement(2) = 0.0; } @@ -3364,7 +3571,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) return; } +#if ENABLE_NON_STATIC_CANVAS_MANAGER + if (wxGetApp().plater()->get_view_toolbar().on_mouse(evt, *this)) +#else if (m_view_toolbar.on_mouse(evt, *this)) +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { if (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()) mouse_up_cleanup(); @@ -3527,7 +3738,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // we do not want to translate objects if the user just clicked on an object while pressing shift to remove it from the selection and then drag if (m_selection.contains_volume(get_first_hover_volume_idx())) { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const Camera& camera = wxGetApp().plater()->get_camera(); + if (std::abs(camera.get_dir_forward()(2)) < EPSILON) +#else if (std::abs(m_camera.get_dir_forward()(2)) < EPSILON) +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { // side view -> move selected volumes orthogonally to camera view direction Linef3 ray = mouse_ray(pos); @@ -3540,8 +3756,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) // vector from the starting position to the found intersection Vec3d inters_vec = inters - m_mouse.drag.start_position_3D; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + Vec3d camera_right = camera.get_dir_right(); + Vec3d camera_up = camera.get_dir_up(); +#else Vec3d camera_right = m_camera.get_dir_right(); Vec3d camera_up = m_camera.get_dir_up(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER // finds projection of the vector along the camera axes double projection_x = inters_vec.dot(camera_right); @@ -3591,15 +3812,25 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) const Vec3d rot = (Vec3d(pos.x(), pos.y(), 0.) - m_mouse.drag.start_position_3D) * (PI * TRACKBALLSIZE / 180.); if (wxGetApp().app_config->get("use_free_camera") == "1") // Virtual track ball (similar to the 3DConnexion mouse). +#if ENABLE_NON_STATIC_CANVAS_MANAGER + wxGetApp().plater()->get_camera().rotate_local_around_target(Vec3d(rot.y(), rot.x(), 0.)); +#else m_camera.rotate_local_around_target(Vec3d(rot.y(), rot.x(), 0.)); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER else { - // Forces camera right vector to be parallel to XY plane in case it has been misaligned using the 3D mouse free rotation. - // It is cheaper to call this function right away instead of testing wxGetApp().plater()->get_mouse3d_controller().connected(), - // which checks an atomics (flushes CPU caches). - // See GH issue #3816. + // Forces camera right vector to be parallel to XY plane in case it has been misaligned using the 3D mouse free rotation. + // It is cheaper to call this function right away instead of testing wxGetApp().plater()->get_mouse3d_controller().connected(), + // which checks an atomics (flushes CPU caches). + // See GH issue #3816. +#if ENABLE_NON_STATIC_CANVAS_MANAGER + Camera& camera = wxGetApp().plater()->get_camera(); + camera.recover_from_free_camera(); + camera.rotate_on_sphere(rot.x(), rot.y(), wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); +#else m_camera.recover_from_free_camera(); m_camera.rotate_on_sphere(rot.x(), rot.y(), wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } m_dirty = true; @@ -3615,17 +3846,26 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) float z = 0.0f; const Vec3d& cur_pos = _mouse_to_3d(pos, &z); Vec3d orig = _mouse_to_3d(m_mouse.drag.start_position_2D, &z); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + Camera& camera = wxGetApp().plater()->get_camera(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER if (wxGetApp().app_config->get("use_free_camera") != "1") - // Forces camera right vector to be parallel to XY plane in case it has been misaligned using the 3D mouse free rotation. - // It is cheaper to call this function right away instead of testing wxGetApp().plater()->get_mouse3d_controller().connected(), - // which checks an atomics (flushes CPU caches). - // See GH issue #3816. + // Forces camera right vector to be parallel to XY plane in case it has been misaligned using the 3D mouse free rotation. + // It is cheaper to call this function right away instead of testing wxGetApp().plater()->get_mouse3d_controller().connected(), + // which checks an atomics (flushes CPU caches). + // See GH issue #3816. +#if ENABLE_NON_STATIC_CANVAS_MANAGER + camera.recover_from_free_camera(); + + camera.set_target(camera.get_target() + orig - cur_pos); +#else m_camera.recover_from_free_camera(); m_camera.set_target(m_camera.get_target() + orig - cur_pos); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER m_dirty = true; } - + m_mouse.drag.start_position_2D = pos; } } @@ -4071,7 +4311,12 @@ void GLCanvas3D::update_ui_from_settings() if (new_scaling != orig_scaling) { BOOST_LOG_TRIVIAL(debug) << "GLCanvas3D: Scaling factor: " << new_scaling; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + Camera& camera = wxGetApp().plater()->get_camera(); + camera.set_zoom(camera.get_zoom() * new_scaling / orig_scaling); +#else m_camera.set_zoom(m_camera.get_zoom() * new_scaling / orig_scaling); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER _refresh_if_shown_on_screen(); } #endif @@ -4104,16 +4349,13 @@ Linef3 GLCanvas3D::mouse_ray(const Point& mouse_pos) return Linef3(_mouse_to_3d(mouse_pos, &z0), _mouse_to_3d(mouse_pos, &z1)); } - -void GLCanvas3D::refresh_camera_scene_box() -{ - m_camera.set_scene_box(scene_bounding_box()); -} - - double GLCanvas3D::get_size_proportional_to_max_bed_size(double factor) const { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + return factor * wxGetApp().plater()->get_bed().get_bounding_box(false).max_size(); +#else return factor * m_bed.get_bounding_box(false).max_size(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } void GLCanvas3D::set_cursor(ECursorType type) @@ -4176,7 +4418,11 @@ bool GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x) const ImGuiWrapper* imgui = wxGetApp().imgui(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const float x = pos_x * (float)wxGetApp().plater()->get_camera().get_zoom() + 0.5f * (float)get_canvas_size().get_width(); +#else const float x = pos_x * (float)get_camera().get_zoom() + 0.5f * (float)get_canvas_size().get_width(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER imgui->set_next_window_pos(x, m_undoredo_toolbar.get_height(), ImGuiCond_Always, 0.5f, 0.0f); std::string title = is_undo ? L("Undo History") : L("Redo History"); imgui->begin(_(title), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); @@ -4325,7 +4571,11 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, bool // extends the near and far z of the frustrum to avoid the bed being clipped // box in eye space +#if ENABLE_NON_STATIC_CANVAS_MANAGER + BoundingBoxf3 t_bed_box = wxGetApp().plater()->get_bed().get_bounding_box(true).transformed(camera.get_view_matrix()); +#else BoundingBoxf3 t_bed_box = m_bed.get_bounding_box(true).transformed(camera.get_view_matrix()); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER near_z = -t_bed_box.max(2); far_z = -t_bed_box.min(2); } @@ -4602,7 +4852,11 @@ void GLCanvas3D::_render_thumbnail_legacy(ThumbnailData& thumbnail_data, unsigne #endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT // restore the default framebuffer size to avoid flickering on the 3D scene +#if ENABLE_NON_STATIC_CANVAS_MANAGER + wxGetApp().plater()->get_camera().apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height()); +#else m_camera.apply_viewport(0, 0, cnv_size.get_width(), cnv_size.get_height()); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } bool GLCanvas3D::_init_toolbars() @@ -4956,19 +5210,31 @@ BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_be bb.merge(BoundingBoxf3(sel_bb_center - extend_by, sel_bb_center + extend_by)); } +#if ENABLE_NON_STATIC_CANVAS_MANAGER + bb.merge(wxGetApp().plater()->get_bed().get_bounding_box(include_bed_model)); +#else bb.merge(m_bed.get_bounding_box(include_bed_model)); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER return bb; } void GLCanvas3D::_zoom_to_box(const BoundingBoxf3& box, double margin_factor) { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + wxGetApp().plater()->get_camera().zoom_to_box(box, margin_factor); +#else m_camera.zoom_to_box(box, margin_factor); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER m_dirty = true; } void GLCanvas3D::_update_camera_zoom(double zoom) { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + wxGetApp().plater()->get_camera().update_zoom(zoom); +#else m_camera.update_zoom(zoom); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER m_dirty = true; } @@ -5159,7 +5425,11 @@ void GLCanvas3D::_render_bed(float theta, bool show_axes) const #if ENABLE_RETINA_GL scale_factor = m_retina_helper->get_scale_factor(); #endif // ENABLE_RETINA_GL +#if ENABLE_NON_STATIC_CANVAS_MANAGER + wxGetApp().plater()->get_bed().render(const_cast<GLCanvas3D&>(*this), theta, scale_factor, show_axes); +#else m_bed.render(const_cast<GLCanvas3D&>(*this), theta, scale_factor, show_axes); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } void GLCanvas3D::_render_objects() const @@ -5178,7 +5448,11 @@ void GLCanvas3D::_render_objects() const if (m_config != nullptr) { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false); +#else const BoundingBoxf3& bed_bb = m_bed.get_bounding_box(false); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER 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); } @@ -5194,19 +5468,37 @@ void GLCanvas3D::_render_objects() const m_shader.start_using(); if (m_picking_enabled && !m_gizmos.is_dragging() && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) { int object_id = m_layers_editing.last_object_id; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + m_volumes.render(GLVolumeCollection::Opaque, false, wxGetApp().plater()->get_camera().get_view_matrix(), [object_id](const GLVolume& volume) { + // Which volume to paint without the layer height profile shader? + return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id); + }); +#else m_volumes.render(GLVolumeCollection::Opaque, false, m_camera.get_view_matrix(), [object_id](const GLVolume& volume) { // Which volume to paint without the layer height profile shader? return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id); }); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER // Let LayersEditing handle rendering of the active object using the layer height profile shader. m_layers_editing.render_volumes(*this, this->m_volumes); } else { // do not cull backfaces to show broken geometry, if any +#if ENABLE_NON_STATIC_CANVAS_MANAGER + m_volumes.render(GLVolumeCollection::Opaque, m_picking_enabled, wxGetApp().plater()->get_camera().get_view_matrix(), [this](const GLVolume& volume) { + return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0); + }); +#else m_volumes.render(GLVolumeCollection::Opaque, m_picking_enabled, m_camera.get_view_matrix(), [this](const GLVolume& volume) { return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0); }); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } + +#if ENABLE_NON_STATIC_CANVAS_MANAGER + m_volumes.render(GLVolumeCollection::Transparent, false, wxGetApp().plater()->get_camera().get_view_matrix()); +#else m_volumes.render(GLVolumeCollection::Transparent, false, m_camera.get_view_matrix()); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER m_shader.stop_using(); m_camera_clipping_plane = ClippingPlane::ClipsNothing(); @@ -5236,9 +5528,16 @@ void GLCanvas3D::_render_overlays() const glsafe(::glPushMatrix()); glsafe(::glLoadIdentity()); // ensure that the textures are renderered inside the frustrum +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const Camera& camera = wxGetApp().plater()->get_camera(); + glsafe(::glTranslated(0.0, 0.0, -(camera.get_near_z() + 0.005))); + // ensure that the overlay fits the frustrum near z plane + double gui_scale = camera.get_gui_scale(); +#else glsafe(::glTranslated(0.0, 0.0, -(m_camera.get_near_z() + 0.005))); // ensure that the overlay fits the frustrum near z plane double gui_scale = m_camera.get_gui_scale(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER glsafe(::glScaled(gui_scale, gui_scale, 1.0)); _render_gizmos_overlay(); @@ -5275,6 +5574,10 @@ void GLCanvas3D::_render_overlays() const } m_labels.render(sorted_instances); +#if ENABLE_SLOPE_RENDERING + m_slope.render(); +#endif // ENABLE_SLOPE_RENDERING + glsafe(::glPopMatrix()); } @@ -5301,7 +5604,11 @@ void GLCanvas3D::_render_volumes_for_picking() const glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const Transform3d& view_matrix = wxGetApp().plater()->get_camera().get_view_matrix(); +#else const Transform3d& view_matrix = m_camera.get_view_matrix(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER for (size_t type = 0; type < 2; ++ type) { GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, (type == 0) ? GLVolumeCollection::Opaque : GLVolumeCollection::Transparent, view_matrix); for (const GLVolumeWithIdAndZ& volume : to_render) @@ -5350,7 +5657,11 @@ void GLCanvas3D::_render_main_toolbar() const return; Size cnv_size = get_canvas_size(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float inv_zoom = (float)m_camera.get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; float left = -0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width()) * inv_zoom; @@ -5365,7 +5676,11 @@ void GLCanvas3D::_render_undoredo_toolbar() const return; Size cnv_size = get_canvas_size(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float inv_zoom = (float)m_camera.get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER float top = 0.5f * (float)cnv_size.get_height() * inv_zoom; float left = (m_main_toolbar.get_width() - 0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width())) * inv_zoom; @@ -5375,25 +5690,50 @@ void GLCanvas3D::_render_undoredo_toolbar() const void GLCanvas3D::_render_view_toolbar() const { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + GLToolbar& view_toolbar = wxGetApp().plater()->get_view_toolbar(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + #if ENABLE_RETINA_GL // m_view_toolbar.set_scale(m_retina_helper->get_scale_factor()); const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + view_toolbar.set_scale(scale); //! #ys_FIXME_experiment +#else m_view_toolbar.set_scale(scale); //! #ys_FIXME_experiment +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #else // m_view_toolbar.set_scale(m_canvas->GetContentScaleFactor()); // m_view_toolbar.set_scale(wxGetApp().em_unit()*0.1f); const float size = int(GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale()); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + view_toolbar.set_icons_size(size); //! #ys_FIXME_experiment +#else m_view_toolbar.set_icons_size(size); //! #ys_FIXME_experiment +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #endif // ENABLE_RETINA_GL Size cnv_size = get_canvas_size(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float inv_zoom = (float)m_camera.get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER // places the toolbar on the bottom-left corner of the 3d scene +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float top = (-0.5f * (float)cnv_size.get_height() + view_toolbar.get_height()) * inv_zoom; +#else float top = (-0.5f * (float)cnv_size.get_height() + m_view_toolbar.get_height()) * inv_zoom; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER float left = -0.5f * (float)cnv_size.get_width() * inv_zoom; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + view_toolbar.set_position(top, left); + view_toolbar.render(*this); +#else m_view_toolbar.set_position(top, left); m_view_toolbar.render(*this); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } #if ENABLE_SHOW_CAMERA_TARGET @@ -5672,10 +6012,16 @@ Vec3d GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z) if (m_canvas == nullptr) return Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); - +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const Camera& camera = wxGetApp().plater()->get_camera(); + const std::array<int, 4>& viewport = camera.get_viewport(); + const Transform3d& modelview_matrix = camera.get_view_matrix(); + const Transform3d& projection_matrix = camera.get_projection_matrix(); +#else const std::array<int, 4>& viewport = m_camera.get_viewport(); const Transform3d& modelview_matrix = m_camera.get_view_matrix(); const Transform3d& projection_matrix = m_camera.get_projection_matrix(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER GLint y = viewport[3] - (GLint)mouse_pos(1); GLfloat mouse_z; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 15249b1f2..228095a06 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -28,6 +28,9 @@ class wxMouseEvent; class wxTimerEvent; class wxPaintEvent; class wxGLCanvas; +#if ENABLE_NON_STATIC_CANVAS_MANAGER +class wxGLContext; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER // Support for Retina OpenGL on Mac OS #define ENABLE_RETINA_GL __APPLE__ @@ -404,6 +407,24 @@ private: }; #endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI +#if ENABLE_SLOPE_RENDERING + class Slope + { + bool m_enabled{ false }; + GLCanvas3D& m_canvas; + GLVolumeCollection& m_volumes; + + public: + Slope(GLCanvas3D& canvas, GLVolumeCollection& volumes) : m_canvas(canvas), m_volumes(volumes) {} + + void enable(bool enable) { m_enabled = enable; } + bool is_enabled() const { return m_enabled; } + void show(bool show) { m_volumes.set_slope_active(m_enabled ? show : false); } + bool is_shown() const { return m_volumes.is_slope_active(); } + void render() const; + }; +#endif // ENABLE_SLOPE_RENDERING + public: enum ECursorType : unsigned char { @@ -421,9 +442,11 @@ private: LegendTexture m_legend_texture; WarningTexture m_warning_texture; wxTimer m_timer; +#if !ENABLE_NON_STATIC_CANVAS_MANAGER Bed3D& m_bed; Camera& m_camera; GLToolbar& m_view_toolbar; +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER LayersEditing m_layers_editing; Shader m_shader; Mouse m_mouse; @@ -485,11 +508,22 @@ private: #if ENABLE_CANVAS_TOOLTIP_USING_IMGUI mutable Tooltip m_tooltip; #endif // ENABLE_CANVAS_TOOLTIP_USING_IMGUI +#if ENABLE_SLOPE_RENDERING + Slope m_slope; +#endif // ENABLE_SLOPE_RENDERING public: +#if ENABLE_NON_STATIC_CANVAS_MANAGER + explicit GLCanvas3D(wxGLCanvas* canvas); +#else GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER ~GLCanvas3D(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + bool is_initialized() const { return m_initialized; } +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + void set_context(wxGLContext* context) { m_context = context; } wxGLCanvas* get_wxglcanvas() { return m_canvas; } @@ -536,9 +570,14 @@ public: void set_color_by(const std::string& value); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + void refresh_camera_scene_box(); +#else + void refresh_camera_scene_box() { m_camera.set_scene_box(scene_bounding_box()); } const Camera& get_camera() const { return m_camera; } - const Shader& get_shader() const { return m_shader; } Camera& get_camera() { return m_camera; } +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + const Shader& get_shader() const { return m_shader; } BoundingBoxf3 volumes_bounding_box() const; BoundingBoxf3 scene_bounding_box() const; @@ -562,6 +601,9 @@ public: void enable_undoredo_toolbar(bool enable); void enable_dynamic_background(bool enable); void enable_labels(bool enable) { m_labels.enable(enable); } +#if ENABLE_SLOPE_RENDERING + void enable_slope(bool enable) { m_slope.enable(enable); } +#endif // ENABLE_SLOPE_RENDERING void allow_multisample(bool allow); void zoom_to_bed(); @@ -630,7 +672,9 @@ public: void update_ui_from_settings(); +#if !ENABLE_NON_STATIC_CANVAS_MANAGER float get_view_toolbar_height() const { return m_view_toolbar.get_height(); } +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER int get_move_volume_id() const { return m_mouse.drag.move_volume_idx; } int get_first_hover_volume_idx() const { return m_hover_volume_idxs.empty() ? -1 : m_hover_volume_idxs.front(); } @@ -662,7 +706,6 @@ public: Linef3 mouse_ray(const Point& mouse_pos); void set_mouse_as_dragging() { m_mouse.dragging = true; } - void refresh_camera_scene_box(); bool is_mouse_dragging() const { return m_mouse.dragging; } double get_size_proportional_to_max_bed_size(double factor) const; @@ -684,6 +727,11 @@ public: bool are_labels_shown() const { return m_labels.is_shown(); } void show_labels(bool show) { m_labels.show(show); } +#if ENABLE_SLOPE_RENDERING + bool is_slope_shown() const { return m_slope.is_shown(); } + void show_slope(bool show) { m_slope.show(show); } +#endif // ENABLE_SLOPE_RENDERING + private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index 02585c5f7..d4522bb07 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -1,3 +1,4 @@ +#include "libslic3r/libslic3r.h" #include "GLCanvas3DManager.hpp" #include "../../slic3r/GUI/GUI.hpp" #include "../../slic3r/GUI/AppConfig.hpp" @@ -7,7 +8,9 @@ #include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/classification.hpp> - +#if ENABLE_NON_STATIC_CANVAS_MANAGER +#include <boost/log/trivial.hpp> +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #include <wx/glcanvas.h> #include <wx/timer.h> #include <wx/msgdlg.h> @@ -17,8 +20,10 @@ #include <iostream> #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5 -// Part of temporary hack to remove crash when closing on OSX 10.9.5 +#ifdef __APPLE__ +// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets #include <wx/platinfo.h> +#endif // __APPLE__ #endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5 #ifdef __APPLE__ @@ -28,6 +33,7 @@ namespace Slic3r { namespace GUI { +#if !ENABLE_NON_STATIC_CANVAS_MANAGER GLCanvas3DManager::GLInfo::GLInfo() : m_detected(false) , m_version("") @@ -38,6 +44,7 @@ GLCanvas3DManager::GLInfo::GLInfo() , m_max_anisotropy(0.0f) { } +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER const std::string& GLCanvas3DManager::GLInfo::get_version() const { @@ -196,27 +203,57 @@ std::string GLCanvas3DManager::GLInfo::to_string(bool format_as_html, bool exten return out.str(); } -GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown; -bool GLCanvas3DManager::s_compressed_textures_supported = false; -GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None; GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info; +bool GLCanvas3DManager::s_compressed_textures_supported = false; +#if ENABLE_NON_STATIC_CANVAS_MANAGER +GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::EMultisampleState::Unknown; +GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::EFramebufferType::Unknown; +#else +GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas3DManager::MS_Unknown; +GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5 #ifdef __APPLE__ +// Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets GLCanvas3DManager::OSInfo GLCanvas3DManager::s_os_info; #endif // __APPLE__ #endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5 +#if !ENABLE_NON_STATIC_CANVAS_MANAGER GLCanvas3DManager::GLCanvas3DManager() : m_context(nullptr) , m_gl_initialized(false) { } +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER GLCanvas3DManager::~GLCanvas3DManager() { - this->destroy(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER +#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5 +#ifdef __APPLE__ + // This is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5 with newer wxWidgets + // The crash is triggered inside wxGLContext destructor + if (s_os_info.major != 10 || s_os_info.minor != 9 || s_os_info.micro != 5) + { +#endif //__APPLE__ +#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5 + + if (m_context != nullptr) + delete m_context; + +#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5 +#ifdef __APPLE__ + } +#endif //__APPLE__ +#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5 +#else + this->destroy(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } +#if !ENABLE_NON_STATIC_CANVAS_MANAGER bool GLCanvas3DManager::add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar) { if (canvas == nullptr) @@ -239,7 +276,7 @@ bool GLCanvas3DManager::add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLTo #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5 #ifdef __APPLE__ - // Part of temporary hack to remove crash when closing on OSX 10.9.5 + // Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion(); s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion(); s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion(); @@ -277,28 +314,50 @@ void GLCanvas3DManager::remove_all() m_canvases.clear(); } -unsigned int GLCanvas3DManager::count() const +size_t GLCanvas3DManager::count() const { - return (unsigned int)m_canvases.size(); + return m_canvases.size(); } +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER +#if ENABLE_NON_STATIC_CANVAS_MANAGER +bool GLCanvas3DManager::init_gl() +#else void GLCanvas3DManager::init_gl() +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { if (!m_gl_initialized) { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + if (glewInit() != GLEW_OK) + { + BOOST_LOG_TRIVIAL(error) << "Unable to init glew library"; + return false; + } +#else glewInit(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER m_gl_initialized = true; if (GLEW_EXT_texture_compression_s3tc) s_compressed_textures_supported = true; else s_compressed_textures_supported = false; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + if (GLEW_ARB_framebuffer_object) + s_framebuffers_type = EFramebufferType::Arb; + else if (GLEW_EXT_framebuffer_object) + s_framebuffers_type = EFramebufferType::Ext; + else + s_framebuffers_type = EFramebufferType::Unknown; +#else if (GLEW_ARB_framebuffer_object) s_framebuffers_type = FB_Arb; else if (GLEW_EXT_framebuffer_object) s_framebuffers_type = FB_Ext; else s_framebuffers_type = FB_None; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER if (! s_gl_info.is_version_greater_or_equal_to(2, 0)) { // Complain about the OpenGL version. @@ -314,8 +373,31 @@ void GLCanvas3DManager::init_gl() wxMessageBox(message, wxString("PrusaSlicer - ") + _(L("Unsupported OpenGL version")), wxOK | wxICON_ERROR); } } + +#if ENABLE_NON_STATIC_CANVAS_MANAGER + return true; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } +#if ENABLE_NON_STATIC_CANVAS_MANAGER +wxGLContext* GLCanvas3DManager::init_glcontext(wxGLCanvas& canvas) +{ + if (m_context == nullptr) + { + m_context = new wxGLContext(&canvas); + +#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5 +#ifdef __APPLE__ + // Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets + s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion(); + s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion(); + s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion(); +#endif //__APPLE__ +#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5 + } + return m_context; +} +#else bool GLCanvas3DManager::init(wxGLCanvas* canvas) { CanvasesMap::const_iterator it = do_get_canvas(canvas); @@ -331,7 +413,7 @@ void GLCanvas3DManager::destroy() { #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5 #ifdef __APPLE__ - // this is a temporary ugly hack to solve the crash happening when closing the application on OSX 10.9.5 + // this is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5 // the crash is inside wxGLContext destructor if (s_os_info.major == 10 && s_os_info.minor == 9 && s_os_info.micro == 5) return; @@ -342,14 +424,21 @@ void GLCanvas3DManager::destroy() m_context = nullptr; } } +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER +#if !ENABLE_NON_STATIC_CANVAS_MANAGER GLCanvas3D* GLCanvas3DManager::get_canvas(wxGLCanvas* canvas) { CanvasesMap::const_iterator it = do_get_canvas(canvas); return (it != m_canvases.end()) ? it->second : nullptr; } +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER +#if ENABLE_NON_STATIC_CANVAS_MANAGER +wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow& parent) +#else wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent) +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { int attribList[] = { WX_GL_RGBA, @@ -367,7 +456,11 @@ wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent) 0 }; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + if (s_multisample == EMultisampleState::Unknown) +#else if (s_multisample == MS_Unknown) +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { detect_multisample(attribList); // // debug output @@ -377,9 +470,14 @@ wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent) if (! can_multisample()) attribList[12] = 0; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + return new wxGLCanvas(&parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS); +#else return new wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } +#if !ENABLE_NON_STATIC_CANVAS_MANAGER GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::do_get_canvas(wxGLCanvas* canvas) { return (canvas == nullptr) ? m_canvases.end() : m_canvases.find(canvas); @@ -397,12 +495,17 @@ bool GLCanvas3DManager::init(GLCanvas3D& canvas) return canvas.init(); } +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER void GLCanvas3DManager::detect_multisample(int* attribList) { int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER; bool enable_multisample = wxVersion >= 30003; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? EMultisampleState::Enabled : EMultisampleState::Disabled; +#else s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? MS_Enabled : MS_Disabled; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER // Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows // s_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample"); } diff --git a/src/slic3r/GUI/GLCanvas3DManager.hpp b/src/slic3r/GUI/GLCanvas3DManager.hpp index c7301f2b4..428ccd96a 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -23,22 +23,43 @@ class PrintObject; namespace GUI { class GLCanvas3D; +#if !ENABLE_NON_STATIC_CANVAS_MANAGER class Bed3D; class GLToolbar; struct Camera; +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER class GLCanvas3DManager { public: +#if ENABLE_NON_STATIC_CANVAS_MANAGER + enum class EFramebufferType : unsigned char + { + Unknown, + Arb, + Ext + }; +#else enum EFramebufferType : unsigned char { FB_None, FB_Arb, FB_Ext }; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER class GLInfo { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + mutable bool m_detected{ false }; + mutable int m_max_tex_size{ 0 }; + mutable float m_max_anisotropy{ 0.0f }; + + mutable std::string m_version; + mutable std::string m_glsl_version; + mutable std::string m_vendor; + mutable std::string m_renderer; +#else mutable bool m_detected; mutable std::string m_version; @@ -48,9 +69,14 @@ public: mutable int m_max_tex_size; mutable float m_max_anisotropy; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER public: +#if ENABLE_NON_STATIC_CANVAS_MANAGER + GLInfo() = default; +#else GLInfo(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER const std::string& get_version() const; const std::string& get_glsl_version() const; @@ -70,6 +96,7 @@ public: #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5 #ifdef __APPLE__ + // Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets struct OSInfo { int major{ 0 }; @@ -80,6 +107,14 @@ public: #endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5 private: +#if ENABLE_NON_STATIC_CANVAS_MANAGER + enum class EMultisampleState : unsigned char + { + Unknown, + Enabled, + Disabled + }; +#else enum EMultisampleState : unsigned char { MS_Unknown, @@ -88,51 +123,85 @@ private: }; typedef std::map<wxGLCanvas*, GLCanvas3D*> CanvasesMap; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER - CanvasesMap m_canvases; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + bool m_gl_initialized{ false }; + wxGLContext* m_context{ nullptr }; +#else wxGLContext* m_context; + bool m_gl_initialized; + CanvasesMap m_canvases; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER static GLInfo s_gl_info; #if ENABLE_HACK_CLOSING_ON_OSX_10_9_5 #ifdef __APPLE__ + // Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets static OSInfo s_os_info; #endif //__APPLE__ #endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5 - bool m_gl_initialized; - static EMultisampleState s_multisample; static bool s_compressed_textures_supported; + static EMultisampleState s_multisample; static EFramebufferType s_framebuffers_type; public: +#if ENABLE_NON_STATIC_CANVAS_MANAGER + GLCanvas3DManager() = default; +#else GLCanvas3DManager(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER ~GLCanvas3DManager(); +#if !ENABLE_NON_STATIC_CANVAS_MANAGER bool add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar); bool remove(wxGLCanvas* canvas); void remove_all(); - unsigned int count() const; + size_t count() const; +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER +#if ENABLE_NON_STATIC_CANVAS_MANAGER + bool init_gl(); +#else void init_gl(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER +#if ENABLE_NON_STATIC_CANVAS_MANAGER + wxGLContext* init_glcontext(wxGLCanvas& canvas); +#else bool init(wxGLCanvas* canvas); void destroy(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER +#if !ENABLE_NON_STATIC_CANVAS_MANAGER GLCanvas3D* get_canvas(wxGLCanvas* canvas); +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER - static bool can_multisample() { return s_multisample == MS_Enabled; } static bool are_compressed_textures_supported() { return s_compressed_textures_supported; } +#if ENABLE_NON_STATIC_CANVAS_MANAGER + static bool can_multisample() { return s_multisample == EMultisampleState::Enabled; } + static bool are_framebuffers_supported() { return (s_framebuffers_type != EFramebufferType::Unknown); } +#else + static bool can_multisample() { return s_multisample == MS_Enabled; } static bool are_framebuffers_supported() { return (s_framebuffers_type != FB_None); } +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER static EFramebufferType get_framebuffers_type() { return s_framebuffers_type; } +#if ENABLE_NON_STATIC_CANVAS_MANAGER + static wxGLCanvas* create_wxglcanvas(wxWindow& parent); +#else static wxGLCanvas* create_wxglcanvas(wxWindow *parent); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER static const GLInfo& get_gl_info() { return s_gl_info; } private: +#if !ENABLE_NON_STATIC_CANVAS_MANAGER CanvasesMap::iterator do_get_canvas(wxGLCanvas* canvas); CanvasesMap::const_iterator do_get_canvas(wxGLCanvas* canvas) const; bool init(GLCanvas3D& canvas); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER static void detect_multisample(int* attribList); }; diff --git a/src/slic3r/GUI/GLSelectionRectangle.cpp b/src/slic3r/GUI/GLSelectionRectangle.cpp index 10238c41b..eacf7a153 100644 --- a/src/slic3r/GUI/GLSelectionRectangle.cpp +++ b/src/slic3r/GUI/GLSelectionRectangle.cpp @@ -2,6 +2,9 @@ #include "Camera.hpp" #include "3DScene.hpp" #include "GLCanvas3D.hpp" +#if ENABLE_NON_STATIC_CANVAS_MANAGER +#include "GUI_App.hpp" +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #include <GL/glew.h> @@ -35,7 +38,11 @@ namespace GUI { m_state = Off; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const Camera& camera = wxGetApp().plater()->get_camera(); +#else const Camera& camera = canvas.get_camera(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER const std::array<int, 4>& viewport = camera.get_viewport(); const Transform3d& modelview_matrix = camera.get_view_matrix(); const Transform3d& projection_matrix = camera.get_projection_matrix(); @@ -68,7 +75,11 @@ namespace GUI { if (!is_dragging()) return; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const Camera& camera = wxGetApp().plater()->get_camera(); +#else const Camera& camera = canvas.get_camera(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER float inv_zoom = (float)camera.get_inv_zoom(); Size cnv_size = canvas.get_canvas_size(); diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index f178ddc73..545b066bb 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -2,6 +2,9 @@ #include "GLTexture.hpp" #include "3DScene.hpp" +#if ENABLE_NON_STATIC_CANVAS_MANAGER +#include "GLCanvas3DManager.hpp" +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #include <GL/glew.h> diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index be3d5495e..4219fe482 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -3,8 +3,14 @@ #include "GLToolbar.hpp" +#if ENABLE_NON_STATIC_CANVAS_MANAGER +#include "slic3r/GUI/GLCanvas3D.hpp" +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/Camera.hpp" +#else #include "../../slic3r/GUI/GLCanvas3D.hpp" #include "../../slic3r/GUI/Camera.hpp" +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #include <wx/event.h> #include <wx/bitmap.h> @@ -15,7 +21,6 @@ namespace Slic3r { namespace GUI { - wxDEFINE_EVENT(EVT_GLTOOLBAR_ADD, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_DELETE, SimpleEvent); wxDEFINE_EVENT(EVT_GLTOOLBAR_DELETE_ALL, SimpleEvent); @@ -718,7 +723,11 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC { // NB: mouse_pos is already scaled appropriately +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float inv_zoom = (float)parent.get_camera().get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER float factor = m_layout.scale * inv_zoom; Size cnv_size = parent.get_canvas_size(); @@ -859,7 +868,11 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan { // NB: mouse_pos is already scaled appropriately +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float inv_zoom = (float)parent.get_camera().get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER float factor = m_layout.scale * inv_zoom; Size cnv_size = parent.get_canvas_size(); @@ -1008,7 +1021,11 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3 { // NB: mouse_pos is already scaled appropriately +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float inv_zoom = (float)parent.get_camera().get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER float factor = m_layout.scale * inv_zoom; Size cnv_size = parent.get_canvas_size(); @@ -1081,7 +1098,11 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& { // NB: mouse_pos is already scaled appropriately +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float inv_zoom = (float)parent.get_camera().get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER float factor = m_layout.scale * inv_zoom; Size cnv_size = parent.get_canvas_size(); @@ -1233,7 +1254,11 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const int tex_width = m_icons_texture.get_width(); int tex_height = m_icons_texture.get_height(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float inv_zoom = (float)parent.get_camera().get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER float factor = inv_zoom * m_layout.scale; float scaled_icons_size = m_layout.icons_size * factor; @@ -1281,7 +1306,11 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const int tex_width = m_icons_texture.get_width(); int tex_height = m_icons_texture.get_height(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float inv_zoom = (float)parent.get_camera().get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER float factor = inv_zoom * m_layout.scale; float scaled_icons_size = m_layout.icons_size * factor; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index f44efa130..f5a4a3d92 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -50,8 +50,8 @@ #include "RemovableDriveManager.hpp" #ifdef __WXMSW__ -#include <Shlobj.h> #include <dbt.h> +#include <shlobj.h> #endif // __WXMSW__ #if ENABLE_THUMBNAIL_GENERATOR_DEBUG @@ -158,6 +158,41 @@ static void register_win32_device_notification_event() } return true; }); + + wxWindow::MSWRegisterMessageHandler(MainFrame::WM_USER_MEDIACHANGED, [](wxWindow *win, WXUINT /* nMsg */, WXWPARAM wParam, WXLPARAM lParam) { + // Some messages are sent to top level windows by default, some messages are sent to only registered windows, and we explictely register on MainFrame only. + auto main_frame = dynamic_cast<MainFrame*>(win); + auto plater = (main_frame == nullptr) ? nullptr : main_frame->plater(); + if (plater == nullptr) + // Maybe some other top level window like a dialog or maybe a pop-up menu? + return true; + wchar_t sPath[MAX_PATH]; + if (lParam == SHCNE_MEDIAINSERTED || lParam == SHCNE_MEDIAREMOVED) { + struct _ITEMIDLIST* pidl = *reinterpret_cast<struct _ITEMIDLIST**>(wParam); + if (! SHGetPathFromIDList(pidl, sPath)) { + BOOST_LOG_TRIVIAL(error) << "MediaInserted: SHGetPathFromIDList failed"; + return false; + } + } + switch (lParam) { + case SHCNE_MEDIAINSERTED: + { + //printf("SHCNE_MEDIAINSERTED %S\n", sPath); + plater->GetEventHandler()->AddPendingEvent(VolumeAttachedEvent(EVT_VOLUME_ATTACHED)); + break; + } + case SHCNE_MEDIAREMOVED: + { + //printf("SHCNE_MEDIAREMOVED %S\n", sPath); + plater->GetEventHandler()->AddPendingEvent(VolumeDetachedEvent(EVT_VOLUME_DETACHED)); + break; + } + default: +// printf("Unknown\n"); + break; + } + return true; + }); } #endif // WIN32 @@ -216,6 +251,23 @@ GUI_App::~GUI_App() delete preset_updater; } +#if ENABLE_NON_STATIC_CANVAS_MANAGER +std::string GUI_App::get_gl_info(bool format_as_html, bool extensions) +{ + return GLCanvas3DManager::get_gl_info().to_string(format_as_html, extensions); +} + +wxGLContext* GUI_App::init_glcontext(wxGLCanvas& canvas) +{ + return m_canvas_mgr.init_glcontext(canvas); +} + +bool GUI_App::init_opengl() +{ + return m_canvas_mgr.init_gl(); +} +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + bool GUI_App::OnInit() { try { @@ -667,15 +719,16 @@ bool GUI_App::select_language() // Try to load a new language. if (index != -1 && (init_selection == -1 || init_selection != index)) { const wxLanguageInfo *new_language_info = language_infos[index]; - if (new_language_info == m_language_info_best || new_language_info == m_language_info_system) { - // The newly selected profile matches user's default profile exactly. That's great. - } else if (m_language_info_best != nullptr && new_language_info->CanonicalName.BeforeFirst('_') == m_language_info_best->CanonicalName.BeforeFirst('_')) - new_language_info = m_language_info_best; - else if (m_language_info_system != nullptr && new_language_info->CanonicalName.BeforeFirst('_') == m_language_info_system->CanonicalName.BeforeFirst('_')) - new_language_info = m_language_info_system; if (this->load_language(new_language_info->CanonicalName, false)) { // Save language at application config. - app_config->set("translation_language", m_wxLocale->GetCanonicalName().ToUTF8().data()); + // Which language to save as the selected dictionary language? + // 1) Hopefully the language set to wxTranslations by this->load_language(), but that API is weird and we don't want to rely on its + // stability in the future: + // wxTranslations::Get()->GetBestTranslation(SLIC3R_APP_KEY, wxLANGUAGE_ENGLISH); + // 2) Current locale language may not match the dictionary name, see GH issue #3901 + // m_wxLocale->GetCanonicalName() + // 3) new_language_info->CanonicalName is a safe bet. It points to a valid dictionary name. + app_config->set("translation_language", new_language_info->CanonicalName.ToUTF8().data()); app_config->save(); return true; } @@ -704,7 +757,6 @@ bool GUI_App::load_language(wxString language, bool initial) BOOST_LOG_TRIVIAL(trace) << boost::format("System language detected (user locales and such): %1%") % m_language_info_system->CanonicalName.ToUTF8().data(); } } -#if defined(__WXMSW__) || defined(__WXOSX__) { // Allocating a temporary locale will switch the default wxTranslations to its internal wxTranslations instance. wxLocale temp_locale; @@ -721,7 +773,6 @@ bool GUI_App::load_language(wxString language, bool initial) BOOST_LOG_TRIVIAL(trace) << boost::format("Best translation language detected (may be different from user locales): %1%") % m_language_info_best->CanonicalName.ToUTF8().data(); } } -#endif } const wxLanguageInfo *language_info = language.empty() ? nullptr : wxLocale::FindLanguageInfo(language); @@ -737,6 +788,7 @@ bool GUI_App::load_language(wxString language, bool initial) } if (language_info == nullptr) { + // PrusaSlicer does not support the Right to Left languages yet. if (m_language_info_system != nullptr && m_language_info_system->LayoutDirection != wxLayout_RightToLeft) language_info = m_language_info_system; if (m_language_info_best != nullptr && m_language_info_best->LayoutDirection != wxLayout_RightToLeft) @@ -755,6 +807,16 @@ bool GUI_App::load_language(wxString language, bool initial) BOOST_LOG_TRIVIAL(trace) << "Using Czech dictionaries for Slovak language"; } + // Select language for locales. This language may be different from the language of the dictionary. + if (language_info == m_language_info_best || language_info == m_language_info_system) { + // The current language matches user's default profile exactly. That's great. + } else if (m_language_info_best != nullptr && language_info->CanonicalName.BeforeFirst('_') == m_language_info_best->CanonicalName.BeforeFirst('_')) { + // Use whatever the operating system recommends, if it the language code of the dictionary matches the recommended language. + // This allows a Swiss guy to use a German dictionary without forcing him to German locales. + language_info = m_language_info_best; + } else if (m_language_info_system != nullptr && language_info->CanonicalName.BeforeFirst('_') == m_language_info_system->CanonicalName.BeforeFirst('_')) + language_info = m_language_info_system; + if (! wxLocale::IsAvailable(language_info->Language)) { // Loading the language dictionary failed. wxString message = "Switching PrusaSlicer to language " + language_info->CanonicalName + " failed."; @@ -781,7 +843,7 @@ bool GUI_App::load_language(wxString language, bool initial) wxTranslations::Get()->SetLanguage(language_dict); m_wxLocale->AddCatalog(SLIC3R_APP_KEY); m_imgui->set_language(into_u8(language_info->CanonicalName)); - //FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only. + //FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only. wxSetlocale(LC_NUMERIC, "C"); Preset::update_suffix_modified(); return true; diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index d02a60ba9..bf75eaaa6 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -7,6 +7,9 @@ #include "MainFrame.hpp" #include "ImGuiWrapper.hpp" #include "ConfigWizard.hpp" +#if ENABLE_NON_STATIC_CANVAS_MANAGER +#include "GLCanvas3DManager.hpp" +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #include <wx/app.h> #include <wx/colour.h> @@ -96,7 +99,11 @@ class GUI_App : public wxApp // Best translation language, provided by Windows or OSX, owned by wxWidgets. const wxLanguageInfo *m_language_info_best = nullptr; - std::unique_ptr<RemovableDriveManager> m_removable_drive_manager; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + GLCanvas3DManager m_canvas_mgr; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + + std::unique_ptr<RemovableDriveManager> m_removable_drive_manager; std::unique_ptr<ImGuiWrapper> m_imgui; std::unique_ptr<PrintHostJobQueue> m_printhost_job_queue; @@ -109,6 +116,12 @@ public: GUI_App(); ~GUI_App() override; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + static std::string get_gl_info(bool format_as_html, bool extensions); + wxGLContext* init_glcontext(wxGLCanvas& canvas); + bool init_opengl(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + static unsigned get_colour_approx_luma(const wxColour &colour); static bool dark_mode(); void init_label_colours(); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 1ae73a192..29ece9b31 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -27,31 +27,63 @@ namespace Slic3r { namespace GUI { +#if ENABLE_NON_STATIC_CANVAS_MANAGER +View3D::View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) + : m_canvas_widget(nullptr) + , m_canvas(nullptr) +{ + init(parent, model, config, process); +} +#else View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) : m_canvas_widget(nullptr) , m_canvas(nullptr) { init(parent, bed, camera, view_toolbar, model, config, process); } +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER View3D::~View3D() { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + if (m_canvas != nullptr) + delete m_canvas; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + if (m_canvas_widget != nullptr) { +#if !ENABLE_NON_STATIC_CANVAS_MANAGER _3DScene::remove_canvas(m_canvas_widget); +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER delete m_canvas_widget; +#if !ENABLE_NON_STATIC_CANVAS_MANAGER m_canvas = nullptr; +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER } } +#if ENABLE_NON_STATIC_CANVAS_MANAGER +bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) +#else bool View3D::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process) +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */)) return false; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(*this); + if (m_canvas_widget == nullptr) + return false; + + m_canvas = new GLCanvas3D(m_canvas_widget); + m_canvas->set_context(wxGetApp().init_glcontext(*m_canvas_widget)); + m_canvas->bind_event_handlers(); +#else m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(this); _3DScene::add_canvas(m_canvas_widget, bed, camera, view_toolbar); m_canvas = _3DScene::get_canvas(this->m_canvas_widget); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER m_canvas->allow_multisample(GLCanvas3DManager::can_multisample()); // XXX: If have OpenGL @@ -66,6 +98,9 @@ bool View3D::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_ m_canvas->enable_main_toolbar(true); m_canvas->enable_undoredo_toolbar(true); m_canvas->enable_labels(true); +#if ENABLE_SLOPE_RENDERING + m_canvas->enable_slope(true); +#endif // ENABLE_SLOPE_RENDERING wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL); main_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0); @@ -163,9 +198,15 @@ void View3D::render() m_canvas->set_as_dirty(); } +#if ENABLE_NON_STATIC_CANVAS_MANAGER +Preview::Preview( + wxWindow* parent, Model* model, DynamicPrintConfig* config, + BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func) +#else Preview::Preview( wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func) +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER : m_canvas_widget(nullptr) , m_canvas(nullptr) , m_double_slider_sizer(nullptr) @@ -190,21 +231,39 @@ Preview::Preview( , m_volumes_cleanup_required(false) #endif // __linux__ { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + if (init(parent, model)) +#else if (init(parent, bed, camera, view_toolbar, model)) +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { show_hide_ui_elements("none"); load_print(); } } +#if ENABLE_NON_STATIC_CANVAS_MANAGER +bool Preview::init(wxWindow* parent, Model* model) +#else bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model) +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */)) return false; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(*this); + if (m_canvas_widget == nullptr) + return false; + + m_canvas = new GLCanvas3D(m_canvas_widget); + m_canvas->set_context(wxGetApp().init_glcontext(*m_canvas_widget)); + m_canvas->bind_event_handlers(); +#else m_canvas_widget = GLCanvas3DManager::create_wxglcanvas(this); _3DScene::add_canvas(m_canvas_widget, bed, camera, view_toolbar); m_canvas = _3DScene::get_canvas(this->m_canvas_widget); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER m_canvas->allow_multisample(GLCanvas3DManager::can_multisample()); m_canvas->set_config(m_config); m_canvas->set_model(model); @@ -313,9 +372,16 @@ Preview::~Preview() { unbind_event_handlers(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + if (m_canvas != nullptr) + delete m_canvas; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + if (m_canvas_widget != nullptr) { - _3DScene::remove_canvas(m_canvas_widget); +#if !ENABLE_NON_STATIC_CANVAS_MANAGER + _3DScene::remove_canvas(m_canvas_widget); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER delete m_canvas_widget; m_canvas = nullptr; } diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index cc8f15325..2fe26ede9 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -34,6 +34,9 @@ class GLCanvas3D; class GLToolbar; class Bed3D; struct Camera; +#if ENABLE_NON_STATIC_CANVAS_MANAGER +class Plater; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER class View3D : public wxPanel { @@ -41,7 +44,11 @@ class View3D : public wxPanel GLCanvas3D* m_canvas; public: +#if ENABLE_NON_STATIC_CANVAS_MANAGER + View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process); +#else View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER virtual ~View3D(); wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } @@ -69,7 +76,11 @@ public: void render(); private: +#if ENABLE_NON_STATIC_CANVAS_MANAGER + bool init(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process); +#else bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER }; class Preview : public wxPanel @@ -109,8 +120,13 @@ class Preview : public wxPanel DoubleSlider::Control* m_slider {nullptr}; public: - Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, +#if ENABLE_NON_STATIC_CANVAS_MANAGER + Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config, + BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = []() {}); +#else + Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = [](){}); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER virtual ~Preview(); wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; } @@ -137,7 +153,11 @@ public: bool is_loaded() const { return m_loaded; } private: +#if ENABLE_NON_STATIC_CANVAS_MANAGER + bool init(wxWindow* parent, Model* model); +#else bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER void bind_event_handlers(); void unbind_event_handlers(); @@ -170,7 +190,6 @@ private: void load_print_as_sla(); void on_sliders_scroll_changed(wxCommandEvent& event); - }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 0a3a6f898..51e6d7458 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -10,6 +10,9 @@ #include "slic3r/GUI/GUI_ObjectList.hpp" #include "slic3r/GUI/MeshUtils.hpp" #include "slic3r/GUI/Plater.hpp" +#if ENABLE_NON_STATIC_CANVAS_MANAGER +#include "slic3r/GUI/Camera.hpp" +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #include "slic3r/GUI/PresetBundle.hpp" #include "libslic3r/SLAPrint.hpp" #include "libslic3r/TriangleMesh.hpp" @@ -311,7 +314,11 @@ bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, V if (! m_c->m_mesh_raycaster) return false; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const Camera& camera = wxGetApp().plater()->get_camera(); +#else const Camera& camera = m_parent.get_camera(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER const Selection& selection = m_parent.get_selection(); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); Geometry::Transformation trafo = volume->get_instance_transformation(); @@ -426,7 +433,11 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos points_inside.push_back(points[idx].cast<float>()); // Only select/deselect points that are actually visible +#if ENABLE_NON_STATIC_CANVAS_MANAGER + for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, wxGetApp().plater()->get_camera(), points_inside, m_c->m_clipping_plane.get())) +#else for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_c->m_clipping_plane.get())) +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { if (rectangle_status == GLSelectionRectangle::Deselect) unselect_point(points_idxs[idx]); @@ -1026,8 +1037,13 @@ void GLGizmoHollow::update_clipping_plane(bool keep_normal) const { if (! m_c->m_model_object) return; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ? + m_c->m_clipping_plane->get_normal() : -wxGetApp().plater()->get_camera().get_dir_forward()); +#else Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ? m_c->m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift); float dist = normal.dot(center); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index ab0b9b5d6..064302c02 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -14,6 +14,9 @@ #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/GUI_ObjectSettings.hpp" #include "slic3r/GUI/GUI_ObjectList.hpp" +#if ENABLE_NON_STATIC_CANVAS_MANAGER +#include "slic3r/GUI/Camera.hpp" +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #include "slic3r/GUI/MeshUtils.hpp" #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/PresetBundle.hpp" @@ -379,7 +382,11 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec if (! m_c->m_mesh_raycaster) return false; +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const Camera& camera = wxGetApp().plater()->get_camera(); +#else const Camera& camera = m_parent.get_camera(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER const Selection& selection = m_parent.get_selection(); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); Geometry::Transformation trafo = volume->get_instance_transformation(); @@ -489,7 +496,11 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous points_inside.push_back(points[idx].cast<float>()); // Only select/deselect points that are actually visible +#if ENABLE_NON_STATIC_CANVAS_MANAGER + for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, wxGetApp().plater()->get_camera(), points_inside, m_c->m_clipping_plane.get())) +#else for (size_t idx : m_c->m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_c->m_clipping_plane.get())) +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER { if (rectangle_status == GLSelectionRectangle::Deselect) unselect_point(points_idxs[idx]); @@ -1282,8 +1293,14 @@ void GLGizmoSlaSupports::update_clipping_plane(bool keep_normal) const { if (! m_c->m_model_object) return; + +#if ENABLE_NON_STATIC_CANVAS_MANAGER Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ? - m_c->m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); + m_c->m_clipping_plane->get_normal() : -wxGetApp().plater()->get_camera().get_dir_forward()); +#else + Vec3d normal = (keep_normal && m_c->m_clipping_plane->get_normal() != Vec3d::Zero() ? + m_c->m_clipping_plane->get_normal() : -m_parent.get_camera().get_dir_forward()); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER const Vec3d& center = m_c->m_model_object->instances[m_c->m_active_instance]->get_offset() + Vec3d(0., 0., m_z_shift); float dist = normal.dot(center); diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 18d603507..379bd48d1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -2,6 +2,9 @@ #include "GLGizmosManager.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/3DScene.hpp" +#if ENABLE_NON_STATIC_CANVAS_MANAGER +#include "slic3r/GUI/Camera.hpp" +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_ObjectManipulation.hpp" #include "slic3r/GUI/PresetBundle.hpp" @@ -1029,8 +1032,13 @@ void GLGizmosManager::do_render_overlay() const float cnv_w = (float)m_parent.get_canvas_size().get_width(); float cnv_h = (float)m_parent.get_canvas_size().get_height(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float zoom = (float)wxGetApp().plater()->get_camera().get_zoom(); + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); +#else float zoom = (float)m_parent.get_camera().get_zoom(); float inv_zoom = (float)m_parent.get_camera().get_inv_zoom(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER float height = get_scaled_total_height(); float width = get_scaled_total_width(); @@ -1081,7 +1089,11 @@ void GLGizmosManager::do_render_overlay() const GLTexture::render_sub_texture(icons_texture_id, zoomed_top_x, zoomed_top_x + zoomed_icons_size, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } }); if (idx == m_current) { +#if ENABLE_NON_STATIC_CANVAS_MANAGER + float toolbar_top = cnv_h - wxGetApp().plater()->get_view_toolbar().get_height(); +#else float toolbar_top = cnv_h - m_parent.get_view_toolbar_height(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER gizmo->render_input_window(width, 0.5f * cnv_h - zoomed_top_y * zoom, toolbar_top); } zoomed_top_y -= zoomed_stride_y; diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 842cec5e2..d05ecbcd8 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -145,6 +145,9 @@ void KBShortcutsDialog::fill_shortcuts() // View { "0-6", L("Camera view") }, { "E", L("Show/Hide object/instance labels") }, +#if ENABLE_SLOPE_RENDERING + { "D", L("Turn On/Off facets' slope rendering") }, +#endif // ENABLE_SLOPE_RENDERING // Configuration { ctrl + "P", L("Preferences") }, // Help diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index e1fb72c15..26ceda7bf 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -33,6 +33,7 @@ #ifdef _WIN32 #include <dbt.h> +#include <shlobj.h> #endif // _WIN32 namespace Slic3r { @@ -127,6 +128,30 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S // DEV_BROADCAST_HANDLE NotificationFilter = { 0 }; // NotificationFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE); // NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE; + + // Using Win32 Shell API to register for media insert / removal events. + LPITEMIDLIST ppidl; + if (SHGetSpecialFolderLocation(this->GetHWND(), CSIDL_DESKTOP, &ppidl) == NOERROR) { + SHChangeNotifyEntry shCNE; + shCNE.pidl = ppidl; + shCNE.fRecursive = TRUE; + // Returns a positive integer registration identifier (ID). + // Returns zero if out of memory or in response to invalid parameters. + m_ulSHChangeNotifyRegister = SHChangeNotifyRegister(this->GetHWND(), // Hwnd to receive notification + SHCNE_DISKEVENTS, // Event types of interest (sources) + SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED, + //SHCNE_UPDATEITEM, // Events of interest - use SHCNE_ALLEVENTS for all events + WM_USER_MEDIACHANGED, // Notification message to be sent upon the event + 1, // Number of entries in the pfsne array + &shCNE); // Array of SHChangeNotifyEntry structures that + // contain the notifications. This array should + // always be set to one when calling SHChnageNotifyRegister + // or SHChangeNotifyDeregister will not work properly. + assert(m_ulSHChangeNotifyRegister != 0); // Shell notification failed + } else { + // Failed to get desktop location + assert(false); + } #endif // _WIN32 // propagate event @@ -161,13 +186,26 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S void MainFrame::shutdown() { #ifdef _WIN32 - ::UnregisterDeviceNotification(HDEVNOTIFY(m_hDeviceNotify)); - m_hDeviceNotify = nullptr; + if (m_hDeviceNotify) { + ::UnregisterDeviceNotification(HDEVNOTIFY(m_hDeviceNotify)); + m_hDeviceNotify = nullptr; + } + if (m_ulSHChangeNotifyRegister) { + SHChangeNotifyDeregister(m_ulSHChangeNotifyRegister); + m_ulSHChangeNotifyRegister = 0; + } #endif // _WIN32 if (m_plater) m_plater->stop_jobs(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + // Unbinding of wxWidgets event handling in canvases needs to be done here because on MAC, + // when closing the application using Command+Q, a mouse event is triggered after this lambda is completed, + // causing a crash + if (m_plater) m_plater->unbind_canvas_event_handlers(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + // Weird things happen as the Paint messages are floating around the windows being destructed. // Avoid the Paint messages by hiding the main window. // Also the application closes much faster without these unnecessary screen refreshes. @@ -188,7 +226,9 @@ void MainFrame::shutdown() wxGetApp().app_config->save(); // if (m_plater) // m_plater->print = undef; +#if !ENABLE_NON_STATIC_CANVAS_MANAGER _3DScene::remove_all_canvases(); +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER // Slic3r::GUI::deregister_on_request_update_callback(); // set to null tabs and a plater @@ -755,9 +795,20 @@ void MainFrame::init_menubar() append_menu_item(viewMenu, wxID_ANY, _(L("Right")) + sep + "&6", _(L("Right View")), [this](wxCommandEvent&) { select_view("right"); }, "", nullptr, [this](){return can_change_view(); }, this); viewMenu->AppendSeparator(); +#if ENABLE_SLOPE_RENDERING + wxMenu* options_menu = new wxMenu(); + append_menu_check_item(options_menu, wxID_ANY, _(L("Show &labels")) + sep + "E", _(L("Show object/instance labels in 3D scene")), + [this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this, + [this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this); + append_menu_check_item(options_menu, wxID_ANY, _(L("Show &slope")) + sep + "D", _(L("Objects coloring using faces' slope")), + [this](wxCommandEvent&) { m_plater->show_view3D_slope(!m_plater->is_view3D_slope_shown()); }, this, + [this]() { return m_plater->is_view3D_shown() && !m_plater->is_view3D_layers_editing_enabled(); }, [this]() { return m_plater->is_view3D_slope_shown(); }, this); + append_submenu(viewMenu, options_menu, wxID_ANY, _(L("&Options")), ""); +#else append_menu_check_item(viewMenu, wxID_ANY, _(L("Show &labels")) + sep + "E", _(L("Show object/instance labels in 3D scene")), [this](wxCommandEvent&) { m_plater->show_view3D_labels(!m_plater->are_view3D_labels_shown()); }, this, [this]() { return m_plater->is_view3D_shown(); }, [this]() { return m_plater->are_view3D_labels_shown(); }, this); +#endif // ENABLE_SLOPE_RENDERING append_menu_check_item(viewMenu, wxID_ANY, _(L("&Collapse sidebar")), _(L("Collapse sidebar")), [this](wxCommandEvent&) { m_plater->collapse_sidebur(!m_plater->is_sidebar_collapsed()); }, this, [this]() { return true; }, [this]() { return m_plater->is_sidebar_collapsed(); }, this); diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 8c8b98090..6038e6d2f 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -144,6 +144,8 @@ public: #ifdef _WIN32 void* m_hDeviceNotify { nullptr }; + uint32_t m_ulSHChangeNotifyRegister { 0 }; + static constexpr int WM_USER_MEDIACHANGED { 0x7FFF }; // WM_USER from 0x0400 to 0x7FFF, picking the last one to not interfere with wxWidgets allocation #endif // _WIN32 }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 74a51d9f0..a04698a47 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -81,6 +81,12 @@ #include "RemovableDriveManager.hpp" #include "SearchComboBox.hpp" +#if ENABLE_NON_STATIC_CANVAS_MANAGER +#ifdef __APPLE__ +#include "Gizmos/GLGizmosManager.hpp" +#endif // __APPLE__ +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + #include <wx/glcanvas.h> // Needs to be last because reasons :-/ #include "WipeTowerDialog.hpp" #include "libslic3r/CustomGCode.hpp" @@ -1886,8 +1892,18 @@ struct Plater::priv bool is_sidebar_collapsed() const { return sidebar->is_collapsed(); } void collapse_sidebur(bool show) { sidebar->collapse(show); } +#if ENABLE_SLOPE_RENDERING + bool is_view3D_slope_shown() const { return (current_panel == view3D) && view3D->get_canvas3d()->is_slope_shown(); } + void show_view3D_slope(bool show) { if (current_panel == view3D) view3D->get_canvas3d()->show_slope(show); } + + bool is_view3D_layers_editing_enabled() const { return (current_panel == view3D) && view3D->get_canvas3d()->is_layers_editing_enabled(); } +#endif // ENABLE_SLOPE_RENDERING + void set_current_canvas_as_dirty(); GLCanvas3D* get_current_canvas3D(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + void unbind_canvas_event_handlers(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER bool init_view_toolbar(); @@ -2116,8 +2132,18 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) sla_print.set_status_callback(statuscb); this->q->Bind(EVT_SLICING_UPDATE, &priv::on_slicing_update, this); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + view3D = new View3D(q, &model, config, &background_process); + preview = new Preview(q, &model, config, &background_process, &gcode_preview_data, [this]() { schedule_background_process(); }); + +#ifdef __APPLE__ + // set default view_toolbar icons size equal to GLGizmosManager::Default_Icons_Size + view_toolbar.set_icons_size(GLGizmosManager::Default_Icons_Size); +#endif // __APPLE__ +#else view3D = new View3D(q, bed, camera, view_toolbar, &model, config, &background_process); preview = new Preview(q, bed, camera, view_toolbar, &model, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); }); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER panels.push_back(view3D); panels.push_back(preview); @@ -2218,7 +2244,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) // Drop target: q->SetDropTarget(new PlaterDropTarget(q)); // if my understanding is right, wxWindow takes the owenership +#if !ENABLE_NON_STATIC_CANVAS_MANAGER update_ui_from_settings(); +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER q->Layout(); set_current_panel(view3D); @@ -4124,6 +4152,17 @@ GLCanvas3D* Plater::priv::get_current_canvas3D() return (current_panel == view3D) ? view3D->get_canvas3d() : ((current_panel == preview) ? preview->get_canvas3d() : nullptr); } +#if ENABLE_NON_STATIC_CANVAS_MANAGER +void Plater::priv::unbind_canvas_event_handlers() +{ + if (view3D != nullptr) + view3D->get_canvas3d()->unbind_event_handlers(); + + if (preview != nullptr) + preview->get_canvas3d()->unbind_event_handlers(); +} +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + bool Plater::priv::init_view_toolbar() { if (view_toolbar.get_items_count() > 0) @@ -4594,7 +4633,8 @@ void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& lab // Plater / Public Plater::Plater(wxWindow *parent, MainFrame *main_frame) - : wxPanel(parent), p(new priv(this, main_frame)) + : wxPanel(parent) + , p(new priv(this, main_frame)) { // Initialization performed in the private c-tor } @@ -4721,6 +4761,13 @@ void Plater::show_view3D_labels(bool show) { p->show_view3D_labels(show); } bool Plater::is_sidebar_collapsed() const { return p->is_sidebar_collapsed(); } void Plater::collapse_sidebur(bool show) { p->collapse_sidebur(show); } +#if ENABLE_SLOPE_RENDERING +bool Plater::is_view3D_slope_shown() const { return p->is_view3D_slope_shown(); } +void Plater::show_view3D_slope(bool show) { p->show_view3D_slope(show); } + +bool Plater::is_view3D_layers_editing_enabled() const { return p->is_view3D_layers_editing_enabled(); } +#endif // ENABLE_SLOPE_RENDERING + void Plater::select_all() { p->select_all(); } void Plater::deselect_all() { p->deselect_all(); } @@ -5540,6 +5587,13 @@ void Plater::set_current_canvas_as_dirty() p->set_current_canvas_as_dirty(); } +#if ENABLE_NON_STATIC_CANVAS_MANAGER +void Plater::unbind_canvas_event_handlers() +{ + p->unbind_canvas_event_handlers(); +} +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + PrinterTechnology Plater::printer_technology() const { return p->printer_technology; @@ -5673,6 +5727,28 @@ Camera& Plater::get_camera() return p->camera; } +#if ENABLE_NON_STATIC_CANVAS_MANAGER +const Bed3D& Plater::get_bed() const +{ + return p->bed; +} + +Bed3D& Plater::get_bed() +{ + return p->bed; +} + +const GLToolbar& Plater::get_view_toolbar() const +{ + return p->view_toolbar; +} + +GLToolbar& Plater::get_view_toolbar() +{ + return p->view_toolbar; +} +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + const Mouse3DController& Plater::get_mouse3d_controller() const { return p->mouse3d_controller; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 5a24ac5eb..cf1c10681 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -43,6 +43,10 @@ class ObjectList; class GLCanvas3D; class Mouse3DController; struct Camera; +#if ENABLE_NON_STATIC_CANVAS_MANAGER +class Bed3D; +class GLToolbar; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>; @@ -183,6 +187,13 @@ public: bool is_sidebar_collapsed() const; void collapse_sidebur(bool show); +#if ENABLE_SLOPE_RENDERING + bool is_view3D_slope_shown() const; + void show_view3D_slope(bool show); + + bool is_view3D_layers_editing_enabled() const; +#endif // ENABLE_SLOPE_RENDERING + // Called after the Preferences dialog is closed and the program settings are saved. // Update the UI based on the current preferences. void update_ui_from_settings(); @@ -262,6 +273,9 @@ public: BoundingBoxf bed_shape_bb() const; void set_current_canvas_as_dirty(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + void unbind_canvas_event_handlers(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER PrinterTechnology printer_technology() const; void set_printer_technology(PrinterTechnology printer_technology); @@ -291,12 +305,21 @@ public: const Camera& get_camera() const; Camera& get_camera(); + +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const Bed3D& get_bed() const; + Bed3D& get_bed(); + + const GLToolbar& get_view_toolbar() const; + GLToolbar& get_view_toolbar(); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + const Mouse3DController& get_mouse3d_controller() const; Mouse3DController& get_mouse3d_controller(); void set_bed_shape() const; - // ROII wrapper for suppressing the Undo / Redo snapshot to be taken. + // ROII wrapper for suppressing the Undo / Redo snapshot to be taken. class SuppressSnapshots { public: diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index cdb1c1d45..d67ac4a22 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -33,17 +33,19 @@ wxDEFINE_EVENT(EVT_REMOVABLE_DRIVES_CHANGED, RemovableDrivesChangedEvent); #if _WIN32 std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() const { - //get logical drives flags by letter in alphabetical order + // Get logical drives flags by letter in alphabetical order. DWORD drives_mask = ::GetLogicalDrives(); // Allocate the buffers before the loop. std::wstring volume_name; std::wstring file_system_name; - // Iterate the Windows drives from 'A' to 'Z' + // Iterate the Windows drives from 'C' to 'Z' std::vector<DriveData> current_drives; - for (size_t i = 0; i < 26; ++ i) - if (drives_mask & (1 << i)) { - std::string path { char('A' + i), ':' }; + // Skip A and B drives. + drives_mask >>= 2; + for (char drive = 'C'; drive <= 'Z'; ++ drive, drives_mask >>= 1) + if (drives_mask & 1) { + std::string path { drive, ':' }; UINT drive_type = ::GetDriveTypeA(path.c_str()); // DRIVE_REMOVABLE on W are sd cards and usb thumbnails (not usb harddrives) if (drive_type == DRIVE_REMOVABLE) { @@ -450,14 +452,8 @@ void RemovableDriveManager::thread_proc() { std::unique_lock<std::mutex> lck(m_thread_stop_mutex); #ifdef _WIN32 - // Windows do not send an update on insert / eject of an SD card into an external SD card reader. - // Windows also do not send an update on software eject of a FLASH drive. - // We can likely use the Windows WMI API, but it will be quite time consuming to implement. - // https://www.codeproject.com/Articles/10539/Making-WMI-Queries-In-C - // https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-start-page - // https://docs.microsoft.com/en-us/windows/win32/wmisdk/com-api-for-wmi - // https://docs.microsoft.com/en-us/windows/win32/wmisdk/example--receiving-event-notifications-through-wmi- - m_thread_stop_condition.wait_for(lck, std::chrono::seconds(2), [this]{ return m_stop || m_wakeup; }); + // Reacting to updates by WM_DEVICECHANGE and WM_USER_MEDIACHANGED + m_thread_stop_condition.wait(lck, [this]{ return m_stop || m_wakeup; }); #else m_thread_stop_condition.wait_for(lck, std::chrono::seconds(2), [this]{ return m_stop; }); #endif diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 146111f49..b07463857 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -440,6 +440,12 @@ void Selection::clear() update_type(); this->set_bounding_boxes_dirty(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + // this happens while the application is closing + if (wxGetApp().obj_manipul() == nullptr) + return; +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER + // resets the cache in the sidebar wxGetApp().obj_manipul()->reset_cache(); diff --git a/src/slic3r/GUI/SysInfoDialog.cpp b/src/slic3r/GUI/SysInfoDialog.cpp index a1bae8742..f26fe7033 100644 --- a/src/slic3r/GUI/SysInfoDialog.cpp +++ b/src/slic3r/GUI/SysInfoDialog.cpp @@ -145,7 +145,11 @@ SysInfoDialog::SysInfoDialog() "</font>" "</body>" "</html>", bgr_clr_str, text_clr_str, text_clr_str, +#if ENABLE_NON_STATIC_CANVAS_MANAGER + get_mem_info(true) + "<br>" + wxGetApp().get_gl_info(true, true)); +#else get_mem_info(true) + "<br>" + _3DScene::get_gl_info(true, true)); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER m_opengl_info_html->SetPage(text); main_sizer->Add(m_opengl_info_html, 1, wxEXPAND | wxBOTTOM, 15); } @@ -198,7 +202,11 @@ void SysInfoDialog::on_dpi_changed(const wxRect &suggested_rect) void SysInfoDialog::onCopyToClipboard(wxEvent &) { wxTheClipboard->Open(); +#if ENABLE_NON_STATIC_CANVAS_MANAGER + const auto text = get_main_info(false) + "\n" + wxGetApp().get_gl_info(false, true); +#else const auto text = get_main_info(false)+"\n"+_3DScene::get_gl_info(false, true); +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER wxTheClipboard->SetData(new wxTextDataObject(text)); wxTheClipboard->Close(); }