Compare commits

..
Author SHA1 Message Date
ExPikaPaka 391c53a8da Take the print config by reference while simplifying extrusions
simplify_path, simplify_multi_path and simplify_loop each copied the whole
PrintConfig, 10520 bytes with around 200 heap owning members, once per extrusion
entity, from inside the parallel_for over all layers. LayerRegion.cpp already
binds a reference a few hundred lines above. Three more sites in Layer.cpp do the
same thing.

The tree support changes in the same area: draw_circles() dropped layers from an
owning vector without deleting them, so every re-slice leaked the layers above
the topmost overhang. std::stable_partition rather than std::remove_if, because
remove_if leaves moved-from duplicates of kept pointers in the tail and deleting
those would be a double free. The collision and avoidance accessors returned
ExPolygons by value out of a cache that hands them out by reference, several
times per node per layer. The preview cache is released when the support step
finishes instead of at the start of the next slice; nothing reads it in between.

set_shared_object() now releases the layers the object still owns before it
starts aliasing another object's. Both clear functions are no-ops once the alias
is set, so this cannot free the sharee's layers.

PrintObjectSlice.cpp: eps was a function local static inside a parallel_for, so
slice_closing_radius was latched once per process. This one changes output for
projects that override it per object, or on a re-slice after editing it. The old
behaviour was undefined: whichever object won the race set it for the session.
2026-10-01 09:15:15 +02:00
17 changed files with 67 additions and 168 deletions
+3 -3
View File
@@ -360,7 +360,7 @@ void Layer::simplify_support_entity_collection(ExtrusionEntityCollection* entity
//BBS: method to simplify support path
void Layer::simplify_support_path(ExtrusionPath * path)
{
const auto print_config = this->object()->print()->config();
const PrintConfig &print_config = this->object()->print()->config();
const bool spiral_mode = print_config.spiral_mode;
const bool enable_arc_fitting = print_config.enable_arc_fitting;
const auto scaled_resolution = scaled<double>(print_config.resolution.value);
@@ -375,7 +375,7 @@ void Layer::simplify_support_path(ExtrusionPath * path)
//BBS: method to simplify support path
void Layer::simplify_support_multi_path(ExtrusionMultiPath* multipath)
{
const auto print_config = this->object()->print()->config();
const PrintConfig &print_config = this->object()->print()->config();
const bool spiral_mode = print_config.spiral_mode;
const bool enable_arc_fitting = print_config.enable_arc_fitting;
const auto scaled_resolution = scaled<double>(print_config.resolution.value);
@@ -392,7 +392,7 @@ void Layer::simplify_support_multi_path(ExtrusionMultiPath* multipath)
//BBS: method to simplify support path
void Layer::simplify_support_loop(ExtrusionLoop* loop)
{
const auto print_config = this->object()->print()->config();
const PrintConfig &print_config = this->object()->print()->config();
const bool spiral_mode = print_config.spiral_mode;
const bool enable_arc_fitting = print_config.enable_arc_fitting;
const auto scaled_resolution = scaled<double>(print_config.resolution.value);
+3 -3
View File
@@ -1074,7 +1074,7 @@ void LayerRegion::simplify_entity_collection(ExtrusionEntityCollection* entity_c
void LayerRegion::simplify_path(ExtrusionPath* path)
{
const auto print_config = this->layer()->object()->print()->config();
const PrintConfig &print_config = this->layer()->object()->print()->config();
const bool spiral_mode = print_config.spiral_mode;
const bool enable_arc_fitting = print_config.enable_arc_fitting;
const auto scaled_resolution = scaled<double>(print_config.resolution.value);
@@ -1092,7 +1092,7 @@ void LayerRegion::simplify_path(ExtrusionPath* path)
void LayerRegion::simplify_multi_path(ExtrusionMultiPath* multipath)
{
const auto print_config = this->layer()->object()->print()->config();
const PrintConfig &print_config = this->layer()->object()->print()->config();
const bool spiral_mode = print_config.spiral_mode;
const bool enable_arc_fitting = print_config.enable_arc_fitting;
const auto scaled_resolution = scaled<double>(print_config.resolution.value);
@@ -1112,7 +1112,7 @@ void LayerRegion::simplify_multi_path(ExtrusionMultiPath* multipath)
void LayerRegion::simplify_loop(ExtrusionLoop* loop)
{
const auto print_config = this->layer()->object()->print()->config();
const PrintConfig &print_config = this->layer()->object()->print()->config();
const bool spiral_mode = print_config.spiral_mode;
const bool enable_arc_fitting = print_config.enable_arc_fitting;
const auto scaled_resolution = scaled<double>(print_config.resolution.value);
+13 -11
View File
@@ -2604,6 +2604,11 @@ void Print::auto_assign_extruders(ModelObject* model_object) const
void PrintObject::set_shared_object(PrintObject *object)
{
// Orca: from now on m_layers / m_support_layers only alias the shared object's layers, so release the
// ones this object still owns (it may have sliced itself before it became shareable again).
// Both are no-ops once m_shared_object is set, so this cannot free layers owned by another object.
clear_support_layers();
clear_layers();
m_shared_object = object;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": this=%1%, found shared object from %2%")%this%m_shared_object;
}
@@ -4329,9 +4334,9 @@ bool Print::is_dynamic_group_reorder() const
return true;
}
int Print::get_filament_config_indx(int filament_id, int layer_id, bool use_cache)
int Print::get_filament_config_indx(int filament_id, int layer_id)
{
return get_config_index(filament_id, layer_id, m_config.filament_extruder_variant.values, m_filament_self_index, use_cache ? &m_filament_index_map : nullptr);
return get_config_index(filament_id, layer_id, m_config.filament_extruder_variant.values, m_filament_self_index, m_filament_index_map);
}
void Print::update_filament_self_index_cache()
@@ -4374,7 +4379,7 @@ int Print::get_nozzle_config_index(int filament_id, int layer_id)
return get_config_index(filament_id, layer_id, m_default_region_config.print_extruder_variant.values, m_default_region_config.print_extruder_id.values, m_nozzle_index_map);
}
int Print::get_config_index(int filament_id, int layer_id, const std::vector<std::string> &variant_list, const std::vector<int>& self_index_list, FilamentIndexMap *index_map)
int Print::get_config_index(int filament_id, int layer_id, const std::vector<std::string> &variant_list, const std::vector<int>& self_index_list, FilamentIndexMap &index_map)
{
auto group_result = get_layered_nozzle_group_result();
// Orca: defensive — when no grouping producer has published a result yet, fall back to the
@@ -4385,8 +4390,7 @@ int Print::get_config_index(int filament_id, int layer_id, const std::vector<std
if (!nozzle_info.has_value()) {
// Orca: this fallback runs per-filament/per-layer in the g-code hot path — log once per filament
// (reset each slice) instead of flooding thousands of identical lines that bury the real error.
// Without the cache, the log set is left alone too; the cached caller reports the same filament.
if (index_map && m_missing_nozzle_group_logged.insert(filament_id).second)
if (m_missing_nozzle_group_logged.insert(filament_id).second)
BOOST_LOG_TRIVIAL(error) << __FUNCTION__
<< boost::format(", Line %1%: could not found group_nozzle_info corresponding to filament_id %2%, layer_id %3% (further occurrences for this filament suppressed)") % __LINE__ % filament_id %
layer_id;
@@ -4395,17 +4399,15 @@ int Print::get_config_index(int filament_id, int layer_id, const std::vector<std
ExtruderType extruder_type = ExtruderType(m_config.extruder_type.get_at(nozzle_info->extruder_id));
NozzleVolumeType nozzle_volume_type = nozzle_info->volume_type;
if (!index_map)
return get_config_index_base(nozzle_volume_type, extruder_type, filament_id + 1, variant_list, self_index_list);
FilamentIndexKey key{filament_id, extruder_type, nozzle_volume_type};
auto iter = index_map->find(key);
if (iter == index_map->end()) {
auto iter = index_map.find(key);
if (iter == index_map.end()) {
int index = get_config_index_base(nozzle_volume_type, extruder_type, filament_id + 1, variant_list, self_index_list);
(*index_map)[key] = index;
index_map[key] = index;
return index;
} else {
return iter->second;
return index_map[key];
}
}
+3
View File
@@ -987,6 +987,9 @@ void PrintObject::generate_support_material()
this->_generate_support_material();
m_print->throw_if_canceled();
}
// Orca: the tree support collision/avoidance caches and support nodes are only used while this step runs
// (detect_overhangs() rebuilds them from scratch), so don't keep them resident until the next slice.
this->clear_tree_support_preview_cache();
this->set_done(posSupportMaterial);
}
}
+1 -1
View File
@@ -1346,7 +1346,7 @@ void PrintObject::slice_volumes()
if (min_growth < 0.f || elfoot > 0.f) {
// Apply the negative XY compensation. (the ones that is <0)
ExPolygons trimming;
static const float eps = float(scale_(m_config.slice_closing_radius.value) * 1.5);
const float eps = float(scale_(m_config.slice_closing_radius.value) * 1.5);
if (elfoot > 0.f) {
ExPolygons expolygons_to_compensate = offset_ex(layer->merged(eps), -eps);
lslices_elfoot_uncompensated[layer_id] = expolygons_to_compensate;
+12 -30
View File
@@ -1820,37 +1820,15 @@ coordf_t TreeSupport::get_radius(const SupportNode* node)
return node->radius;
}
ExPolygons TreeSupport::get_avoidance(coordf_t radius, size_t obj_layer_nr)
// Orca: these are hit up to several times per node per layer in drop_nodes(), so hand out a
// reference into the TreeSupportData cache instead of copying the ExPolygons out of it.
const ExPolygons& TreeSupport::get_avoidance(coordf_t radius, size_t obj_layer_nr)
{
#if USE_SUPPORT_3D
if (m_model_volumes) {
bool on_build_plate = m_object_config->support_on_build_plate_only.value;
const Polygons& avoid_polys = m_model_volumes->getAvoidance(radius, obj_layer_nr, TreeSupport3D::TreeModelVolumes::AvoidanceType::FastSafe, on_build_plate, true);
ExPolygons expolys;
for (auto& poly : avoid_polys)
expolys.emplace_back(std::move(poly));
return expolys;
}
return ExPolygons();
#else
return m_ts_data->get_avoidance(radius, obj_layer_nr);
#endif
}
ExPolygons TreeSupport::get_collision(coordf_t radius, size_t layer_nr)
const ExPolygons& TreeSupport::get_collision(coordf_t radius, size_t layer_nr)
{
#if USE_SUPPORT_3D
if (m_model_volumes) {
bool on_build_plate = m_object_config->support_on_build_plate_only.value;
const Polygons& collision_polys = m_model_volumes->getCollision(radius, layer_nr, true);
ExPolygons expolys;
for (auto& poly : collision_polys)
expolys.emplace_back(std::move(poly));
return expolys;
}
#else
return m_ts_data->get_collision(radius, layer_nr);
#endif
return ExPolygons();
}
Polygons TreeSupport::get_collision_polys(coordf_t radius, size_t layer_nr)
{
@@ -2639,7 +2617,11 @@ void TreeSupport::draw_circles()
#endif // SUPPORT_TREE_DEBUG_TO_SVG
SupportLayerPtrs& ts_layers = m_object->support_layers();
auto iter = std::remove_if(ts_layers.begin(), ts_layers.end(), [](SupportLayer* ts_layer) { return ts_layer->height < EPSILON; });
// Orca: the vector owns its layers, so the dropped ones have to be deleted, not just unlinked.
// std::stable_partition (unlike std::remove_if) leaves exactly the dropped layers in the tail.
auto iter = std::stable_partition(ts_layers.begin(), ts_layers.end(), [](SupportLayer* ts_layer) { return ts_layer->height >= EPSILON; });
for (auto it = iter; it != ts_layers.end(); ++it)
delete *it;
ts_layers.erase(iter, ts_layers.end());
for (int layer_nr = 0; layer_nr < ts_layers.size(); layer_nr++) {
ts_layers[layer_nr]->upper_layer = layer_nr != ts_layers.size() - 1 ? ts_layers[layer_nr + 1] : nullptr;
@@ -2882,7 +2864,7 @@ void TreeSupport::drop_nodes()
//Insert a completely new node and let both original nodes fade.
Point next_position = (node.position + neighbours[0]) / 2; //Average position of the two nodes.
coordf_t next_radius = calc_radius(node.dist_mm_to_top+height_next);
auto avoid_layer = get_avoidance(next_radius, obj_layer_nr_next);
const ExPolygons& avoid_layer = get_avoidance(next_radius, obj_layer_nr_next);
if (group_index == 0)
{
//Avoid collisions.
@@ -3069,7 +3051,7 @@ void TreeSupport::drop_nodes()
}
#endif
coordf_t next_radius = calc_radius(node.dist_mm_to_top + height_next);
auto avoidance_next = get_avoidance(next_radius, obj_layer_nr_next);
const ExPolygons& avoidance_next = get_avoidance(next_radius, obj_layer_nr_next);
Point to_outside = projection_onto(avoidance_next, node.position);
Point direction_to_outer = to_outside - node.position;
@@ -3123,7 +3105,7 @@ void TreeSupport::drop_nodes()
if (is_outside) { next_layer_vertex = candidate_vertex; }
}
}
auto next_collision = get_collision(0, obj_layer_nr_next);
const ExPolygons& next_collision = get_collision(0, obj_layer_nr_next);
const bool to_buildplate = !is_inside_ex(m_ts_data->m_layer_outlines[obj_layer_nr_next], next_layer_vertex);
// don't increase radius if next node will collide partially with the object (STUDIO-7883)
to_outside = projection_onto(next_collision, next_layer_vertex);
+2 -2
View File
@@ -511,9 +511,9 @@ private:
coordf_t calc_branch_radius(coordf_t base_radius, coordf_t mm_to_top, double diameter_angle_scale_factor, bool use_min_distance=true);
coordf_t calc_radius(coordf_t mm_to_top);
coordf_t get_radius(const SupportNode* node);
ExPolygons get_avoidance(coordf_t radius, size_t obj_layer_nr);
const ExPolygons& get_avoidance(coordf_t radius, size_t obj_layer_nr);
// layer's expolygon expanded by radius+m_xy_distance
ExPolygons get_collision(coordf_t radius, size_t layer_nr);
const ExPolygons& get_collision(coordf_t radius, size_t layer_nr);
// get Polygons instead of ExPolygons
Polygons get_collision_polys(coordf_t radius, size_t layer_nr);
-2
View File
@@ -55,8 +55,6 @@ public:
static bool parse_color(const std::string& scolor, unsigned char* rgb_out);
static bool parse_color4(const std::string& scolor, unsigned char* rgba_out);
// Rasterizes the SVG into a freshly generated GL texture; the caller owns it and has to delete
// it (ImGuiWrapper::svg_texture() caches the result for the whole session).
static bool load_from_svg_file_change_color(const std::string &filename, unsigned width, unsigned height, ImTextureID &texture_id, const char *hexColor);
+11 -28
View File
@@ -3245,8 +3245,7 @@ void GLCanvas3D::load_sla_preview()
void GLCanvas3D::bind_event_handlers()
{
// Every view switch binds, so binding twice would run each handler twice per event.
if (m_canvas != nullptr && !m_event_handlers_bound) {
if (m_canvas != nullptr) {
m_canvas->Bind(wxEVT_SIZE, &GLCanvas3D::on_size, this);
m_canvas->Bind(wxEVT_IDLE, &GLCanvas3D::on_idle, this);
m_canvas->Bind(wxEVT_CHAR, &GLCanvas3D::on_char, this);
@@ -3256,9 +3255,9 @@ void GLCanvas3D::bind_event_handlers()
m_canvas->Bind(wxEVT_TIMER, &GLCanvas3D::on_timer, this);
m_canvas->Bind(EVT_GLCANVAS_RENDER_TIMER, &GLCanvas3D::on_render_timer, this);
m_toolbar_highlighter.set_timer_owner(m_canvas, 0);
m_canvas->Bind(EVT_GLCANVAS_TOOLBAR_HIGHLIGHTER_TIMER, &GLCanvas3D::on_toolbar_highlighter_timer, this);
m_canvas->Bind(EVT_GLCANVAS_TOOLBAR_HIGHLIGHTER_TIMER, [this](wxTimerEvent&) { m_toolbar_highlighter.blink(); });
m_gizmo_highlighter.set_timer_owner(m_canvas, 0);
m_canvas->Bind(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, &GLCanvas3D::on_gizmo_highlighter_timer, this);
m_canvas->Bind(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, [this](wxTimerEvent&) { m_gizmo_highlighter.blink(); });
m_canvas->Bind(wxEVT_LEFT_DOWN, &GLCanvas3D::on_mouse, this);
m_canvas->Bind(wxEVT_LEFT_UP, &GLCanvas3D::on_mouse, this);
m_canvas->Bind(wxEVT_MIDDLE_DOWN, &GLCanvas3D::on_mouse, this);
@@ -3273,7 +3272,14 @@ void GLCanvas3D::bind_event_handlers()
m_canvas->Bind(wxEVT_RIGHT_DCLICK, &GLCanvas3D::on_mouse, this);
m_canvas->Bind(wxEVT_PAINT, &GLCanvas3D::on_paint, this);
m_canvas->Bind(wxEVT_SET_FOCUS, &GLCanvas3D::on_set_focus, this);
m_canvas->Bind(wxEVT_KILL_FOCUS, &GLCanvas3D::on_kill_focus, this);
m_canvas->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent& evt) {
// The key-up that would commit a keyboard edit goes to whatever took the focus.
if (m_selection_edit.kind != SelectionEdit::None)
finish_selection_edit();
ImGui::SetWindowFocus(nullptr);
render();
evt.Skip();
});
m_event_handlers_bound = true;
m_canvas->Bind(wxEVT_GESTURE_PAN, &GLCanvas3D::on_gesture, this);
@@ -3311,9 +3317,6 @@ void GLCanvas3D::unbind_event_handlers()
m_canvas->Unbind(wxEVT_RIGHT_DCLICK, &GLCanvas3D::on_mouse, this);
m_canvas->Unbind(wxEVT_PAINT, &GLCanvas3D::on_paint, this);
m_canvas->Unbind(wxEVT_SET_FOCUS, &GLCanvas3D::on_set_focus, this);
m_canvas->Unbind(wxEVT_KILL_FOCUS, &GLCanvas3D::on_kill_focus, this);
m_canvas->Unbind(EVT_GLCANVAS_TOOLBAR_HIGHLIGHTER_TIMER, &GLCanvas3D::on_toolbar_highlighter_timer, this);
m_canvas->Unbind(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, &GLCanvas3D::on_gizmo_highlighter_timer, this);
m_event_handlers_bound = false;
m_canvas->Unbind(wxEVT_GESTURE_PAN, &GLCanvas3D::on_gesture, this);
@@ -4890,26 +4893,6 @@ void GLCanvas3D::on_set_focus(wxFocusEvent& evt)
m_is_touchpad_navigation = wxGetApp().app_config->get_bool("camera_navigation_style");
}
void GLCanvas3D::on_kill_focus(wxFocusEvent& evt)
{
// The key-up that would commit a keyboard edit goes to whatever took the focus.
if (m_selection_edit.kind != SelectionEdit::None)
finish_selection_edit();
ImGui::SetWindowFocus(nullptr);
render();
evt.Skip();
}
void GLCanvas3D::on_toolbar_highlighter_timer(wxTimerEvent& evt)
{
m_toolbar_highlighter.blink();
}
void GLCanvas3D::on_gizmo_highlighter_timer(wxTimerEvent& evt)
{
m_gizmo_highlighter.blink();
}
bool GLCanvas3D::clicked_button_matches_action(const wxMouseEvent& evt, const MouseAction action, const std::map<MouseButton, MouseAction>& mappings) const
{
MouseButton clicked = MouseButton::None;
-3
View File
@@ -1133,9 +1133,6 @@ public:
void on_gesture(wxGestureEvent& evt);
void on_paint(wxPaintEvent& evt);
void on_set_focus(wxFocusEvent& evt);
void on_kill_focus(wxFocusEvent& evt);
void on_toolbar_highlighter_timer(wxTimerEvent& evt);
void on_gizmo_highlighter_timer(wxTimerEvent& evt);
void force_set_focus();
enum class MouseButton { None, Left, Middle, Right };
+6 -12
View File
@@ -2057,15 +2057,9 @@ wxMenu* MenuFactory::instance_menu()
return &m_instance_menu;
}
MenuWithSeparators* MenuFactory::new_transient_menu()
{
m_transient_menu = std::make_unique<MenuWithSeparators>();
return m_transient_menu.get();
}
wxMenu* MenuFactory::layer_menu()
{
MenuWithSeparators* menu = new_transient_menu();
MenuWithSeparators* menu = new MenuWithSeparators();
append_menu_item_settings(menu);
return menu;
@@ -2091,13 +2085,13 @@ wxMenu* MenuFactory::multi_selection_menu()
}
if (all_plates) {
wxMenu* menu = new_transient_menu();
wxMenu* menu = new MenuWithSeparators();
append_menu_item_replace_all_with_stl(menu);
return menu;
}
if (undefined_type)
return nullptr;
wxMenu* menu = new_transient_menu();
wxMenu* menu = new MenuWithSeparators();
if (!multi_volume) {
int index = 0;
if (obj_list()->can_merge_to_multipart_object()) {
@@ -2171,7 +2165,7 @@ wxMenu* MenuFactory::assemble_multi_selection_menu()
// show this menu only for Objects(Instances mixed with Objects)/Volumes selection
return nullptr;
wxMenu* menu = new_transient_menu();
wxMenu* menu = new MenuWithSeparators();
append_menu_item_set_visible(menu);
//append_menu_item_fix_through_cgal(menu);
//append_menu_item_simplify(menu);
@@ -2217,7 +2211,7 @@ wxMenu* MenuFactory::plate_menu()
wxMenu* MenuFactory::assemble_object_menu()
{
wxMenu* menu = new_transient_menu();
wxMenu* menu = new MenuWithSeparators();
// Set Visible
append_menu_item_set_visible(menu);
// Delete
@@ -2237,7 +2231,7 @@ wxMenu* MenuFactory::assemble_object_menu()
wxMenu* MenuFactory::assemble_part_menu()
{
wxMenu* menu = new_transient_menu();
wxMenu* menu = new MenuWithSeparators();
append_menu_item_set_visible(menu);
append_menu_item_delete(menu);
-10
View File
@@ -2,7 +2,6 @@
#define slic3r_GUI_Factories_hpp_
#include <map>
#include <memory>
#include <vector>
#include <array>
#include <cstddef>
@@ -121,12 +120,6 @@ private:
MenuWithSeparators m_assemble_part_menu;
wxMenu m_filament_action_menu;
// The selection dependent menus are rebuilt for every popup, so they cannot be members that
// outlive a build like the ones above; this owns the current one and destroys the previous.
// One slot is enough because PopupMenu() is synchronous: the menu a caller was handed is gone
// from the screen before anything can ask for the next one.
std::unique_ptr<MenuWithSeparators> m_transient_menu;
// Removed/Prepended Items according to the view mode
@@ -134,9 +127,6 @@ private:
std::array<wxMenuItem*, mtCount> items_decrease;
std::array<wxMenuItem*, mtCount> items_set_number_of_copies;
// Replaces m_transient_menu with an empty menu and returns it.
MenuWithSeparators* new_transient_menu();
void create_default_menu();
void create_common_object_menu(wxMenu *menu);
void create_object_menu();
-4
View File
@@ -2272,10 +2272,6 @@ void GLGizmoMeasure::update_measurement_result()
void GLGizmoMeasure::reset_all_pick()
{
std::map<GLVolume*, std::shared_ptr<PickRaycaster>>().swap(m_mesh_raycaster_map);
// register_single_mesh_pick() fills both maps in lockstep, so the measurings have to go with
// the raycasters; otherwise the entries keyed on the GLVolumes of the previous selection stay
// behind for the rest of the session.
std::map<GLVolume*, std::shared_ptr<Measure::Measuring>>().swap(m_mesh_measure_map);
reset_gripper_pick(GripperType::UNDEFINE,true);
}
+3 -4
View File
@@ -27,7 +27,8 @@ enum class PainterGizmoType {
FDM_SUPPORTS,
SEAM,
MM_SEGMENTATION,
FUZZY_SKIN
FUZZY_SKIN,
TEXTURE_DISPLACEMENT
};
class TriangleSelectorGUI : public TriangleSelector {
@@ -101,9 +102,7 @@ class TriangleSelectorPatch : public TriangleSelectorGUI {
public:
explicit TriangleSelectorPatch(const TriangleMesh& mesh, const std::vector<ColorRGBA> ebt_colors, float edge_limit = 0.6f)
: TriangleSelectorGUI(mesh, edge_limit), m_ebt_colors(ebt_colors) {}
// Releases the VAO and the per-patch VBOs built by finalize_triangle_indices(). The base class
// already deletes GL buffers from its GLModel members here, so this needs no context of its own.
virtual ~TriangleSelectorPatch() { release_geometry(); }
virtual ~TriangleSelectorPatch() = default;
// Render current selection. Transformation matrices are supposed
// to be already set.
+9 -45
View File
@@ -361,7 +361,6 @@ ImGuiWrapper::~ImGuiWrapper()
{
//destroy_fonts_texture();
destroy_font();
destroy_svg_textures();
ImGui::DestroyContext();
}
@@ -543,12 +542,6 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt)
return ret;
}
// SVG icons rasterized into GL textures, keyed on file name, size and recolor. Cleared as a whole
// from new_frame() once it grows past MAX_SVG_TEXTURES, which is safe there: the previous frame has
// been rendered and the frame about to be recorded asks for every icon it draws again.
static std::map<std::string, ImTextureID> s_svg_textures;
static const size_t MAX_SVG_TEXTURES = 256;
void ImGuiWrapper::new_frame()
{
if (m_new_frame_open) {
@@ -559,11 +552,6 @@ void ImGuiWrapper::new_frame()
init_font(true);
}
// Recolored icons accumulate one texture per color the session has shown; drop them before
// anything references them again. This frame recreates the handful it actually draws.
if (s_svg_textures.size() > MAX_SVG_TEXTURES)
destroy_svg_textures();
ImGuiIO& io = ImGui::GetIO();
ImGui::NewFrame();
@@ -1816,7 +1804,8 @@ bool menu_item_with_icon(const char *label, const char *shortcut, ImVec2 icon_si
if (icon_color != 0)
ImGui::RenderFrame(icon_pos, icon_pos + icon_size, icon_color);
else {
ImTextureID transparent = ImGuiWrapper::svg_texture(Slic3r::resources_dir() + "/images/transparent.svg", icon_size.x, icon_size.y);
static ImTextureID transparent;
IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/transparent.svg", icon_size.x, icon_size.y, transparent);
window->DrawList->AddImage(transparent, icon_pos, icon_pos + icon_size, { 0,0 }, { 1,1 }, ImGui::GetColorU32(ImVec4(1.f, 1.f, 1.f, 1.f)));
}
}
@@ -2642,7 +2631,11 @@ void ImGuiWrapper::push_toolbar_style(const float scale)
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.00f)); // 10
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 0.00f)); // 11
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, COL_GREEN_LIGHT); // 12
ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.00f, 1.00f, 1.00f, 1.00f));//13
// The checkbox/radio frame behind this is drawn fully transparent (see FrameBg above,
// alpha 0), showing the light window background through it - a white check mark there is
// invisible. Dark mode doesn't have this problem (its window background is dark), so only
// this branch needs a check mark color with real contrast against a light background.
ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.f, 156 / 255.f, 136 / 255.f, 1.00f));//13
ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab, ImVec4(0.42f, 0.42f, 0.42f, 1.00f));
ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImVec4(0.93f, 0.93f, 0.93f, 1.00f));
ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImVec4(0.93f, 0.93f, 0.93f, 1.00f));
@@ -3396,36 +3389,6 @@ bool ImGuiWrapper::display_initialized() const
return io.DisplaySize.x >= 0.0f && io.DisplaySize.y >= 0.0f;
}
ImTextureID ImGuiWrapper::svg_texture(const std::string& filename, unsigned width, unsigned height, const char* hex_color)
{
std::string key = filename + "|" + std::to_string(width) + "x" + std::to_string(height);
if (hex_color != nullptr)
key += std::string("|") + hex_color;
const auto it = s_svg_textures.find(key);
if (it != s_svg_textures.end())
return it->second;
ImTextureID texture_id = nullptr;
const bool loaded = (hex_color != nullptr) ?
BitmapCache::load_from_svg_file_change_color(filename, width, height, texture_id, hex_color) :
IMTexture::load_from_svg_file(filename, width, height, texture_id);
if (!loaded)
return nullptr;
s_svg_textures.emplace(std::move(key), texture_id);
return texture_id;
}
void ImGuiWrapper::destroy_svg_textures()
{
for (const auto& texture : s_svg_textures) {
GLuint texture_id = (GLuint)(intptr_t)texture.second;
glsafe(::glDeleteTextures(1, &texture_id));
}
s_svg_textures.clear();
}
void ImGuiWrapper::destroy_font()
{
if (m_font_texture != 0) {
@@ -3505,6 +3468,7 @@ void ImGuiWrapper::filament_group(const std::string& filament_type, const char*
//ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
std::string id = std::to_string(static_cast<unsigned int> (filament_id + 1));
ImDrawList* draw_list = ImGui::GetWindowDrawList();
static ImTextureID transparent;
ImVec2 text_size = ImGui::CalcTextSize(filament_type.c_str());
// BBS image sizing based on text width (DPI scaling)
float img_width = ImGui::CalcTextSize("ABC").x;
@@ -3517,7 +3481,7 @@ void ImGuiWrapper::filament_group(const std::string& filament_type, const char*
if (rgba[3] == 0x00) {
svg_path = "/images/outlined_rect_transparent.svg";
}
ImTextureID transparent = svg_texture(Slic3r::resources_dir() + svg_path, img_size.x, img_size.y, hex_color);
BitmapCache::load_from_svg_file_change_color(Slic3r::resources_dir() + svg_path, img_size.x, img_size.y, transparent, hex_color);
ImGui::BeginGroup();
{
ImVec2 cursor_pos = ImGui::GetCursorScreenPos();
-8
View File
@@ -104,14 +104,6 @@ public:
// Hash of every draw list's vertices, indices and commands.
static ImGuiID draw_data_signature(const ImDrawData* draw_data);
// A GL texture holding an SVG icon rasterized at width x height, optionally recolored.
// Rasterizing an SVG is far too expensive to redo for every frame that draws the icon, and the
// texture the previous frame generated would leak, so the result is kept until the frame that
// finds the cache overgrown drops it (and rebuilds only what it still draws).
static ImTextureID svg_texture(const std::string& filename, unsigned width, unsigned height, const char* hex_color = nullptr);
// Deletes every texture svg_texture() handed out. Requires a current GL context.
static void destroy_svg_textures();
float scaled(float x) const { return x * m_font_size; }
ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size, y * m_font_size); }
/// <summary>
+1 -2
View File
@@ -2225,12 +2225,11 @@ void NotificationManager::close_and_delete_self(PopNotification * self)
}
void NotificationManager::remove_notification_of_type(const NotificationType type) {
// Seven notification types may have several instances alive at once, so erase every match:
// stopping at the first one leaves the rest (and the ObjectIDs they hold) behind.
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
std::unique_ptr<PopNotification> &notification = *it;
if (notification->get_type() == type) {
it = m_pop_notifications.erase(it);
break;
} else
++it;
}