mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-06-13 07:23:03 +00:00
added support for >16 colors in color picker
This commit is contained in:
@@ -1448,7 +1448,12 @@ void TriangleSelector::get_facets(std::vector<indexed_triangle_set>& facets_per_
|
||||
{
|
||||
facets_per_type.clear();
|
||||
|
||||
for (int type = (int)EnforcerBlockerType::NONE; type <= (int)EnforcerBlockerType::ExtruderMax; type++) {
|
||||
int max_state = int(EnforcerBlockerType::NONE);
|
||||
for (const Triangle &tr : m_triangles)
|
||||
if (tr.valid() && !tr.is_split())
|
||||
max_state = std::max(max_state, int(tr.get_state()));
|
||||
|
||||
for (int type = int(EnforcerBlockerType::NONE); type <= max_state; ++type) {
|
||||
facets_per_type.emplace_back();
|
||||
indexed_triangle_set& its = facets_per_type.back();
|
||||
std::vector<int> vertex_map(m_vertices.size(), -1);
|
||||
@@ -1642,9 +1647,10 @@ void TriangleSelector::get_seed_fill_contour_recursive(const int facet_idx, cons
|
||||
|
||||
TriangleSelector::TriangleSplittingData TriangleSelector::serialize() const {
|
||||
// Each original triangle of the mesh is assigned a number encoding its state
|
||||
// or how it is split. Each triangle is encoded by 4 bits (xxyy) or 8 bits (zzzzxxyy):
|
||||
// or how it is split. Each triangle is encoded by 4 bits (xxyy) or by
|
||||
// 4 bits plus one or more extension nibbles:
|
||||
// leaf triangle: xx = EnforcerBlockerType (Only values 0, 1, and 2. Value 3 is used as an indicator for additional 4 bits.), yy = 0
|
||||
// leaf triangle: xx = 0b11, yy = 0b00, zzzz = EnforcerBlockerType (subtracted by 3)
|
||||
// leaf triangle: xx = 0b11, yy = 0b00, zzzz... = EnforcerBlockerType (subtracted by 3) in base-15 chunks
|
||||
// non-leaf: xx = special side, yy = number of split sides
|
||||
// These are bitwise appended and formed into one 64-bit integer.
|
||||
|
||||
@@ -1687,14 +1693,17 @@ TriangleSelector::TriangleSplittingData TriangleSelector::serialize() const {
|
||||
data.used_states[n] = true;
|
||||
|
||||
if (n >= 3) {
|
||||
assert(n <= 16);
|
||||
if (n <= 16) {
|
||||
// Store "11" plus 4 bits of (n-3).
|
||||
data.bitstream.insert(data.bitstream.end(), { true, true });
|
||||
n -= 3;
|
||||
// Store "11" plus one or more 4-bit chunks of (n - 3), where
|
||||
// 0b1111 indicates that another chunk follows.
|
||||
data.bitstream.insert(data.bitstream.end(), { true, true });
|
||||
n -= 3;
|
||||
while (n >= 15) {
|
||||
for (size_t bit_idx = 0; bit_idx < 4; ++bit_idx)
|
||||
data.bitstream.push_back(n & (uint64_t(0b0001) << bit_idx));
|
||||
data.bitstream.push_back(uint64_t(0b1111) & (uint64_t(0b0001) << bit_idx));
|
||||
n -= 15;
|
||||
}
|
||||
for (size_t bit_idx = 0; bit_idx < 4; ++bit_idx)
|
||||
data.bitstream.push_back(n & (uint64_t(0b0001) << bit_idx));
|
||||
} else {
|
||||
// Simple case, compatible with PrusaSlicer 2.3.1 and older for storing paint on supports and seams.
|
||||
// Store 2 bits of n.
|
||||
@@ -1890,7 +1899,16 @@ void TriangleSelector::TriangleSplittingData::update_used_states(const size_t bi
|
||||
if (const bool is_split = (code & 0b11) != 0; is_split)
|
||||
continue;
|
||||
|
||||
const uint8_t facet_state = (code & 0b1100) == 0b1100 ? read_next_nibble() + 3 : code >> 2;
|
||||
size_t facet_state = code >> 2;
|
||||
if ((code & 0b1100) == 0b1100) {
|
||||
size_t extension_count = 0;
|
||||
size_t next_code = read_next_nibble();
|
||||
while (next_code == 0b1111) {
|
||||
++extension_count;
|
||||
next_code = read_next_nibble();
|
||||
}
|
||||
facet_state = next_code + 15 * extension_count + 3;
|
||||
}
|
||||
assert(facet_state < this->used_states.size());
|
||||
if (facet_state >= this->used_states.size())
|
||||
continue;
|
||||
@@ -1920,9 +1938,19 @@ bool TriangleSelector::has_facets(const TriangleSplittingData &data, const Enfor
|
||||
auto num_children_or_state = [&next_nibble]() -> int {
|
||||
int code = next_nibble();
|
||||
int num_of_split_sides = code & 0b11;
|
||||
return num_of_split_sides == 0 ?
|
||||
((code & 0b1100) == 0b1100 ? next_nibble() + 3 : code >> 2) :
|
||||
- num_of_split_sides - 1;
|
||||
if (num_of_split_sides != 0)
|
||||
return - num_of_split_sides - 1;
|
||||
|
||||
if ((code & 0b1100) != 0b1100)
|
||||
return code >> 2;
|
||||
|
||||
int extension_count = 0;
|
||||
int next_code = next_nibble();
|
||||
while (next_code == 0b1111) {
|
||||
++extension_count;
|
||||
next_code = next_nibble();
|
||||
}
|
||||
return next_code + 15 * extension_count + 3;
|
||||
};
|
||||
|
||||
int state = num_children_or_state();
|
||||
|
||||
@@ -10,14 +10,15 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
enum class EnforcerBlockerType : int8_t {
|
||||
enum class EnforcerBlockerType : int16_t {
|
||||
// Maximum is 3. The value is serialized in TriangleSelector into 2 bits.
|
||||
NONE = 0,
|
||||
ENFORCER = 1,
|
||||
BLOCKER = 2,
|
||||
// For the fuzzy skin, we use just two values (NONE and FUZZY_SKIN).
|
||||
FUZZY_SKIN = ENFORCER,
|
||||
// Maximum is 15. The value is serialized in TriangleSelector into 6 bits using a 2 bit prefix code.
|
||||
// Extruder states are serialized using a 2-bit prefix plus one or more 4-bit nibbles.
|
||||
// This allows more than 16 painted states while keeping backward compatibility.
|
||||
Extruder1 = ENFORCER,
|
||||
Extruder2 = BLOCKER,
|
||||
Extruder3,
|
||||
@@ -34,7 +35,7 @@ enum class EnforcerBlockerType : int8_t {
|
||||
Extruder14,
|
||||
Extruder15,
|
||||
Extruder16,
|
||||
ExtruderMax = Extruder16
|
||||
ExtruderMax = 255
|
||||
};
|
||||
|
||||
// Type alias for the state mapping array to improve code readability
|
||||
|
||||
@@ -33,7 +33,7 @@ static inline void show_notification_extruders_limit_exceeded()
|
||||
|
||||
void GLGizmoMmuSegmentation::on_opening()
|
||||
{
|
||||
if (wxGetApp().filaments_cnt() > int(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT))
|
||||
if (get_extruders_colors().size() > GLGizmoMmuSegmentation::EXTRUDERS_LIMIT)
|
||||
show_notification_extruders_limit_exceeded();
|
||||
}
|
||||
|
||||
@@ -89,10 +89,11 @@ static std::vector<int> get_extruder_id_for_volumes(const ModelObject &model_obj
|
||||
return extruders_idx;
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::init_extruders_data()
|
||||
void GLGizmoMmuSegmentation::init_extruders_data(const std::vector<ColorRGBA> &extruder_colors)
|
||||
{
|
||||
m_extruders_colors = get_extruders_colors();
|
||||
m_selected_extruder_idx = 0;
|
||||
const size_t old_selected = m_selected_extruder_idx;
|
||||
m_extruders_colors = extruder_colors;
|
||||
m_selected_extruder_idx = m_extruders_colors.empty() ? 0 : std::min(old_selected, m_extruders_colors.size() - 1);
|
||||
|
||||
// keep remap table consistent with current extruder count
|
||||
m_extruder_remap.resize(m_extruders_colors.size());
|
||||
@@ -100,6 +101,11 @@ void GLGizmoMmuSegmentation::init_extruders_data()
|
||||
m_extruder_remap[i] = i;
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::init_extruders_data()
|
||||
{
|
||||
init_extruders_data(get_extruders_colors());
|
||||
}
|
||||
|
||||
bool GLGizmoMmuSegmentation::on_init()
|
||||
{
|
||||
// BBS
|
||||
@@ -188,18 +194,20 @@ void GLGizmoMmuSegmentation::data_changed(bool is_serializing)
|
||||
return;
|
||||
|
||||
ModelObject* model_object = m_c->selection_info()->model_object();
|
||||
int prev_extruders_count = int(m_extruders_colors.size());
|
||||
if (prev_extruders_count != wxGetApp().filaments_cnt()) {
|
||||
if (wxGetApp().filaments_cnt() > int(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT))
|
||||
const std::vector<ColorRGBA> current_extruder_colors = get_extruders_colors();
|
||||
const int prev_extruders_count = int(m_extruders_colors.size());
|
||||
const int current_extruders_count = int(current_extruder_colors.size());
|
||||
if (prev_extruders_count != current_extruders_count) {
|
||||
if (current_extruder_colors.size() > GLGizmoMmuSegmentation::EXTRUDERS_LIMIT)
|
||||
show_notification_extruders_limit_exceeded();
|
||||
|
||||
this->init_extruders_data();
|
||||
this->init_extruders_data(current_extruder_colors);
|
||||
// Reinitialize triangle selectors because of change of extruder count need also change the size of GLIndexedVertexArray
|
||||
if (prev_extruders_count != wxGetApp().filaments_cnt())
|
||||
if (prev_extruders_count != current_extruders_count)
|
||||
this->init_model_triangle_selectors();
|
||||
}
|
||||
else if (get_extruders_colors() != m_extruders_colors) {
|
||||
this->init_extruders_data();
|
||||
else if (current_extruder_colors != m_extruders_colors) {
|
||||
this->init_extruders_data(current_extruder_colors);
|
||||
this->update_triangle_selectors_colors();
|
||||
}
|
||||
else if (model_object != nullptr && get_extruder_id_for_volumes(*model_object) != m_volumes_extruder_idxs) {
|
||||
@@ -251,14 +259,14 @@ static void render_extruders_combo(const std::string& label,
|
||||
size_t& selection_idx)
|
||||
{
|
||||
assert(!extruders_colors.empty());
|
||||
assert(extruders_colors.size() == extruders_colors.size());
|
||||
assert(extruders.size() == extruders_colors.size());
|
||||
|
||||
size_t selection_out = selection_idx;
|
||||
// It is necessary to use BeginGroup(). Otherwise, when using SameLine() is called, then other items will be drawn inside the combobox.
|
||||
ImGui::BeginGroup();
|
||||
ImVec2 combo_pos = ImGui::GetCursorScreenPos();
|
||||
if (ImGui::BeginCombo(label.c_str(), "")) {
|
||||
for (size_t extruder_idx = 0; extruder_idx < std::min(extruders.size(), GLGizmoMmuSegmentation::EXTRUDERS_LIMIT); ++extruder_idx) {
|
||||
for (size_t extruder_idx = 0; extruder_idx < extruders.size(); ++extruder_idx) {
|
||||
ImGui::PushID(int(extruder_idx));
|
||||
ImVec2 start_position = ImGui::GetCursorScreenPos();
|
||||
|
||||
@@ -371,6 +379,9 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
const float buttons_width = remove_btn_width + filter_btn_width + remap_btn_width + m_imgui->scaled(2.f);
|
||||
const float minimal_slider_width = m_imgui->scaled(4.f);
|
||||
const float color_button_width = m_imgui->calc_text_size(std::string_view{""}).x + m_imgui->scaled(1.75f);
|
||||
const size_t total_filament_count = m_extruders_colors.size();
|
||||
const std::string max_filament_label = std::to_string(std::max<size_t>(total_filament_count, 1));
|
||||
const ImVec2 max_filament_label_size = ImGui::CalcTextSize(max_filament_label.c_str(), NULL, true);
|
||||
|
||||
float caption_max = 0.f;
|
||||
float total_text_max = 0.f;
|
||||
@@ -390,7 +401,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
float window_width = minimal_slider_width + sliders_left_width + slider_icon_width;
|
||||
const int max_filament_items_per_line = 8;
|
||||
const float empty_button_width = m_imgui->calc_button_size("").x;
|
||||
const float filament_item_width = empty_button_width + m_imgui->scaled(1.5f);
|
||||
const float filament_item_width = std::max(empty_button_width, max_filament_label_size.x + m_imgui->scaled(1.4f)) + m_imgui->scaled(1.5f);
|
||||
|
||||
window_width = std::max(window_width, total_text_max);
|
||||
window_width = std::max(window_width, buttons_width);
|
||||
@@ -410,17 +421,15 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
m_imgui->text(m_desc.at("filaments"));
|
||||
|
||||
float start_pos_x = ImGui::GetCursorPos().x;
|
||||
const ImVec2 max_label_size = ImGui::CalcTextSize("99", NULL, true);
|
||||
const float item_spacing = m_imgui->scaled(0.8f);
|
||||
size_t n_extruder_colors = std::min((size_t)EnforcerBlockerType::ExtruderMax, m_extruders_colors.size());
|
||||
for (int extruder_idx = 0; extruder_idx < n_extruder_colors; extruder_idx++) {
|
||||
size_t n_extruder_colors = std::min(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT, m_extruders_colors.size());
|
||||
for (size_t extruder_idx = 0; extruder_idx < n_extruder_colors; ++extruder_idx) {
|
||||
const ColorRGBA &extruder_color = m_extruders_colors[extruder_idx];
|
||||
ImVec4 color_vec = ImGuiWrapper::to_ImVec4(extruder_color);
|
||||
std::string color_label = std::string("##extruder color ") + std::to_string(extruder_idx);
|
||||
std::string item_text = std::to_string(extruder_idx + 1);
|
||||
const ImVec2 label_size = ImGui::CalcTextSize(item_text.c_str(), NULL, true);
|
||||
|
||||
const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f),0.f);
|
||||
const ImVec2 button_size(max_filament_label_size.x + m_imgui->scaled(0.5f), 0.f);
|
||||
|
||||
float button_offset = start_pos_x;
|
||||
if (extruder_idx % max_filament_items_per_line != 0) {
|
||||
@@ -449,7 +458,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
color_button_high = ImGui::GetCursorPos().y - color_button - 2.0;
|
||||
if (color_picked) { m_selected_extruder_idx = extruder_idx; }
|
||||
|
||||
if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
if (extruder_idx < 9)
|
||||
m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width);
|
||||
else
|
||||
m_imgui->tooltip(wxString::Format(_L("Filament %d"), int(extruder_idx + 1)), max_tooltip_width);
|
||||
}
|
||||
|
||||
// draw filament id
|
||||
float gray = 0.299 * extruder_color.r() + 0.587 * extruder_color.g() + 0.114 * extruder_color.b();
|
||||
@@ -465,6 +479,21 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
||||
//ImGui::NewLine();
|
||||
ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1));
|
||||
|
||||
if (n_extruder_colors > 0) {
|
||||
int selected_filament = int(m_selected_extruder_idx) + 1;
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text(_L("Selected filament"));
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(m_imgui->scaled(4.5f));
|
||||
if (ImGui::InputInt("##selected_filament", &selected_filament, 1, 10, ImGuiInputTextFlags_CharsDecimal)) {
|
||||
selected_filament = std::clamp(selected_filament, 1, int(n_extruder_colors));
|
||||
m_selected_extruder_idx = size_t(selected_filament - 1);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
m_imgui->text(wxString::Format(_L("/ %d"), int(n_extruder_colors)));
|
||||
ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1));
|
||||
}
|
||||
|
||||
m_imgui->text(m_desc.at("tool_type"));
|
||||
|
||||
std::array<wchar_t, 6> tool_ids;
|
||||
@@ -857,9 +886,10 @@ void GLGizmoMmuSegmentation::update_from_model_object(bool first_update)
|
||||
|
||||
// Extruder colors need to be reloaded before calling init_model_triangle_selectors to render painted triangles
|
||||
// using colors from loaded 3MF and not from printer profile in Slicer.
|
||||
const std::vector<ColorRGBA> current_extruder_colors = get_extruders_colors();
|
||||
if (int prev_extruders_count = int(m_extruders_colors.size());
|
||||
prev_extruders_count != wxGetApp().filaments_cnt() || get_extruders_colors() != m_extruders_colors)
|
||||
this->init_extruders_data();
|
||||
prev_extruders_count != int(current_extruder_colors.size()) || current_extruder_colors != m_extruders_colors)
|
||||
this->init_extruders_data(current_extruder_colors);
|
||||
|
||||
this->init_model_triangle_selectors();
|
||||
}
|
||||
@@ -907,7 +937,7 @@ wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GL
|
||||
if (shift_down)
|
||||
action_name = _L("Remove painted color");
|
||||
else {
|
||||
action_name = GUI::format(_L("Painted using: Filament %1%"), m_selected_extruder_idx);
|
||||
action_name = GUI::format(_L("Painted using: Filament %1%"), m_selected_extruder_idx + 1);
|
||||
}
|
||||
return action_name;
|
||||
}
|
||||
@@ -993,15 +1023,20 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float
|
||||
{
|
||||
size_t n_extr = std::min((size_t)EnforcerBlockerType::ExtruderMax, m_extruders_colors.size());
|
||||
|
||||
const ImVec2 max_label_size = ImGui::CalcTextSize("99", NULL, true);
|
||||
const std::string max_label = std::to_string(std::max<size_t>(n_extr, 1));
|
||||
const ImVec2 max_label_size = ImGui::CalcTextSize(max_label.c_str(), NULL, true);
|
||||
const ImVec2 button_size(max_label_size.x + m_imgui->scaled(0.5f), 0.f);
|
||||
const int max_items_per_line = 8;
|
||||
const float item_width = button_size.x + m_imgui->scaled(1.5f);
|
||||
const float start_pos_x = ImGui::GetCursorPosX();
|
||||
|
||||
for (int src = 0; src < (int)n_extr; ++src) {
|
||||
const ColorRGBA &src_col = m_extruders_colors[src]; // keep for text contrast
|
||||
const ColorRGBA &dst_col = m_extruders_colors[m_extruder_remap[src]];
|
||||
ImVec4 col_vec = ImGuiWrapper::to_ImVec4(dst_col);
|
||||
|
||||
if (src) ImGui::SameLine();
|
||||
if (src % max_items_per_line != 0) {
|
||||
ImGui::SameLine(start_pos_x + item_width * (src % max_items_per_line));
|
||||
}
|
||||
std::string btn_id = "##remap_src_" + std::to_string(src);
|
||||
|
||||
ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs |
|
||||
@@ -1062,11 +1097,13 @@ void GLGizmoMmuSegmentation::render_filament_remap_ui(float window_width, float
|
||||
ImGui::PushStyleColor(ImGuiCol_Border, m_is_dark_mode ? ImVec4(0.5f, 0.5f, 0.5f, 1.0f) : ImVec4(0.6f, 0.6f, 0.6f, 1.0f));
|
||||
|
||||
if (ImGui::BeginPopup(pop_id.c_str())) {
|
||||
const float popup_start_pos_x = ImGui::GetCursorPosX();
|
||||
|
||||
for (int dst = 0; dst < (int)n_extr; ++dst) {
|
||||
const ColorRGBA &dst_col_popup = m_extruders_colors[dst];
|
||||
ImVec4 dst_vec = ImGuiWrapper::to_ImVec4(dst_col_popup);
|
||||
if (dst) ImGui::SameLine();
|
||||
if (dst % max_items_per_line != 0)
|
||||
ImGui::SameLine(popup_start_pos_x + item_width * (dst % max_items_per_line));
|
||||
std::string dst_btn = "##dst_" + std::to_string(src) + "_" + std::to_string(dst);
|
||||
|
||||
// Apply same styling to destination buttons
|
||||
|
||||
@@ -71,11 +71,8 @@ public:
|
||||
|
||||
void data_changed(bool is_serializing) override;
|
||||
|
||||
// TriangleSelector::serialization/deserialization has a limit to store 19 different states.
|
||||
// EXTRUDER_LIMIT + 1 states are used to storing the painting because also uncolored triangles are stored.
|
||||
// When increasing EXTRUDER_LIMIT, it needs to ensure that TriangleSelector::serialization/deserialization
|
||||
// will be also extended to support additional states, requiring at least one state to remain free out of 19 states.
|
||||
static const constexpr size_t EXTRUDERS_LIMIT = 16;
|
||||
// Keep this in sync with the shared triangle-selector state range.
|
||||
static const constexpr size_t EXTRUDERS_LIMIT = static_cast<size_t>(EnforcerBlockerType::ExtruderMax);
|
||||
|
||||
const float get_cursor_radius_min() const override { return CursorRadiusMin; }
|
||||
|
||||
@@ -136,6 +133,7 @@ private:
|
||||
// BBS
|
||||
void update_triangle_selectors_colors();
|
||||
void init_extruders_data();
|
||||
void init_extruders_data(const std::vector<ColorRGBA> &extruder_colors);
|
||||
|
||||
// Filament remapping methods
|
||||
void remap_filament_assignments();
|
||||
|
||||
@@ -1283,11 +1283,15 @@ void TriangleSelectorPatch::render(ImGuiWrapper* imgui, const Transform3d& matri
|
||||
ColorRGBA color;
|
||||
if (patch.is_fragment() && !patch.neighbor_types.empty()) {
|
||||
size_t color_idx = (size_t)*patch.neighbor_types.begin();
|
||||
if (color_idx >= m_ebt_colors.size())
|
||||
continue;
|
||||
color = m_ebt_colors[color_idx];
|
||||
color.a(0.85);
|
||||
}
|
||||
else {
|
||||
size_t color_idx = (size_t)patch.type;
|
||||
if (color_idx >= m_ebt_colors.size())
|
||||
continue;
|
||||
color = m_ebt_colors[color_idx];
|
||||
}
|
||||
//to make black not too hard too see
|
||||
@@ -1303,7 +1307,7 @@ void TriangleSelectorPatch::render(ImGuiWrapper* imgui, const Transform3d& matri
|
||||
void TriangleSelectorPatch::update_triangles_per_type()
|
||||
{
|
||||
//BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", enter");
|
||||
m_triangle_patches.resize((int)EnforcerBlockerType::ExtruderMax + 1);
|
||||
m_triangle_patches.resize(m_ebt_colors.size());
|
||||
for (int i = 0; i < m_triangle_patches.size(); i++) {
|
||||
auto& patch = m_triangle_patches[i];
|
||||
patch.type = (EnforcerBlockerType)i;
|
||||
@@ -1317,6 +1321,8 @@ void TriangleSelectorPatch::update_triangles_per_type()
|
||||
continue;
|
||||
|
||||
int state = (int)triangle.get_state();
|
||||
if (state < 0 || state >= int(m_triangle_patches.size()))
|
||||
continue;
|
||||
auto& patch = m_triangle_patches[state];
|
||||
//patch.triangle_indices.insert(patch.triangle_indices.end(), triangle.verts_idxs.begin(), triangle.verts_idxs.end());
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
|
||||
@@ -11,6 +11,7 @@ add_executable(${_TEST_NAME}_tests
|
||||
test_elephant_foot_compensation.cpp
|
||||
test_geometry.cpp
|
||||
test_mixed_filament.cpp
|
||||
test_triangle_selector.cpp
|
||||
test_local_z_order_optimizer.cpp
|
||||
test_placeholder_parser.cpp
|
||||
test_polygon.cpp
|
||||
|
||||
39
tests/libslic3r/test_triangle_selector.cpp
Normal file
39
tests/libslic3r/test_triangle_selector.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/TriangleSelector.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
TEST_CASE("Triangle selector round-trips painted states above sixteen", "[TriangleSelector][MMUPaint]")
|
||||
{
|
||||
indexed_triangle_set its;
|
||||
its.vertices = {
|
||||
Vec3f(0.f, 0.f, 0.f),
|
||||
Vec3f(1.f, 0.f, 0.f),
|
||||
Vec3f(0.f, 1.f, 0.f),
|
||||
};
|
||||
its.indices = {
|
||||
stl_triangle_vertex_indices(0, 1, 2),
|
||||
};
|
||||
|
||||
TriangleMesh mesh(its);
|
||||
TriangleSelector selector(mesh);
|
||||
|
||||
constexpr int painted_state = 120;
|
||||
selector.set_facet(0, static_cast<EnforcerBlockerType>(painted_state));
|
||||
|
||||
auto data = selector.serialize();
|
||||
REQUIRE_FALSE(data.triangles_to_split.empty());
|
||||
REQUIRE(data.used_states.size() > painted_state);
|
||||
CHECK(data.used_states[painted_state]);
|
||||
|
||||
data.reset_used_states();
|
||||
data.update_used_states(size_t(data.triangles_to_split.front().bitstream_start_idx));
|
||||
CHECK(data.used_states[painted_state]);
|
||||
CHECK(TriangleSelector::has_facets(data, static_cast<EnforcerBlockerType>(painted_state)));
|
||||
|
||||
TriangleSelector restored(mesh);
|
||||
restored.deserialize(data, true, static_cast<EnforcerBlockerType>(painted_state));
|
||||
CHECK(restored.has_facets(static_cast<EnforcerBlockerType>(painted_state)));
|
||||
}
|
||||
Reference in New Issue
Block a user