diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 6493cd667b..bdc2a35988 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -79,7 +79,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, // Grab the lock for the Print / PrintObject milestones. tbb::mutex::scoped_lock lock(this->state_mutex()); - if(m_objects.empty() && model.objects.empty()) + if (m_objects.empty() && model.objects.empty() && m_model.objects.empty()) return APPLY_STATUS_UNCHANGED; // Temporary: just to have to correct layer height for the rasterization @@ -437,6 +437,32 @@ SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object): SLAPrintObject::~SLAPrintObject() {} +bool SLAPrintObject::has_mesh(SLAPrintObjectStep step) const +{ + switch (step) { + case slaposSupportTree: +// return m_supportdata && m_supportdata->support_tree_ptr && ! m_supportdata->support_tree_ptr->get().merged_mesh().empty(); + return ! this->support_mesh().empty(); + case slaposBasePool: +// return m_supportdata && m_supportdata->support_tree_ptr && ! m_supportdata->support_tree_ptr->get_pad().empty(); + return ! this->pad_mesh().empty(); + default: + return false; + } +} + +TriangleMesh SLAPrintObject::get_mesh(SLAPrintObjectStep step) const +{ + switch (step) { + case slaposSupportTree: + return this->support_mesh(); + case slaposBasePool: + return this->pad_mesh(); + default: + return TriangleMesh(); + } +} + TriangleMesh SLAPrintObject::support_mesh() const { TriangleMesh trm; diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index e18febd15e..31c604aa4c 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -48,6 +48,9 @@ public: }; const std::vector& instances() const { return m_instances; } + bool has_mesh(SLAPrintObjectStep step) const; + TriangleMesh get_mesh(SLAPrintObjectStep step) const; + // Get a support mesh centered around origin in XY, and with zero rotation around Z applied. // Support mesh is only valid if this->is_step_done(slaposSupportTree) is true. TriangleMesh support_mesh() const; diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 425967f9f7..0da2334f88 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -521,6 +521,7 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& t) const if (stl.stats.shared_vertices > 0) { + assert(stl.v_shared != nullptr); stl_vertex* vertex_ptr = stl.v_shared; for (int i = 0; i < stl.stats.shared_vertices; ++i) { diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index fd312d0e06..e2bf470142 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -65,6 +65,7 @@ public: void reset_repair_stats(); bool needed_repair() const; size_t facets_count() const { return this->stl.stats.number_of_facets; } + bool empty() const { return this->facets_count() == 0; } // Returns true, if there are two and more connected patches in the mesh. // Returns false, if one or zero connected patch is in the mesh. diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 16b7e022b3..df743e5e70 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -216,6 +216,7 @@ GLVolume::GLVolume(float r, float g, float b, float a) #endif // ENABLE_MODELVOLUME_TRANSFORM , m_transformed_convex_hull_bounding_box_dirty(true) , m_convex_hull(nullptr) + , m_convex_hull_owned(false) // geometry_id == 0 -> invalid , geometry_id(std::pair(0, 0)) , extruder_id(0) @@ -239,6 +240,12 @@ GLVolume::GLVolume(float r, float g, float b, float a) set_render_color(r, g, b, a); } +GLVolume::~GLVolume() +{ + if (m_convex_hull_owned) + delete m_convex_hull; +} + void GLVolume::set_render_color(float r, float g, float b, float a) { render_color[0] = r; @@ -365,9 +372,10 @@ void GLVolume::set_mirror(Axis axis, double mirror) } #endif // !ENABLE_MODELVOLUME_TRANSFORM -void GLVolume::set_convex_hull(const TriangleMesh& convex_hull) +void GLVolume::set_convex_hull(const TriangleMesh *convex_hull, bool owned) { - m_convex_hull = &convex_hull; + m_convex_hull = convex_hull; + m_convex_hull_owned = owned; } #if !ENABLE_MODELVOLUME_TRANSFORM @@ -779,7 +787,8 @@ int GLVolumeCollection::load_object_volume( v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx); if (model_volume->is_model_part()) { - v.set_convex_hull(model_volume->get_convex_hull()); + // GLVolume will reference a convex hull from model_volume! + v.set_convex_hull(&model_volume->get_convex_hull(), false); if (extruder_id != -1) v.extruder_id = extruder_id; v.layer_height_texture = layer_height_texture; @@ -808,6 +817,8 @@ void GLVolumeCollection::load_object_auxiliary( // pairs of const std::vector> &instances, SLAPrintObjectStep milestone, + // Timestamp of the last change of the milestone + size_t timestamp, bool use_VBOs) { assert(print_object->is_step_done(milestone)); @@ -835,7 +846,9 @@ void GLVolumeCollection::load_object_auxiliary( v.bounding_box = v.indexed_vertex_array.bounding_box(); v.indexed_vertex_array.finalize_geometry(use_VBOs); v.composite_id = GLVolume::CompositeID(obj_idx, -1, (int)instance_idx.first); - v.set_convex_hull(convex_hull); + v.geometry_id = std::pair(timestamp, model_instance.id().id); + // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. + v.set_convex_hull((&instance_idx == &instances.back()) ? new TriangleMesh(std::move(convex_hull)) : new TriangleMesh(convex_hull), true); v.is_modifier = false; v.shader_outside_printer_detection_enabled = true; //FIXME adjust with print_instance? diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 47dc7662bf..cedead67f9 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -256,6 +256,7 @@ public: GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f); GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {} + ~GLVolume(); private: #if ENABLE_MODELVOLUME_TRANSFORM @@ -280,7 +281,9 @@ private: // Whether or not is needed to recalculate the transformed bounding box. mutable bool m_transformed_bounding_box_dirty; // Pointer to convex hull of the original mesh, if any. + // This object may or may not own the convex hull instance based on m_convex_hull_owned const TriangleMesh* m_convex_hull; + bool m_convex_hull_owned; // Bounding box of this volume, in unscaled coordinates. mutable BoundingBoxf3 m_transformed_convex_hull_bounding_box; // Whether or not is needed to recalculate the transformed convex hull bounding box. @@ -422,7 +425,7 @@ public: void set_offset(const Vec3d& offset); #endif // ENABLE_MODELVOLUME_TRANSFORM - void set_convex_hull(const TriangleMesh& convex_hull); + void set_convex_hull(const TriangleMesh *convex_hull, bool owned); int object_idx() const { return this->composite_id.object_id; } int volume_idx() const { return this->composite_id.volume_id; } @@ -525,6 +528,8 @@ public: // pairs of const std::vector> &instances, SLAPrintObjectStep milestone, + // Timestamp of the last change of the milestone + size_t timestamp, bool use_VBOs); int load_wipe_tower_preview( diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 7408133ab8..2ffcf8ad80 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1867,7 +1867,10 @@ void GLCanvas3D::Selection::erase() for (unsigned int i : m_list) { const GLVolume* v = (*m_volumes)[i]; - volumes_idxs.insert(std::make_pair(v->object_idx(), v->volume_idx())); + // Only remove volumes associated with ModelVolumes from the object list. + // Temporary meshes (SLA supports or pads) are not managed by the object list. + if (v->volume_idx() >= 0) + volumes_idxs.insert(std::make_pair(v->object_idx(), v->volume_idx())); } std::vector items; @@ -3803,9 +3806,15 @@ void GLCanvas3D::reload_scene(bool force) SLASupportState state; for (size_t istep = 0; istep < sla_steps.size(); ++ istep) { state.step[istep] = print_object->step_state_with_timestamp(sla_steps[istep]); - if (state.step[istep].state == PrintStateBase::DONE) - for (const ModelInstance *model_instance : print_object->model_object()->instances) - aux_volume_state.emplace_back(state.step[istep].timestamp, model_instance->id()); + if (state.step[istep].state == PrintStateBase::DONE) { + if (! print_object->has_mesh(sla_steps[istep])) + // Consider the DONE step without a valid mesh as invalid for the purpose + // of mesh visualization. + state.step[istep].state = PrintStateBase::INVALID; + else + for (const ModelInstance *model_instance : print_object->model_object()->instances) + aux_volume_state.emplace_back(state.step[istep].timestamp, model_instance->id()); + } } sla_support_state.emplace_back(state); } @@ -3911,7 +3920,7 @@ void GLCanvas3D::reload_scene(bool force) const ModelObject *model_object = print_object->model_object(); // Find an index of the ModelObject int object_idx; - if (! std::all_of(state.step.begin(), state.step.end(), [](const PrintStateBase::StateWithTimeStamp &state){ return state.state != PrintStateBase::DONE; })) + if (std::all_of(state.step.begin(), state.step.end(), [](const PrintStateBase::StateWithTimeStamp &state){ return state.state != PrintStateBase::DONE; })) continue; // There may be new SLA volumes added to the scene for this print_object. // Find the object index of this print_object in the Model::objects list. @@ -3942,7 +3951,7 @@ void GLCanvas3D::reload_scene(bool force) } for (size_t istep = 0; istep < sla_steps.size(); ++ istep) if (! instances[istep].empty()) - m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], m_use_VBOs && m_initialized); + m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_use_VBOs && m_initialized); } } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 25aaf16f25..d2708f66c6 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1304,7 +1304,10 @@ void ObjectList::update_selections() const auto gl_vol = selection.get_volume(idx); if (selection.is_multiple_full_object()) sels.Add(m_objects_model->GetItemById(gl_vol->object_idx())); - else + else if (gl_vol->volume_idx() >= 0) + // Only add GLVolumes with non-negative volume_ids. GLVolumes with negative volume ids + // are not associated with ModelVolumes, but they are temporarily generated by the backend + // (for example, SLA supports or SLA pad). sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx())); } } diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index d9f996b27c..b035de685b 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -200,7 +200,7 @@ DECLARE_VARIANT_OBJECT(PrusaDataViewBitmapText) // PrusaObjectDataViewModelNode: a node inside PrusaObjectDataViewModel // ---------------------------------------------------------------------------- -enum ItemType{ +enum ItemType { itUndef = 0, itObject = 1, itVolume = 2,