diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 01c6248129..24fc80b01e 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -751,7 +751,7 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab return; GLShaderProgram* curr_shader = GUI::wxGetApp().get_current_shader(); - GLShaderProgram* sink_shader = GUI::wxGetApp().get_shader("flat"); + GLShaderProgram* sink_shader = GUI::wxGetApp().get_shader("flat"); #if SLIC3R_OPENGL_ES GLShaderProgram* edges_shader = GUI::wxGetApp().get_shader("dashed_lines"); #else @@ -774,9 +774,34 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab if (disable_cullface) glsafe(::glDisable(GL_CULL_FACE)); + + // This block is here to render the pained triangles. It is not very nice, but it works. + // There is a cache that holds the OpenGL models of the painted areas to render, one for + // each ModelVolume. The cache is invalidated based on changes in extruder_colors, + // default extruder idx and timestamp of the painted data. The data belonging to objects + // // which no longer exist are removed from the cache periodically. const ModelObjectPtrs& model_objects = GUI::wxGetApp().model().objects; const std::vector extruders_colors = GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config(); const bool is_render_as_mmu_painted_enabled = !model_objects.empty() && !extruders_colors.empty(); + struct MMPaintCachePerVolume { + size_t extruder_id; + std::unique_ptr triangle_selector_mm; + std::chrono::system_clock::time_point time_used; + uint64_t mm_timestamp; + }; + struct MMPaintCache { + std::vector extruders_colors; + std::map volume_data; + }; + static MMPaintCache mm_paint_cache; + if (mm_paint_cache.extruders_colors != extruders_colors) { + mm_paint_cache.extruders_colors = extruders_colors; + mm_paint_cache.volume_data.clear(); + } + auto time_now = std::chrono::system_clock::now(); + + + for (GLVolumeWithIdAndZ& volume : to_render) { if (!volume.first->is_active) @@ -788,8 +813,8 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab const int obj_idx = volume.first->object_idx(); const int vol_idx = volume.first->volume_idx(); const bool render_as_mmu_painted = is_render_as_mmu_painted_enabled && !volume.first->selected && - !volume.first->is_outside && !volume.first->is_wipe_tower && obj_idx >= 0 && vol_idx >= 0 && - !model_objects[obj_idx]->volumes[vol_idx]->mm_segmentation_facets.empty(); + !volume.first->is_outside && volume.first->hover == GLVolume::HS_None && !volume.first->is_wipe_tower && obj_idx >= 0 && vol_idx >= 0 && + !model_objects[obj_idx]->volumes[vol_idx]->mm_segmentation_facets.empty(); volume.first->set_render_color(true); // render sinking contours of non-hovered volumes @@ -827,13 +852,30 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab const ModelVolume& model_volume = *model_objects[obj_idx]->volumes[vol_idx]; const size_t extruder_idx = ModelVolume::get_extruder_color_idx(model_volume, GUI::wxGetApp().extruders_edited_cnt()); - GUI::TriangleSelectorMmGui ts(model_volume.mesh(), extruders_colors, extruders_colors[extruder_idx]); - ts.deserialize(model_volume.mm_segmentation_facets.get_data(), true); - ts.request_update_render_data(); - ts.render(nullptr, world_matrix); + + + // This block retrieves the painted geometry from the cache or adds it to it. + ObjectID vol_id = model_volume.id(); + auto it = mm_paint_cache.volume_data.find(vol_id); + GUI::TriangleSelectorMmGui* ts = nullptr; + uint64_t timestamp = model_volume.mm_segmentation_facets.timestamp(); + if (it == mm_paint_cache.volume_data.end() || it->second.extruder_id != extruder_idx || timestamp != it->second.mm_timestamp) { + auto ts_uptr = std::make_unique(model_volume.mesh(), mm_paint_cache.extruders_colors, mm_paint_cache.extruders_colors[extruder_idx]); + ts = ts_uptr.get(); + ts->deserialize(model_volume.mm_segmentation_facets.get_data(), true); + ts->request_update_render_data(); + mm_paint_cache.volume_data[vol_id] = MMPaintCachePerVolume{ extruder_idx, std::move(ts_uptr), std::chrono::system_clock::now(), timestamp }; + } + else { + ts = it->second.triangle_selector_mm.get(); + it->second.time_used = time_now; + } + + + ts->render(nullptr, world_matrix); if (is_left_handed) - glsafe(::glFrontFace(GL_CCW)); + glsafe(::glFrontFace(GL_CCW)); shader->stop_using(); } @@ -879,6 +921,20 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab } } + + // Purge the painted triangles cache from everything that was not used for some time. + // Only do this occasionally (once a second). + using namespace std::chrono_literals; + static auto time_since_last_check = time_now; + if (time_now - time_since_last_check > 1000ms) + for (auto it = mm_paint_cache.volume_data.begin(); it != mm_paint_cache.volume_data.end(); ) { + auto it_delete = it; // The iterator to the deleted element will be invalidated, the others will not. + ++it; + if (time_now - it_delete->second.time_used > 5000ms) + mm_paint_cache.volume_data.erase(it_delete); + } + + if (m_show_sinking_contours) { if (sink_shader != nullptr) { sink_shader->start_using();