Fixes from Full spectrum port

https://github.com/OrcaSlicer/OrcaSlicer/pull/14383
This commit is contained in:
Ian Bassi
2026-08-23 22:11:48 +08:00
committed by SoftFever
parent 86a7e93a48
commit 42f708bbb6
14 changed files with 288 additions and 65 deletions
+12 -6
View File
@@ -682,13 +682,19 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj
if (shader) {
if (idx == 0) {
int extruder_id = model_volume->extruder_id();
//to make black not too hard too see
ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[extruder_id - 1]);
if (ban_light) {
new_color[3] = (255 - (extruder_id - 1))/255.0f;
// ORCA: extruder_id may be 0 (unset) or point past the colour list after a
// filament is deleted/remapped, so clamp the index instead of reading out of
// bounds.
if (!extruder_colors.empty()) {
int color_idx = std::clamp(extruder_id - 1, 0, int(extruder_colors.size()) - 1);
//to make black not too hard too see
ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[color_idx]);
if (ban_light) {
new_color[3] = (255 - color_idx)/255.0f;
}
m.set_color(new_color);
// shader->set_uniform("uniform_color", new_color);
}
m.set_color(new_color);
// shader->set_uniform("uniform_color", new_color);
}
else {
if (idx <= extruder_colors.size()) {
+32 -28
View File
@@ -577,36 +577,40 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
}
// BBS
// A per-role filament override must name a real, physical filament. Out-of-range values are
// stale; a mixed-color slot is virtual and cannot be driven directly by a role override, so
// both are reset to 0 ("inherit the object's filament"). The object's own extruder assignment
// is what legitimately carries a mixed slot. Orca splits BBS's wall/solid_infill roles into
// six keys, so all of them are checked here.
static const char* keys[] = { "support_filament", "support_interface_filament",
"outer_wall_filament_id", "inner_wall_filament_id",
"sparse_infill_filament_id", "internal_solid_filament_id",
"top_surface_filament_id", "bottom_surface_filament_id" };
for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
std::string key = std::string(keys[i]);
// A filament override naming a slot that no longer exists is stale and falls back to the
// plater's value. Support is additionally restricted to physical filaments: the support paths
// (ToolOrdering::collect_extruders, Print::validate) consume support_filament directly, with
// no per-layer mixed resolution, so a virtual slot there would reach the G-code unresolved.
// The per-feature keys have no such restriction — LayerTools::extruder() and its siblings
// resolve a mixed slot to the physical filament chosen for each layer.
static const char* support_keys[] = { "support_filament", "support_interface_filament" };
static const char* feature_keys[] = { "outer_wall_filament_id", "inner_wall_filament_id",
"sparse_infill_filament_id", "internal_solid_filament_id",
"top_surface_filament_id", "bottom_surface_filament_id" };
auto reset_invalid_filament = [this, config, filament_cnt](const char* key, bool allow_mixed) {
auto* opt = dynamic_cast<ConfigOptionInt*>(config->option(key, false));
if (opt != nullptr) {
int val = opt->getInt();
bool out_of_range = val > filament_cnt;
bool is_mixed = (val > 0 && val <= filament_cnt &&
wxGetApp().preset_bundle->is_mixed_filament(val - 1));
if (out_of_range || is_mixed) {
DynamicPrintConfig new_conf = *config;
int new_value = 0;
if (out_of_range) {
const DynamicPrintConfig *conf_temp = wxGetApp().plater()->config();
if (conf_temp != nullptr && conf_temp->has(key))
new_value = conf_temp->opt_int(key);
}
new_conf.set_key_value(key, new ConfigOptionInt(new_value));
apply(config, &new_conf);
}
if (opt == nullptr)
return;
const int val = opt->getInt();
const bool out_of_range = val > filament_cnt;
const bool is_mixed = !allow_mixed && val > 0 && val <= filament_cnt &&
wxGetApp().preset_bundle->is_mixed_filament(val - 1);
if (!out_of_range && !is_mixed)
return;
DynamicPrintConfig new_conf = *config;
int new_value = 0;
if (out_of_range) {
const DynamicPrintConfig *conf_temp = wxGetApp().plater()->config();
if (conf_temp != nullptr && conf_temp->has(key))
new_value = conf_temp->opt_int(key);
}
}
new_conf.set_key_value(key, new ConfigOptionInt(new_value));
apply(config, &new_conf);
};
for (const char* key : support_keys)
reset_invalid_filament(key, false);
for (const char* key : feature_keys)
reset_invalid_filament(key, true);
// Sub-layer splitting divides each layer by the mix ratio; an adaptive layer profile makes
// those sub-layer heights vary per layer, which degrades the blend. Warn once per enable.
+8
View File
@@ -9681,6 +9681,14 @@ void GLCanvas3D::_render_paint_toolbar() const
}
}
}
// ORCA: the loop above only produces a label for a slot whose preset is found in the preset
// collection, while the render loop below iterates extruder_num (= colour count). Pad the
// label arrays so a slot without a matching preset cannot index past them — reading a garbage
// std::string here crashes in ImGui::CalcTextSize (strlen).
while (int(filament_text_first_line.size()) < extruder_num) {
filament_text_first_line.emplace_back();
filament_text_second_line.emplace_back();
}
ImGuiWrapper& imgui = *wxGetApp().imgui();
const float canvas_w = float(get_canvas_size().get_width());
@@ -454,7 +454,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
ImGui::GetWindowDrawList()->AddRectFilledMultiColor(r_min, r_max, col_from, col_to, col_to, col_from);
}
if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width);
if (extruder_idx < int(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT) && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width);
}
// ORCA: Remap filaments section (Border only, Title in border).
// Styled as a panel for visual grouping.
@@ -73,11 +73,10 @@ 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;
// The paint material limit follows EnforcerBlockerType::ExtruderMax: TriangleSelector
// serialization covers the extended (17..32) range through an escape nibble. Mixed-color
// filaments occupy ordinary slots, so they draw from the same budget as physical ones.
static const constexpr size_t EXTRUDERS_LIMIT = static_cast<size_t>(EnforcerBlockerType::ExtruderMax);
// Endpoint colours for gradient mixed filaments, mirrored from Plater so the extruder
// swatches below can be drawn as a two-tone fade instead of a single blended colour.
+37 -9
View File
@@ -998,16 +998,40 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
keyCode = keyCode- WXK_NUMPAD0+'0';
}
if (keyCode >= '0' && keyCode <= '9') {
if (keyCode == '1' && !m_timer_set_color.IsRunning()) {
// The paint palette now reaches EXTRUDERS_LIMIT (mixed-color filaments share
// the same slots), so any leading digit that can start a valid two-digit
// number waits briefly for a second one.
const int digit = keyCode - '0';
const int shortcut_max = int(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT);
auto can_start_two_digit = [shortcut_max](int d) { return d > 0 && d * 10 <= shortcut_max; };
auto select = [mmu_seg](int number) { return number > 0 && mmu_seg->on_number_key_down(number); };
if (m_timer_set_color.IsRunning() && m_pending_color_shortcut_tens > 0) {
const int two_digit = m_pending_color_shortcut_tens * 10 + digit;
const int pending = m_pending_color_shortcut_tens;
m_pending_color_shortcut_tens = 0;
m_timer_set_color.Stop();
if (two_digit <= shortcut_max) {
processed = select(two_digit);
} else {
// Out of range: commit the pending digit, then treat this one as new input.
processed = select(pending);
if (can_start_two_digit(digit)) {
m_pending_color_shortcut_tens = digit;
m_timer_set_color.StartOnce(500);
processed = true;
} else {
processed = select(digit) || processed;
}
}
}
else if (can_start_two_digit(digit)) {
m_pending_color_shortcut_tens = digit;
m_timer_set_color.StartOnce(500);
processed = true;
}
else if (keyCode < '7' && m_timer_set_color.IsRunning()) {
processed = mmu_seg->on_number_key_down(keyCode - '0'+10);
m_timer_set_color.Stop();
}
else {
processed = mmu_seg->on_number_key_down(keyCode - '0');
processed = select(digit);
}
}
else if (keyCode == 'F' || keyCode == 'T' || keyCode == 'S' || keyCode == 'C' || keyCode == 'H' || keyCode == 'G') {
@@ -1054,11 +1078,15 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
void GLGizmosManager::on_set_color_timer(wxTimerEvent& evt)
{
if (m_current == MmSegmentation) {
// No second digit arrived in time: commit the pending leading digit on its own.
if (m_current == MmSegmentation && m_pending_color_shortcut_tens > 0) {
GLGizmoMmuSegmentation* mmu_seg = dynamic_cast<GLGizmoMmuSegmentation*>(get_current());
mmu_seg->on_number_key_down(1);
m_parent.set_as_dirty();
if (mmu_seg != nullptr) {
mmu_seg->on_number_key_down(m_pending_color_shortcut_tens);
m_parent.set_as_dirty();
}
}
m_pending_color_shortcut_tens = 0;
}
void GLGizmosManager::update_after_undo_redo(const UndoRedo::Snapshot& snapshot)
@@ -144,6 +144,8 @@ private:
//When there are more than 9 colors, shortcut key coloring
wxTimer m_timer_set_color;
// Leading digit of a two-digit color shortcut still waiting for its second digit.
int m_pending_color_shortcut_tens = 0;
void on_set_color_timer(wxTimerEvent& evt);
// key MENU_ICON_NAME, value = ImtextureID