diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 8aa4b34f904..ffcec0d626d 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -139,14 +139,12 @@ bool filament_state_uses_surface_gradient_preview(unsigned int filament_id, return zone != nullptr && zone->is_2d_gradient(); } -bool texture_preview_has_surface_gradient_state(size_t states_count, - unsigned int base_filament_id, - size_t num_physical, - const TextureMappingManager *texture_mgr) +bool texture_preview_used_states_have_surface_gradient(const std::vector &used_states, + size_t num_physical, + const TextureMappingManager *texture_mgr) { - for (size_t state_id = 0; state_id < states_count; ++state_id) { - const unsigned int filament_id = state_id == 0 ? base_filament_id : unsigned(state_id); - if (filament_state_uses_surface_gradient_preview(filament_id, num_physical, texture_mgr)) + for (size_t state_id = 1; state_id < used_states.size(); ++state_id) { + if (used_states[state_id] && filament_state_uses_surface_gradient_preview(unsigned(state_id), num_physical, texture_mgr)) return true; } @@ -669,9 +667,16 @@ void GLVolume::simple_render(GLShaderProgram* shader, const bool base_uses_surface_gradient_preview = filament_state_uses_surface_gradient_preview(base_filament_id, num_physical, texture_mgr); const bool base_uses_image_texture_preview = base_uses_texture_preview && !base_uses_surface_gradient_preview; + const bool has_surface_gradient_preview_state = + base_uses_surface_gradient_preview || + (has_mmu_segmentation && + texture_preview_used_states_have_surface_gradient(model_volume->mmu_segmentation_facets.get_data().used_states, + num_physical, + texture_mgr)); const bool has_texture_mapping_color_preview_data = base_uses_texture_preview && model_volume_has_texture_mapping_color_preview_data(*model_volume); const bool has_texture_preview_data = model_volume_has_texture_preview_data(*model_volume); + const Transform3d preview_world_matrix = this->world_matrix(); use_original_mesh_texture_preview = !has_mmu_segmentation && !has_texture_mapping_color_preview_data && @@ -708,6 +713,15 @@ void GLVolume::simple_render(GLShaderProgram* shader, (preview_visual_signature << 6) + (preview_visual_signature >> 2); preview_visual_signature ^= model_volume_texture_mapping_color_preview_signature(*model_volume) + 0x9e3779b97f4a7c15ull + (preview_visual_signature << 6) + (preview_visual_signature >> 2); + if (has_surface_gradient_preview_state) { + for (int row = 0; row < 4; ++row) { + for (int col = 0; col < 4; ++col) { + preview_visual_signature ^= std::hash{}(int(std::lround(preview_world_matrix(row, col) * 1000000.0))) + + 0x9e3779b97f4a7c15ull + (preview_visual_signature << 6) + + (preview_visual_signature >> 2); + } + } + } if (model_volume->mmu_segmentation_facets.timestamp() != mmuseg_ts || preview_visual_signature != mmuseg_texture_preview_visual_signature) { mmuseg_models.clear(); @@ -760,14 +774,14 @@ void GLVolume::simple_render(GLShaderProgram* shader, if (has_texture_preview_state && (has_active_texture_mapping_color_preview_data || !has_texture_preview_data || - texture_preview_has_surface_gradient_state(triangles_per_type.size(), base_filament_id, num_physical, texture_mgr))) { + has_surface_gradient_preview_state)) { build_mmu_vertex_color_preview_models(*model_volume, triangles_per_type, state_colors, base_filament_id, num_physical, texture_mgr, - this->world_matrix(), + preview_world_matrix, mmuseg_vertex_color_preview_models, mmuseg_vertex_color_preview_colors, mmuseg_vertex_color_preview_filament_ids); diff --git a/src/slic3r/GUI/ObjColorDialog.cpp b/src/slic3r/GUI/ObjColorDialog.cpp index a16b0d840a6..036d04a000c 100644 --- a/src/slic3r/GUI/ObjColorDialog.cpp +++ b/src/slic3r/GUI/ObjColorDialog.cpp @@ -39,6 +39,16 @@ static void update_ui(wxWindow* window) Slic3r::GUI::wxGetApp().UpdateDarkUI(window); } +static ModelObject *single_volume_model_object(Model *model) +{ + if (model == nullptr || model->objects.size() != 1) + return nullptr; + ModelObject *object = model->objects[0]; + if (object == nullptr || object->volumes.size() != 1 || object->volumes[0] == nullptr) + return nullptr; + return object; +} + static const char g_min_cluster_color = 1; static const char g_max_color = 16; @@ -104,8 +114,10 @@ ObjColorDialog::ObjColorDialog(wxWindow *parent, Slic3r::ObjDialogInOut &in_out, bool some_face_no_color = false; if (!in_out.deal_vertex_color) { auto temp0 = in_out.input_colors.size(); - auto temp1 = in_out.model->objects[0]->volumes[0]->mesh_ptr()->facets_count(); - some_face_no_color = temp0 < temp1; + if (ModelObject *object = single_volume_model_object(in_out.model)) { + auto temp1 = object->volumes[0]->mesh_ptr()->facets_count(); + some_face_no_color = temp0 < temp1; + } } bool ok = in_out.lost_material_name.empty() && !some_face_no_color; if (ok) { @@ -275,14 +287,17 @@ ObjColorPanel::ObjColorPanel(wxWindow *parent, Slic3r::ObjDialogInOut &in_out, c auto icon_sizer = new wxBoxSizer(wxHORIZONTAL); auto plater = wxGetApp().plater(); { - auto mo = m_obj_in_out.model->objects[0]; - mo->add_instance(); - auto mv = mo->volumes[0]; - m_thumbnail_offset = Slic3r::Vec3d::Zero(); - auto box = mo->bounding_box_exact(); - if (box.min.x() < 0 || box.min.y() < 0 || box.min.z() < 0) { - m_thumbnail_offset = Slic3r::Vec3d(box.min.x() < 0 ? -box.min.x() : 0, box.min.y() < 0 ? -box.min.y() : 0, box.min.z() < 0 ? -box.min.z() : 0); - mv->translate(m_thumbnail_offset); + if (ModelObject *mo = single_volume_model_object(m_obj_in_out.model)) { + mo->add_instance(); + auto mv = mo->volumes[0]; + m_thumbnail_offset = Slic3r::Vec3d::Zero(); + auto box = mo->bounding_box_exact(); + if (box.min.x() < 0 || box.min.y() < 0 || box.min.z() < 0) { + m_thumbnail_offset = Slic3r::Vec3d(box.min.x() < 0 ? -box.min.x() : 0, + box.min.y() < 0 ? -box.min.y() : 0, + box.min.z() < 0 ? -box.min.z() : 0); + mv->translate(m_thumbnail_offset); + } } } @@ -443,7 +458,11 @@ void ObjColorPanel::send_new_filament_to_ui() void ObjColorPanel::cancel_paint_color() { m_filament_ids.clear(); - auto mo = m_obj_in_out.model->objects[0]; + ModelObject *mo = single_volume_model_object(m_obj_in_out.model); + if (mo == nullptr) { + m_first_extruder_id = 1; + return; + } mo->config.set("extruder", 1); clear_instance_and_revert_offset(); auto mv = mo->volumes[0]; @@ -785,6 +804,10 @@ void ObjColorPanel::deal_default_strategy() void ObjColorPanel::deal_thumbnail() { update_filament_ids(); + if (single_volume_model_object(m_obj_in_out.model) == nullptr) { + m_deal_thumbnail_flag = false; + return; + } // generate model volume if (m_obj_in_out.deal_vertex_color) { if (m_obj_in_out.filament_ids.size() > 0) { @@ -800,42 +823,37 @@ void ObjColorPanel::deal_thumbnail() { void ObjColorPanel::generate_thumbnail() { - if (m_deal_thumbnail_flag && m_obj_in_out.model->objects.size() == 1) { - std::vector colors = GUI::wxGetApp().plater()->get_extruders_colors(); - for (size_t i = 0; i < m_new_add_colors.size(); i++) { - Slic3r::ColorRGBA temp_color; - temp_color[0] = m_new_add_colors[i].Red() / 255.f; - temp_color[1] = m_new_add_colors[i].Green() / 255.f; - temp_color[2] = m_new_add_colors[i].Blue() / 255.f; - temp_color[3] = m_new_add_colors[i].Alpha() / 255.f; - colors.emplace_back(temp_color); - } - - auto mo = m_obj_in_out.model->objects[0]; - wxGetApp().plater()->update_obj_preview_thumbnail(mo, 0, 0, colors, (int) m_camera_view_angle_type); - // get thumbnail image - PartPlate *plate = wxGetApp().plater()->get_partplate_list().get_plate(0); - auto & data = plate->obj_preview_thumbnail_data; - if (data.is_valid()) { - wxImage image(data.width, data.height); - image.InitAlpha(); - for (unsigned int r = 0; r < data.height; ++r) { - unsigned int rr = (data.height - 1 - r) * data.width; - for (unsigned int c = 0; c < data.width; ++c) { - unsigned char *px = (unsigned char *) data.pixels.data() + 4 * (rr + c); - image.SetRGB((int) c, (int) r, px[0], px[1], px[2]); - image.SetAlpha((int) c, (int) r, px[3]); - } - } - image = image.Rescale(FromDIP(IMAGE_SIZE_WIDTH), FromDIP(IMAGE_SIZE_WIDTH)); - m_image_button->SetBitmap(image); - } + ModelObject *mo = single_volume_model_object(m_obj_in_out.model); + if (!m_deal_thumbnail_flag || mo == nullptr) + return; + std::vector colors = GUI::wxGetApp().plater()->get_extruders_colors(); + for (size_t i = 0; i < m_new_add_colors.size(); i++) { + Slic3r::ColorRGBA temp_color; + temp_color[0] = m_new_add_colors[i].Red() / 255.f; + temp_color[1] = m_new_add_colors[i].Green() / 255.f; + temp_color[2] = m_new_add_colors[i].Blue() / 255.f; + temp_color[3] = m_new_add_colors[i].Alpha() / 255.f; + colors.emplace_back(temp_color); } - else { -#ifdef _WIN32 - __debugbreak(); -#endif + + wxGetApp().plater()->update_obj_preview_thumbnail(mo, 0, 0, colors, (int) m_camera_view_angle_type); + // get thumbnail image + PartPlate *plate = wxGetApp().plater()->get_partplate_list().get_plate(0); + auto & data = plate->obj_preview_thumbnail_data; + if (data.is_valid()) { + wxImage image(data.width, data.height); + image.InitAlpha(); + for (unsigned int r = 0; r < data.height; ++r) { + unsigned int rr = (data.height - 1 - r) * data.width; + for (unsigned int c = 0; c < data.width; ++c) { + unsigned char *px = (unsigned char *) data.pixels.data() + 4 * (rr + c); + image.SetRGB((int) c, (int) r, px[0], px[1], px[2]); + image.SetAlpha((int) c, (int) r, px[3]); + } + } + image = image.Rescale(FromDIP(IMAGE_SIZE_WIDTH), FromDIP(IMAGE_SIZE_WIDTH)); + m_image_button->SetBitmap(image); } } @@ -850,7 +868,9 @@ void ObjColorPanel::set_view_angle_type(int value) void ObjColorPanel::clear_instance_and_revert_offset() { - auto mo = m_obj_in_out.model->objects[0]; + ModelObject *mo = single_volume_model_object(m_obj_in_out.model); + if (mo == nullptr) + return; mo->clear_instances(); auto mv = mo->volumes[0]; auto box = mo->bounding_box_exact(); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 83ea9d7ff0f..300af2b2976 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1084,13 +1084,15 @@ public: const TextureMappingGlobalSettings &global_settings, const TextureMappingPrimeTowerImage &prime_tower_image, const TextureMappingPrimeTowerImage &prime_tower_image_back, - int initial_options_tab) + int initial_options_tab, + bool initial_strength_offsets_expanded) : wxDialog(parent, wxID_ANY, _L("Texture Mapping Options"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) , m_global_settings(global_settings) , m_prime_tower_image(prime_tower_image) , m_prime_tower_image_back(prime_tower_image_back) { (void) generic_solver_mix_model; + m_strength_offsets_expanded = initial_strength_offsets_expanded; const int gap = FromDIP(8); auto *root = new wxBoxSizer(wxVERTICAL); auto *tab_row = new wxBoxSizer(wxHORIZONTAL); @@ -1142,8 +1144,6 @@ public: tone_gamma_row->Add(new wxStaticText(image_page, wxID_ANY, _L("x")), 0, wxALIGN_CENTER_VERTICAL); image_root->Add(tone_gamma_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, gap); - auto *minimum_offsets_box = new wxStaticBoxSizer(wxVERTICAL, filament_page, _L("Per-filament minimum offset")); - auto *strengths_box = new wxStaticBoxSizer(wxVERTICAL, filament_page, _L("Per-filament strength")); const std::vector channel_labels = texture_mapping_channel_labels(filament_color_mode); auto component_label = [&component_ids, &channel_labels](size_t i) { wxString text = wxString::Format("F%d", int(component_ids[i])); @@ -1151,48 +1151,6 @@ public: text += wxString::Format(" (%s)", channel_labels[i]); return text; }; - auto add_percent_row = [this, gap, filament_page, component_label](wxStaticBoxSizer *box, - size_t idx, - int value, - std::vector &sliders, - std::vector &spins) { - auto *row = new wxBoxSizer(wxHORIZONTAL); - row->Add(new wxStaticText(filament_page, wxID_ANY, component_label(idx)), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap); - auto *slider = new wxSlider(filament_page, wxID_ANY, value, 0, 100, wxDefaultPosition, wxSize(FromDIP(180), -1), wxSL_HORIZONTAL | wxSL_AUTOTICKS); - auto *spin = new wxSpinCtrl(filament_page, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(70), -1), - wxSP_ARROW_KEYS | wxALIGN_RIGHT, 0, 100, value); - slider->Bind(wxEVT_SLIDER, [spin](wxCommandEvent &evt) { - if (spin) - spin->SetValue(evt.GetInt()); - }); - spin->Bind(wxEVT_SPINCTRL, [slider](wxSpinEvent &evt) { - if (slider) - slider->SetValue(evt.GetInt()); - }); - row->Add(slider, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap); - row->Add(spin, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap / 2); - row->Add(new wxStaticText(filament_page, wxID_ANY, _L("%")), 0, wxALIGN_CENTER_VERTICAL); - sliders.emplace_back(slider); - spins.emplace_back(spin); - box->Add(row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap); - }; - for (size_t i = 0; i < component_ids.size(); ++i) { - const int offset_value = i < component_minimum_offsets_pct.size() ? - std::clamp(int(std::lround(component_minimum_offsets_pct[i])), 0, 100) : - 0; - add_percent_row(minimum_offsets_box, i, offset_value, m_minimum_offset_sliders, m_minimum_offset_spins); - } - for (size_t i = 0; i < component_ids.size(); ++i) { - const int strength_value = i < component_strengths_pct.size() ? - std::clamp(int(std::lround(component_strengths_pct[i])), 0, 100) : - 100; - add_percent_row(strengths_box, i, strength_value, m_strength_sliders, m_strength_spins); - } - filament_root->Add(minimum_offsets_box, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, gap); - filament_root->Add(strengths_box, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, gap); - auto *reset_btn = new wxButton(filament_page, wxID_ANY, _L("Reset strengths and offsets")); - reset_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { reset_strengths_and_offsets(); }); - filament_root->Add(reset_btn, 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT | wxBOTTOM, gap); auto *td_box = new wxStaticBoxSizer(wxVERTICAL, filament_page, _L("Transmission distance")); auto *td_mode_row = new wxBoxSizer(wxHORIZONTAL); @@ -1214,7 +1172,7 @@ public: td_box->Add(td_mode_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap); for (size_t i = 0; i < component_ids.size(); ++i) { auto *row = new wxBoxSizer(wxHORIZONTAL); - row->Add(new wxStaticText(filament_page, wxID_ANY, component_label(i)), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap); + row->Add(new wxStaticText(filament_page, wxID_ANY, component_label(i) + _L(" TD")), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap); const double value = i < component_transmission_distances_mm.size() ? std::clamp(double(component_transmission_distances_mm[i]), 0.0, 50.0) : 0.0; @@ -1236,6 +1194,64 @@ public: } filament_root->Add(td_box, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, gap); + m_strength_offsets_toggle_button = new wxButton(filament_page, wxID_ANY, wxEmptyString); + m_strength_offsets_toggle_button->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { + m_strength_offsets_expanded = !m_strength_offsets_expanded; + update_strength_offsets_visibility(true); + }); + filament_root->Add(m_strength_offsets_toggle_button, 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT | wxBOTTOM, gap); + + m_strength_offsets_panel = new wxPanel(filament_page, wxID_ANY); + auto *strength_offsets_root = new wxBoxSizer(wxVERTICAL); + m_strength_offsets_panel->SetSizer(strength_offsets_root); + auto *minimum_offsets_box = new wxStaticBoxSizer(wxVERTICAL, m_strength_offsets_panel, _L("Per-filament minimum offset")); + auto *strengths_box = new wxStaticBoxSizer(wxVERTICAL, m_strength_offsets_panel, _L("Per-filament strength")); + auto add_percent_row = [this, gap, component_label](wxWindow *parent, + wxStaticBoxSizer *box, + size_t idx, + int value, + std::vector &sliders, + std::vector &spins) { + auto *row = new wxBoxSizer(wxHORIZONTAL); + row->Add(new wxStaticText(parent, wxID_ANY, component_label(idx)), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap); + auto *slider = new wxSlider(parent, wxID_ANY, value, 0, 100, wxDefaultPosition, wxSize(FromDIP(180), -1), wxSL_HORIZONTAL | wxSL_AUTOTICKS); + auto *spin = new wxSpinCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(70), -1), + wxSP_ARROW_KEYS | wxALIGN_RIGHT, 0, 100, value); + slider->Bind(wxEVT_SLIDER, [spin](wxCommandEvent &evt) { + if (spin) + spin->SetValue(evt.GetInt()); + }); + spin->Bind(wxEVT_SPINCTRL, [slider](wxSpinEvent &evt) { + if (slider) + slider->SetValue(evt.GetInt()); + }); + row->Add(slider, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap); + row->Add(spin, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap / 2); + row->Add(new wxStaticText(parent, wxID_ANY, _L("%")), 0, wxALIGN_CENTER_VERTICAL); + sliders.emplace_back(slider); + spins.emplace_back(spin); + box->Add(row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap); + }; + for (size_t i = 0; i < component_ids.size(); ++i) { + const int offset_value = i < component_minimum_offsets_pct.size() ? + std::clamp(int(std::lround(component_minimum_offsets_pct[i])), 0, 100) : + 0; + add_percent_row(m_strength_offsets_panel, minimum_offsets_box, i, offset_value, m_minimum_offset_sliders, m_minimum_offset_spins); + } + for (size_t i = 0; i < component_ids.size(); ++i) { + const int strength_value = i < component_strengths_pct.size() ? + std::clamp(int(std::lround(component_strengths_pct[i])), 0, 100) : + 100; + add_percent_row(m_strength_offsets_panel, strengths_box, i, strength_value, m_strength_sliders, m_strength_spins); + } + strength_offsets_root->Add(minimum_offsets_box, 0, wxEXPAND | wxBOTTOM, gap); + strength_offsets_root->Add(strengths_box, 0, wxEXPAND | wxBOTTOM, gap); + auto *reset_btn = new wxButton(m_strength_offsets_panel, wxID_ANY, _L("Reset strengths and offsets")); + reset_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { reset_strengths_and_offsets(); }); + strength_offsets_root->Add(reset_btn, 0, wxALIGN_RIGHT | wxBOTTOM, gap); + filament_root->Add(m_strength_offsets_panel, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, gap); + update_strength_offsets_visibility(false); + m_force_sequential_filaments_checkbox = new wxCheckBox(filament_page, wxID_ANY, _L("Force sequential order for filaments")); m_force_sequential_filaments_checkbox->SetValue(force_sequential_filaments); @@ -1463,12 +1479,7 @@ public: m_options_book->AddPage(preview_page, _L("Preview Options")); m_options_book->AddPage(experimental_page, _L("Experimental Options")); m_options_book->AddPage(global_page, _L("Prime Tower Texture Mapping")); - m_options_book->SetMinSize(wxSize(FromDIP(420), - std::max({image_page->GetBestSize().y, - filament_page->GetBestSize().y, - preview_page->GetBestSize().y, - experimental_page->GetBestSize().y, - global_page->GetBestSize().y}))); + update_options_book_min_size(); m_options_tab_choice->Bind(wxEVT_CHOICE, [this](wxCommandEvent &evt) { if (m_options_book) m_options_book->SetSelection(std::clamp(evt.GetSelection(), 0, 4)); @@ -1574,6 +1585,7 @@ public: const TextureMappingPrimeTowerImage& prime_tower_image() const { return m_prime_tower_image; } const TextureMappingPrimeTowerImage& prime_tower_image_back() const { return m_prime_tower_image_back; } int selected_options_tab() const { return std::clamp(m_options_tab_choice ? m_options_tab_choice->GetSelection() : 0, 0, 4); } + bool strength_offsets_expanded() const { return m_strength_offsets_expanded; } std::vector component_strengths_pct() const { @@ -1739,11 +1751,43 @@ private: spin->SetValue(100); } + void update_options_book_min_size() + { + if (m_options_book == nullptr) + return; + int max_height = 0; + for (size_t i = 0; i < m_options_book->GetPageCount(); ++i) { + wxWindow *page = m_options_book->GetPage(i); + if (page != nullptr) + max_height = std::max(max_height, page->GetBestSize().y); + } + m_options_book->SetMinSize(wxSize(FromDIP(420), max_height)); + } + + void update_strength_offsets_visibility(bool fit_dialog) + { + if (m_strength_offsets_toggle_button != nullptr) + m_strength_offsets_toggle_button->SetLabel(m_strength_offsets_expanded ? + _L("Hide Filament Strengths & Offsets") : + _L("Show Filament Strengths & Offsets")); + if (m_strength_offsets_panel != nullptr) + m_strength_offsets_panel->Show(m_strength_offsets_expanded); + if (!fit_dialog) + return; + update_options_book_min_size(); + if (GetSizer() != nullptr) { + Layout(); + Fit(); + } + } + wxChoice *m_options_tab_choice {nullptr}; wxSimplebook *m_options_book {nullptr}; wxChoice *m_texture_mapping_mode_choice {nullptr}; wxSpinCtrlDouble *m_tone_gamma_spin {nullptr}; wxChoice *m_transmission_distance_calibration_mode_choice {nullptr}; + wxButton *m_strength_offsets_toggle_button {nullptr}; + wxPanel *m_strength_offsets_panel {nullptr}; wxSlider *m_preview_opacity_slider {nullptr}; wxSpinCtrl *m_preview_opacity_spin {nullptr}; wxCheckBox *m_force_sequential_filaments_checkbox {nullptr}; @@ -1773,6 +1817,7 @@ private: std::vector m_strength_sliders; std::vector m_strength_spins; std::vector m_transmission_distance_spins; + bool m_strength_offsets_expanded {false}; }; } // namespace @@ -1909,6 +1954,7 @@ struct Sidebar::priv Button* m_btn_add_texture_map = nullptr; std::unordered_set m_expanded_texture_mapping_rows; int m_texture_mapping_advanced_options_tab = 0; + bool m_texture_mapping_filament_strength_offsets_expanded = false; wxPanel* m_panel_project_title; ScalableButton* m_filament_icon = nullptr; Button * m_flushing_volume_btn = nullptr; @@ -5748,9 +5794,11 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) bundle->texture_mapping_global_settings, wxGetApp().model().texture_mapping_prime_tower_image, wxGetApp().model().texture_mapping_prime_tower_image_back, - p->m_texture_mapping_advanced_options_tab); + p->m_texture_mapping_advanced_options_tab, + p->m_texture_mapping_filament_strength_offsets_expanded); const int result = dlg.ShowModal(); p->m_texture_mapping_advanced_options_tab = dlg.selected_options_tab(); + p->m_texture_mapping_filament_strength_offsets_expanded = dlg.strength_offsets_expanded(); if (result != wxID_OK) return; updated.texture_mapping_mode = dlg.texture_mapping_mode();