mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-10 17:21:10 +00:00
fix(imex): key the resolved tool roster and fw-managed flag in the zone/ghost cache
Review follow-up. Removing pem from the ghost cache key also removed its accidental role as the key's only printer-identity signal: the resolved active-tools string (roster + primary) and imex_firmware_managed_zones both shape the baked zone/ghost set but were never keyed directly, so a printer swap between presets with matching mode names and topology could leave a stale ghost set. Key all three in build_imex_cache_key, which also hardens the zone cache against the same pre-existing gap. Also from review: the tooltip swatch reuses the pem/map its label already hoisted (one resolution, not two); the bake constructs ghosts with no color at all, making update_imex_ghost_colors the sole color author; the headless !m_plater guard is documented as the wxGetApp sentinel it is. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
28c0c681fe
commit
8a5bc75e7b
@@ -1004,12 +1004,24 @@ std::string PartPlate::build_imex_cache_key() const
|
||||
auto* cw_opt = printer_cfg.option<ConfigOptionFloat>("imex_nozzle_clearance_x");
|
||||
auto* ch_opt = printer_cfg.option<ConfigOptionFloat>("imex_nozzle_clearance_y");
|
||||
auto* mgn_opt = printer_cfg.option<ConfigOptionFloat>("imex_carriage_margin");
|
||||
// Mode NAME alone is not printer identity: two presets can define the same mode
|
||||
// name with different tool rosters/primary, and imex_firmware_managed_zones
|
||||
// suppresses ghost generation entirely. Both shape the baked zone/ghost set, so
|
||||
// key them directly (previously caught only incidentally, via the ghost key's
|
||||
// since-removed pem entry).
|
||||
std::string active_tools;
|
||||
int primary_phys = -1;
|
||||
resolve_active_mode_tools(active_tools, primary_phys); // empty on failure — keyed as such
|
||||
auto* fw_opt = printer_cfg.option<ConfigOptionBool>("imex_firmware_managed_zones");
|
||||
return active_mode
|
||||
+ "|" + std::to_string(n_col_opt ? n_col_opt->value : 2)
|
||||
+ "x" + std::to_string(n_row_opt ? n_row_opt->value : 1)
|
||||
+ "|cw" + std::to_string(cw_opt ? (int)(cw_opt->value * 10) : 0)
|
||||
+ "|ch" + std::to_string(ch_opt ? (int)(ch_opt->value * 10) : 0)
|
||||
+ "|mg" + std::to_string(mgn_opt ? (int)(mgn_opt->value * 10) : 0);
|
||||
+ "|mg" + std::to_string(mgn_opt ? (int)(mgn_opt->value * 10) : 0)
|
||||
+ "|t" + active_tools
|
||||
+ "|p" + std::to_string(primary_phys)
|
||||
+ "|fw" + ((fw_opt && fw_opt->value) ? "1" : "0");
|
||||
}
|
||||
|
||||
// Reposition the IMEX mode icon without requiring a full set_shape() rebuild.
|
||||
@@ -1099,8 +1111,8 @@ bool PartPlate::resolve_active_mode_tools(std::string& out_tools_str, int& out_p
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ghost opacity. RGB is owned by update_imex_ghost_colors (restamped per frame);
|
||||
// calc_imex_ghosts only bakes this alpha into the volume.
|
||||
// Ghost opacity, stamped together with RGB by update_imex_ghost_colors every
|
||||
// frame — the sole author of ghost color.
|
||||
static constexpr float IMEX_GHOST_ALPHA = 0.55f;
|
||||
|
||||
void PartPlate::calc_imex_ghosts()
|
||||
@@ -1192,7 +1204,6 @@ void PartPlate::calc_imex_ghosts()
|
||||
return {aggregated_primary, aggregated_target - aggregated_primary};
|
||||
};
|
||||
|
||||
|
||||
// Mesh is object-local and identical across all instances and heads of a given object.
|
||||
// Build the merged TriangleMesh once per obj_idx and reuse across the inner head loop.
|
||||
// (Per-ghost GLModel::init_from still runs once each, since GLVolume owns its GLModel by value;
|
||||
@@ -1238,11 +1249,9 @@ void PartPlate::calc_imex_ghosts()
|
||||
primary_phys, phys, role, gantry, pri_center, mirror_axis_for(phys));
|
||||
const Transform3d ghost_xf = head_xf * inst_world;
|
||||
|
||||
// RGB here is a placeholder — update_imex_ghost_colors restamps every
|
||||
// ghost from the live filament palette each frame; only alpha matters.
|
||||
const ColorRGBA color = {0.5f, 0.5f, 0.5f, IMEX_GHOST_ALPHA};
|
||||
|
||||
auto ghost = std::make_unique<GLVolume>(color);
|
||||
// No color at bake time: update_imex_ghost_colors is the sole author of
|
||||
// ghost color, restamping RGB + alpha from the live palette every frame.
|
||||
auto ghost = std::make_unique<GLVolume>();
|
||||
ghost->set_instance_transformation(ghost_xf);
|
||||
ghost->force_transparent = 1;
|
||||
ghost->force_native_color = 1;
|
||||
@@ -1361,6 +1370,8 @@ void PartPlate::update_imex_ghost_transforms(
|
||||
// over the effective pem + per-plate override map), so the two cannot disagree.
|
||||
void PartPlate::update_imex_ghost_colors()
|
||||
{
|
||||
// !m_plater is the headless sentinel: without a GUI_App, calling wxGetApp()
|
||||
// below is unsafe — same guard pattern as ensure_imex_zones.
|
||||
if (m_imex_ghost_volumes.empty() || !m_plater) return;
|
||||
auto* pb = wxGetApp().preset_bundle;
|
||||
if (!pb) return;
|
||||
|
||||
@@ -20293,7 +20293,9 @@ Plater::ImexGhostTooltip Plater::format_imex_ghost_tooltip(int physical_head) co
|
||||
return t;
|
||||
}
|
||||
t.filament_slot_1based = logical + 1;
|
||||
t.swatch = plate->get_imex_head_filament_color(physical_head);
|
||||
// Reuse the pem/map already hoisted above so label and swatch are derived
|
||||
// from one resolution, not two.
|
||||
t.swatch = plate->get_imex_head_filament_color(physical_head, pem, map);
|
||||
t.swatch.a(1.0f); // tooltip swatch opaque
|
||||
t.label = "T" + std::to_string(physical_head) +
|
||||
" -> filament " + std::to_string(t.filament_slot_1based);
|
||||
|
||||
Reference in New Issue
Block a user