mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-03 13:51:37 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c017629d11 |
@@ -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 PrintConfig &print_config = this->object()->print()->config();
|
||||
const auto 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 PrintConfig &print_config = this->object()->print()->config();
|
||||
const auto 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 PrintConfig &print_config = this->object()->print()->config();
|
||||
const auto 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);
|
||||
|
||||
@@ -1074,7 +1074,7 @@ void LayerRegion::simplify_entity_collection(ExtrusionEntityCollection* entity_c
|
||||
|
||||
void LayerRegion::simplify_path(ExtrusionPath* path)
|
||||
{
|
||||
const PrintConfig &print_config = this->layer()->object()->print()->config();
|
||||
const auto 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 PrintConfig &print_config = this->layer()->object()->print()->config();
|
||||
const auto 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 PrintConfig &print_config = this->layer()->object()->print()->config();
|
||||
const auto 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);
|
||||
|
||||
+11
-13
@@ -2604,11 +2604,6 @@ 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;
|
||||
}
|
||||
@@ -4334,9 +4329,9 @@ bool Print::is_dynamic_group_reorder() const
|
||||
return true;
|
||||
}
|
||||
|
||||
int Print::get_filament_config_indx(int filament_id, int layer_id)
|
||||
int Print::get_filament_config_indx(int filament_id, int layer_id, bool use_cache)
|
||||
{
|
||||
return get_config_index(filament_id, layer_id, m_config.filament_extruder_variant.values, m_filament_self_index, m_filament_index_map);
|
||||
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);
|
||||
}
|
||||
|
||||
void Print::update_filament_self_index_cache()
|
||||
@@ -4379,7 +4374,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
|
||||
@@ -4390,7 +4385,8 @@ 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.
|
||||
if (m_missing_nozzle_group_logged.insert(filament_id).second)
|
||||
// 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)
|
||||
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;
|
||||
@@ -4399,15 +4395,17 @@ 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 index_map[key];
|
||||
return iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -987,9 +987,6 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
const float eps = float(scale_(m_config.slice_closing_radius.value) * 1.5);
|
||||
static 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;
|
||||
|
||||
@@ -1820,15 +1820,37 @@ coordf_t TreeSupport::get_radius(const SupportNode* node)
|
||||
return node->radius;
|
||||
}
|
||||
|
||||
// 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)
|
||||
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
|
||||
}
|
||||
const ExPolygons& TreeSupport::get_collision(coordf_t radius, size_t layer_nr)
|
||||
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)
|
||||
{
|
||||
@@ -2617,11 +2639,7 @@ void TreeSupport::draw_circles()
|
||||
#endif // SUPPORT_TREE_DEBUG_TO_SVG
|
||||
|
||||
SupportLayerPtrs& ts_layers = m_object->support_layers();
|
||||
// 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;
|
||||
auto iter = std::remove_if(ts_layers.begin(), ts_layers.end(), [](SupportLayer* ts_layer) { return ts_layer->height < EPSILON; });
|
||||
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;
|
||||
@@ -2864,7 +2882,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);
|
||||
const ExPolygons& avoid_layer = get_avoidance(next_radius, obj_layer_nr_next);
|
||||
auto avoid_layer = get_avoidance(next_radius, obj_layer_nr_next);
|
||||
if (group_index == 0)
|
||||
{
|
||||
//Avoid collisions.
|
||||
@@ -3051,7 +3069,7 @@ void TreeSupport::drop_nodes()
|
||||
}
|
||||
#endif
|
||||
coordf_t next_radius = calc_radius(node.dist_mm_to_top + height_next);
|
||||
const ExPolygons& avoidance_next = get_avoidance(next_radius, obj_layer_nr_next);
|
||||
auto 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;
|
||||
@@ -3105,7 +3123,7 @@ void TreeSupport::drop_nodes()
|
||||
if (is_outside) { next_layer_vertex = candidate_vertex; }
|
||||
}
|
||||
}
|
||||
const ExPolygons& next_collision = get_collision(0, obj_layer_nr_next);
|
||||
auto 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);
|
||||
|
||||
@@ -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);
|
||||
const ExPolygons& get_avoidance(coordf_t radius, size_t obj_layer_nr);
|
||||
ExPolygons get_avoidance(coordf_t radius, size_t obj_layer_nr);
|
||||
// layer's expolygon expanded by radius+m_xy_distance
|
||||
const ExPolygons& get_collision(coordf_t radius, size_t layer_nr);
|
||||
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);
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ 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);
|
||||
|
||||
|
||||
|
||||
@@ -3245,7 +3245,8 @@ void GLCanvas3D::load_sla_preview()
|
||||
|
||||
void GLCanvas3D::bind_event_handlers()
|
||||
{
|
||||
if (m_canvas != nullptr) {
|
||||
// Every view switch binds, so binding twice would run each handler twice per event.
|
||||
if (m_canvas != nullptr && !m_event_handlers_bound) {
|
||||
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);
|
||||
@@ -3255,9 +3256,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, [this](wxTimerEvent&) { m_toolbar_highlighter.blink(); });
|
||||
m_canvas->Bind(EVT_GLCANVAS_TOOLBAR_HIGHLIGHTER_TIMER, &GLCanvas3D::on_toolbar_highlighter_timer, this);
|
||||
m_gizmo_highlighter.set_timer_owner(m_canvas, 0);
|
||||
m_canvas->Bind(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, [this](wxTimerEvent&) { m_gizmo_highlighter.blink(); });
|
||||
m_canvas->Bind(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, &GLCanvas3D::on_gizmo_highlighter_timer, this);
|
||||
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);
|
||||
@@ -3272,14 +3273,7 @@ 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, [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_canvas->Bind(wxEVT_KILL_FOCUS, &GLCanvas3D::on_kill_focus, this);
|
||||
m_event_handlers_bound = true;
|
||||
|
||||
m_canvas->Bind(wxEVT_GESTURE_PAN, &GLCanvas3D::on_gesture, this);
|
||||
@@ -3317,6 +3311,9 @@ 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);
|
||||
@@ -4893,6 +4890,26 @@ 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;
|
||||
|
||||
@@ -1133,6 +1133,9 @@ 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 };
|
||||
|
||||
@@ -2057,9 +2057,15 @@ 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 MenuWithSeparators();
|
||||
MenuWithSeparators* menu = new_transient_menu();
|
||||
append_menu_item_settings(menu);
|
||||
|
||||
return menu;
|
||||
@@ -2085,13 +2091,13 @@ wxMenu* MenuFactory::multi_selection_menu()
|
||||
}
|
||||
|
||||
if (all_plates) {
|
||||
wxMenu* menu = new MenuWithSeparators();
|
||||
wxMenu* menu = new_transient_menu();
|
||||
append_menu_item_replace_all_with_stl(menu);
|
||||
return menu;
|
||||
}
|
||||
if (undefined_type)
|
||||
return nullptr;
|
||||
wxMenu* menu = new MenuWithSeparators();
|
||||
wxMenu* menu = new_transient_menu();
|
||||
if (!multi_volume) {
|
||||
int index = 0;
|
||||
if (obj_list()->can_merge_to_multipart_object()) {
|
||||
@@ -2165,7 +2171,7 @@ wxMenu* MenuFactory::assemble_multi_selection_menu()
|
||||
// show this menu only for Objects(Instances mixed with Objects)/Volumes selection
|
||||
return nullptr;
|
||||
|
||||
wxMenu* menu = new MenuWithSeparators();
|
||||
wxMenu* menu = new_transient_menu();
|
||||
append_menu_item_set_visible(menu);
|
||||
//append_menu_item_fix_through_cgal(menu);
|
||||
//append_menu_item_simplify(menu);
|
||||
@@ -2211,7 +2217,7 @@ wxMenu* MenuFactory::plate_menu()
|
||||
|
||||
wxMenu* MenuFactory::assemble_object_menu()
|
||||
{
|
||||
wxMenu* menu = new MenuWithSeparators();
|
||||
wxMenu* menu = new_transient_menu();
|
||||
// Set Visible
|
||||
append_menu_item_set_visible(menu);
|
||||
// Delete
|
||||
@@ -2231,7 +2237,7 @@ wxMenu* MenuFactory::assemble_object_menu()
|
||||
|
||||
wxMenu* MenuFactory::assemble_part_menu()
|
||||
{
|
||||
wxMenu* menu = new MenuWithSeparators();
|
||||
wxMenu* menu = new_transient_menu();
|
||||
|
||||
append_menu_item_set_visible(menu);
|
||||
append_menu_item_delete(menu);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define slic3r_GUI_Factories_hpp_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
@@ -120,6 +121,12 @@ 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
|
||||
@@ -127,6 +134,9 @@ 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();
|
||||
|
||||
@@ -2272,6 +2272,10 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,7 @@ enum class PainterGizmoType {
|
||||
FDM_SUPPORTS,
|
||||
SEAM,
|
||||
MM_SEGMENTATION,
|
||||
FUZZY_SKIN,
|
||||
TEXTURE_DISPLACEMENT
|
||||
FUZZY_SKIN
|
||||
};
|
||||
|
||||
class TriangleSelectorGUI : public TriangleSelector {
|
||||
@@ -102,7 +101,9 @@ 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) {}
|
||||
virtual ~TriangleSelectorPatch() = default;
|
||||
// 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(); }
|
||||
|
||||
// Render current selection. Transformation matrices are supposed
|
||||
// to be already set.
|
||||
|
||||
@@ -361,6 +361,7 @@ ImGuiWrapper::~ImGuiWrapper()
|
||||
{
|
||||
//destroy_fonts_texture();
|
||||
destroy_font();
|
||||
destroy_svg_textures();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
@@ -542,6 +543,12 @@ 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) {
|
||||
@@ -552,6 +559,11 @@ 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();
|
||||
@@ -1804,8 +1816,7 @@ 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 {
|
||||
static ImTextureID transparent;
|
||||
IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/transparent.svg", icon_size.x, icon_size.y, transparent);
|
||||
ImTextureID transparent = ImGuiWrapper::svg_texture(Slic3r::resources_dir() + "/images/transparent.svg", icon_size.x, icon_size.y);
|
||||
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)));
|
||||
}
|
||||
}
|
||||
@@ -2631,11 +2642,7 @@ 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
|
||||
// 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_CheckMark, ImVec4(1.00f, 1.00f, 1.00f, 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));
|
||||
@@ -3389,6 +3396,36 @@ 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) {
|
||||
@@ -3468,7 +3505,6 @@ 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;
|
||||
@@ -3481,7 +3517,7 @@ void ImGuiWrapper::filament_group(const std::string& filament_type, const char*
|
||||
if (rgba[3] == 0x00) {
|
||||
svg_path = "/images/outlined_rect_transparent.svg";
|
||||
}
|
||||
BitmapCache::load_from_svg_file_change_color(Slic3r::resources_dir() + svg_path, img_size.x, img_size.y, transparent, hex_color);
|
||||
ImTextureID transparent = svg_texture(Slic3r::resources_dir() + svg_path, img_size.x, img_size.y, hex_color);
|
||||
ImGui::BeginGroup();
|
||||
{
|
||||
ImVec2 cursor_pos = ImGui::GetCursorScreenPos();
|
||||
|
||||
@@ -104,6 +104,14 @@ 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>
|
||||
|
||||
@@ -2225,11 +2225,12 @@ 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> ¬ification = *it;
|
||||
if (notification->get_type() == type) {
|
||||
it = m_pop_notifications.erase(it);
|
||||
break;
|
||||
} else
|
||||
++it;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user