* fix(deps): build the dependencies from scratch with clang-cl
Six dependencies fail once the superbuild compiles them with clang-cl instead
of cl:
- OpenSSL never goes through CMake. Its VC-WIN64A makefile only works with cl,
and an unquoted clang-cl path with spaces produces no .obj files at all, so
the lib step dies with LNK1181. Pin the upstream toolchain.
- Boost.Container's bundled dlmalloc passes int* to the Interlocked API. cl
warns, clang rejects it.
- curl 7.75's configure probes rely on C laxness clang rejects. The results
flip and nonblock.c ends up in the AmigaOS IoctlSocket branch.
- OCCT installs RelWithDebInfo into bini/libi while find_package looks in lib.
It also prepends -Wl,-s to the shared linker flags for every Clang build,
which the MSVC-style linker gets as an argument it does not know. Both
patched hunks sit inside if (MSVC) in the OCCT sources.
- wxWidgets lands in lib/clang_x64_lib, so wxWidgetsConfig.cmake falls back to
the layout that exists instead of assuming vc_x64_lib. It tries the derived
path first, so a cl-built tree consumed by clang-cl keeps resolving the way
it does today. The patch step also resets the one file it touches, so it can
run again after an interrupted build or after the patch itself changed.
- wxInspector goes through FindwxWidgets, which only searches lib/vc*_lib
because _WX_TOOL is hardcoded to vc. It now gets the root and lib dir
derived the same way wxWidgetsConfig.cmake derives them.
Eigen is the seventh, and it breaks on the generator rather than the compiler.
Its test, lapack and blas/testing subdirectories all call
enable_language(Fortran), and they default to ON because the dependency
configures as its own top-level project. Whether that hurts depends on what
CMake finds: the Visual Studio generator supports no Fortran and finds nothing,
clang-cl sits next to the LLVM toolset's flang and works, while MSVC with Ninja
finds Strawberry Perl's MinGW gfortran, which this build already requires for
OpenSSL, and hands it the MSVC-style /machine:x64 that MinGW's ld reads as a
missing input file. The configure dies there and takes every dependency still
in flight with it. Only the headers are consumed here, so the three subprojects
are off.
* fix(deps): honor the superbuild's generator and compiler in sub-builds
orcaslicer_add_cmake_project pinned every dependency sub-build to the Visual
Studio generator whenever MSVC was true, which is also true for clang-cl. That
generator selects its compiler by toolset and ignores the CMAKE_C_COMPILER and
CMAKE_CXX_COMPILER this file already forwards, so the dependencies were built
with cl.exe no matter which generator or compiler the superbuild was given.
Key the three affected decisions on the generator instead: which generator the
sub-builds use, whether CMAKE_BUILD_TYPE is forwarded, and /m versus -j. A
Visual Studio superbuild is unchanged, so the default path and CI behave
exactly as they do today.
build_release_vs.bat now accepts -l to select clang-cl, alongside the existing
-x for Ninja, so the generator and the compiler can be chosen independently. On
the Visual Studio generator -l reaches the slicer only, through the ClangCL
toolset, because the dependency sub-builds have no toolset to inherit; a deps
build in that combination says so rather than quietly using MSVC.
* fix(deps): use upstream wxWidgets compiler layout fix
The compiler-prefix layout fix now comes from SoftFever/Orca-deps-wxWidgets#7, so remove the duplicated local patch and apply step.
* fix(deps): stop Assimp enabling ccache on the RC rule
ASSIMP_BUILD_USE_CCACHE defaults on and applies the launcher through the
global RULE_LAUNCH_COMPILE property, so it wraps the resource-compiler rule
as well. Under Ninja that rule goes through cmcldeps, which does not survive
being launched by ccache, and the build fails with clang-cl reporting /fo as
a missing file.
The superbuild already forwards CMAKE_<LANG>_COMPILER_LAUNCHER, which CMake
applies per language and so keeps clear of the RC rule.
---------
Co-authored-by: SoftFever <103989404+SoftFever@users.noreply.github.com>
Co-authored-by: raistlin7447 <kris.austin@gmail.com>
Validate mixed-filament definitions during the published material pass: definitions whose components reference slots that do not exist or hold other mixed filaments, or that carry fewer than two components, are reported through the shared skipped_keys channel instead of shipping a mix the GUI integrity check would only flag later.
Fix the slot-limit exhaustion report being silently dropped: it wrote to published_config->skipped_keys, which the pass's final move-assignment from the local vector clobbers. All rejections now go through the local.
Remove the unreachable persist branch from add_detached_preset: no caller passes save_to_project=false, so the parameter is gone and the copy is always project-embedded.
Tests: cover the exhaustion path, the new definition validation, the identity-tier matching matrix (including substitute reporting), the structural-key denylist, whole-vector size-mismatch skips, relocation payload degradation, the "(Published 2)" uniquify chain, mixed blend colours staying out of shared preset configs, and duplicate-slot last-wins. Also fix the legacy-3mf scenario passing vacuously behind an if-guarded assertion. All existing published/3mf tests pass unchanged.
SLIC3R_CAD=OFF now builds without SolveSpace or OCCT's ModelingAlgorithms
module, leaving the dependency set identical to upstream's, and the Design
tab's mate connector preference no longer appears in builds without the tab.
When the deps prefix and the project disagree about the option, the configure
fails naming the cause, rather than failing at link time or at first launch
on Windows. The Windows packaging step stages exactly the toolkits libslic3r
links.
The Camera is Plater-owned and shared by every canvas, and Design sits
outside the panel switch that saves and restores it for Prepare,
Preview and Assemble — so orbiting in Design moved what the editor
tabs showed, and Design lost its own view on every switch. Trade the
live camera for a parked one on the way in and back on the way out, so
Design keeps its view the way Assemble already does.
New Project and Open Project went through Plater::priv::reset, which
drops ModelObjects but not the Model-level recipe, and never touched
the Design panel's document at all — so the previous design stayed
loaded and its next edit wrote itself into the new project.
A design that has not been committed to the plate has no ModelObjects,
so the project also read as clean: no autosave, and no unsaved-changes
prompt before the reset threw the design away.
DesignPanel's constructor creates several hundred controls and its own GL
canvas, which every launch paid for whether or not the user ever opened the
tab. The notebook page is now an empty placeholder and the panel is built
into it the first time the tab is selected, so m_design_panel stays null
until then.
This also lifts the ordering constraint that had pushed the plater's
background colour and Hide() below the panel construction; they go back
where they were.
append_tcr2 scanned the tower's G-code for a "preheat T<n>" comment and rewrote
its S value to the interface temperature. Nothing it could match was ever there.
That comment has exactly one producer, GCodeProcessor's backtrace injector, and
that runs inside run_post_process() -- a pass over the finished, exported file.
append_tcr2 runs while the file is still being generated, so the text it looked
for did not exist yet and could not.
The loop therefore walked every line, matched none, and swapped the string for
an identical copy. Delete it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The badge is meant to predict whether slicing will be refused, and it delegates
to the same helper for that reason. It was feeding that helper a different
filament list. get_extruders(true) resolves a mixed slot into its physical
components -- right for AMS mapping, which has to know what is actually loaded
-- while Print::validate counts the slot itself.
So a plate holding one two-component blend reads as two filaments to the badge
and one to validate. The badge sees two, decides the plate is fine, and stays
silent; the slice is then refused. It also runs the other way: a plate the user
sees as a single colour draws a multi-material warning, because the expansion
made it look like two.
Give get_extruders an expand_mixed flag, defaulted so every existing caller
keeps the resolved list, and have the badge ask for the authored one.
The badge was also only mirroring validate's multi-color rule, not its first
one -- a mixed filament is unsupported in a parallel mode outright. Without it
the badge stays quiet on exactly the plate validate refuses first.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The rule's comment claimed the plate "is not printable as configured: the
primary tool executes the toolpaths while the flow and temperatures were
computed for a filament it cannot load". That is not what the emitter does. It
never uses the declared primary -- it re-derives an effective one from the
filament actually in use -- so a plate whose only filament sits on a Span tool
sharing the primary's gantry produces coherent G-code and would print.
The refusal is still correct, but it rests on intent rather than physics: a
parallel mode exists to run carriages in parallel, and a single-colour plate
riding one span lane is not that. Left as a physical-impossibility claim, the
rule reads as a false positive to anyone who checks it against the emitter --
a review already flagged it as one -- and the obvious "fix" is to relax it.
Say which it is, and keep the genuinely-broken case distinct: a filament routed
to a head outside the mode's active tools still yields a stuck-hot nozzle, and
that one is not a matter of taste.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A mixed filament is unsupported in a parallel mode outright, but the rule saying
so ran third. A plate carrying a blend plus any second filament tripped the
multi-color rule's used > 1 gate first and was told its active tools all sit on
one gantry -- a diagnosis of a multi-color print the user never configured,
whose remedy is to go rework the mode's tool roster. The blend was never
mentioned. Move the check ahead of both rules below it; being unsupported
regardless of routing or topology, it dominates them.
Nothing is masked that leads anywhere else: every branch of
imex_multicolor_block_reason is itself confined to non-primary modes, so the
mixed message's remedy -- switch this plate to Primary -- silences those too.
Say "Mixed filaments", not "Blended". Every other string in the app calls these
mixed, including the button that creates one and the sibling refusal for the
wipe tower filament, so the user had no way to connect the message to the
feature it names.
Three comments in the block were wrong, and two of them were newly wrong. The
routing rule's bounds-check note still said "Blended slots are out of range by
construction, but they never reach here -- the rule above returns first": the
rule above is now the multi-color one, which does not return first for a single
mixed filament, and out-of-range is not guaranteed at all. Mixed slots are kept
at the tail of the filament arrays by convention, not by enforcement --
PresetBundle::set_num_filaments grows filament_is_mixed with resize(), so
raising a printer's extruder count with a blend present lands physical slots
after the mixed one. The scan is position-agnostic and stays correct; only the
stated reason was wrong.
The same discovery makes the empty-routed_list guard live rather than the dead
code it was described as. Print::apply() normalises physical_extruder_map before
validate() runs, so an unauthored map is never the cause -- but a printer with
more filaments than logical extruders leaves the tail slots outside the map, and
raising the extruder count does exactly that.
The new test validates the plate twice. The first pass, with no blend, asserts
the multi-color rule is armed at all; without it the second proves nothing,
because the rule only fires here thanks to a degenerate fixture mode whose two
tools share a gantry. Give that mode a Span tool and the whole test would pass
under either ordering while appearing to guard it. It also pins err.object,
which the mixed path sets and the multi-color path leaves null -- a discriminator
that survives the next wording change. Verified by reverting the order: the test
fails on both the message and the object.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
build: clear 295 -Woverloaded-virtual warnings in GUI widgets
Turns three hidden base virtuals into real overrides, clearing 295 of
the 553 -Woverloaded-virtual warnings and taking a full clang-cl build
from 1,264 to 969. Part of #15374.
Search.hpp: SearchDialog::Popup and SearchObjectDialog::Popup took a
wxPoint that neither body ever read, hiding the virtual
wxPopupTransientWindow::Popup(wxWindow*). Both bodies clear the input,
call the base, set focus and refill the list, and SearchObjectDialog
also guards re-entry, so hiding meant none of that ran when the window
was popped through a base pointer. They now override and forward focus.
LabeledStaticBox::SetFont and ScrolledWindow::SetBackgroundColour hid
their base virtuals the same way, so the label metrics recompute and
the child colour propagation only ran for callers holding the concrete
type. Both now override.
Marking a member override makes clang flag every other unmarked
override in the same class, so seven sibling declarations needed the
keyword too. Left unmarked they were worth 481 warnings, which would
have made this a net loss.
MSWDismissUnfocusedPopup is declared only inside #ifdef __WXMSW__ in
wx/popupwin.h, so off Windows there is no base virtual to override and
the keyword would not compile. Both the declarations and the definitions
are guarded, which is how wxWidgets itself declares MSWWindowProc in
wx/nativewin.h and how this repo already handles it in BBLTopbar,
MainFrame, Button, ComboBox and TabCtrl.
ScrolledWindow's constructor left m_userPanel and m_scroll_win
uninitialised unless the style requested a vertical scrollbar, while
SetBackgroundColour dereferences both. No caller hits that today since
every instantiation passes wxVSCROLL, but the override widens who can
reach them, so they are now initialised alongside their siblings.
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
- Publish mixed-filament slots as whole units: serialize the filament_mixed_* definition into project_config on import, grow the receiver's parallel arrays in lockstep, and report unappliable definitions as skipped instead of dropping them silently
- Per-extruder printer selection: one inner tab per extruder, rows keyed by full "#N" ids; single-extruder receivers collapse variants onto their slot (first applied, rest skipped), multi-extruder receivers override element-wise
- New per-slot "Enable" toggle gating what gets published; enabling a mix auto-enables + Full Publishes its components
- Mixed page previews: fixed-size ratio bar, ternary triangle (3 components) and Material Ratio vs Model Height graph (gradients), always visible regardless of Enable
- Tab strip shows full swatch compositions with adjustable spacing; barycentric helpers shared via FilamentBitmapUtils
M104/M109 address a heater, but every caller of the instance
GCodeWriter::set_temperature overload addresses filaments by logical id, so on a
printer whose physical_extruder_map is not the identity the emitted T named the
wrong head -- or, where the logical id exceeds the head count, no head at all.
With a map of 0,0,0,0,1,2,3 a toolchange to filament 5 emitted "M109 S265 T4"
and "M104 S190 T4 ;cooldown" while the head it meant was T1.
Upstream already treats these commands as physical: the preheat it injects in
GCodeProcessor maps through the same map before emitting, and BBS's own wipe
tower does likewise. Emitting logical is the half that never got the memo.
That mismatch also disabled the cooldown suppression beside the preheat, which
compares the line's T against pem[tool_number] and so never matched a logical
one -- 171 cooldowns survived in a two-head print where none should have. Worse,
it could match the wrong line: a cooldown for filament 1 emitted T1, and a
toolchange to filament 5 gives pem[4] == 1, so a legitimate cooldown for head 0
was deleted because the incoming head happened to be numbered 1.
Translate once, in the instance overload every logical-space caller passes
through. The static overload is already physical-in and is left alone.
Gated on is_imex. physical_extruder_map carries two readings in this tree: the
BBS paths index it by extruder id, the IMEX paths by filament id, and the two
coincide only when the filament and nozzle counts match. Mapping unconditionally
would impose the IMEX reading on profiles that mean the other one --
fdm_bbl_3dp_002_common ships a non-identity [1,0], spared today only because
single_extruder_multi_material suppresses the T qualifier entirely.
The wipe tower's interface-temperature pass has to move with it. It strips the
M109 that post_toolchange emits by searching for that filament's tool index, so
it now searches for the mapped one; left alone it would have stopped matching,
and the surviving blocking M109 would have silently defeated the interface
temperature. Its sibling pass reads WipeTower2 output, which emits no T at all,
and is deliberately unchanged.
The bare T<n> toolchange stays logical -- it selects an AFC lane, not a heater.
Test slices two objects across a head boundary, the only case that reaches this
emission: the same-physical short-circuit in set_extruder suppresses the
cooldown entirely for lane swaps within one head. It scans every M104/M109
rather than matching fixed strings, so it catches any unmapped emission and not
just the two sites changed here. With the mapping neutered it reports 101
offending lines; with it in place, none.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The routing error ran to roughly 450 characters and explained the mechanism
before it got to the remedy. It also offered to "edit the mode in Printer
Settings so its Primary tool is one of %3%", which on a plate whose filaments
resolve to no head at all rendered as "one of no configured extruder". Cut it
to the mode, the tool it prints with, where the plate's filaments actually are,
and the two things the user can do about it.
The second msgid that named candidate modes went with it. It could only suggest
a mode whose primary is among the routed heads, and every mode on the printers
this fires for declares 0:P, so it had nothing to offer.
Blended filaments now return before that check rather than falling through it.
A blend is mixed at the nozzle by its component toolheads, and a parallel mode
is already using those toolheads to print copies or mirrors, so the two cannot
run at once regardless of where the components route -- including when a
component sits on the declared primary. Reaching the routing rule would also
have described them wrongly: mixed slots sit past the end of
physical_extruder_map, so they resolve to no head and read as merely unrouted.
Keeps the empty-list guard the shortening first dropped. validate() reads the
raw physical_extruder_map, whose registered default is a single entry, so a
profile that declares IMEX modes without authoring a map leaves every slot past
the first outside it -- and the sentence ended in a dangling "on .".
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Brings the upstream color-mixing feature and its follow-ups onto the branch so the
IMEX placement and primary-routing checks are built and tested against them for the
first time.
Merged clean, no conflicts. Not yet exercised together: a mixed filament is a virtual
slot no nozzle carries, while physical_extruder_map routes logical slots to physical
heads, so the IMEX pem lookups have no defined answer for one. Print::extruders()
lists mixed slots under their own id while tool_ordering.all_extruders() lists them
post-expansion, and the IMEX code reads both.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Plater::validate_current_plate() runs the same background_process.validate() as
update_background_process(), and on success clears update_apply_result_invalid(false)
and closes the ValidateError notification -- but it never consulted
imex_placement_violation(). Any event reaching it wiped a live IMEX placement error
and re-enabled the Slice button on a plate the slicer still refused; pressing Slice
then hit the check in reslice() and returned early, so the job simply never started.
Reproduce by clicking the bed with the prime tower overlapping a reserved area.
Plater::select_plate_by_hover_id() -> select_plate() calls validate_current_plate()
unconditionally, even when the clicked plate is already current, and deselects as a
side effect -- which makes it look as though deselecting the tower cleared the error.
Escape and clicks off the bed go through selection_changed(), which only renders and
clears nothing.
Extract the violation-to-message mapping into one helper and call it from both paths.
model_fits is set alongside err.string in validate_current_plate, mirroring the
missing-plugin block below it: the slice is already gated by m_apply_invalid, but
leaving m_ready_for_slice true would trap a future consumer that reads it alone.
These are the only two sites that matter. NotificationType::ValidateError has exactly
three references in the tree and update_apply_result_invalid exactly four; the other
slice-ready writers can only touch m_ready_for_slice, never m_apply_invalid, so they
cannot re-enable Slice on their own.
Three adjacent gaps are left alone, all pre-existing: "Slice all" is hard-coded
always-enabled regardless of plate state; a slice-all batch halts silently at a
violating plate because reslice() returns above the line that queues the advance; and
object_list_changed() computes its own can_slice from geometry, harmless only because
the result is ANDed with PartPlate::can_slice().
This is a hole in the shipped tower-zone check rather than a regression from rotating
the tower hull -- it was simply invisible until a tower could be placed in violation.
No automated gate: Plater is GUI-only, the helper is file-local and unlinkable, and
imex_placement_violation() needs a live wxApp and preset bundle. "Both call sites
consult it" is a call-graph property no unit test can express. The grep for a single
imex_placement_violation reference is a future regression tripwire, not evidence this
refactor happened -- it already returned 1 beforehand.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Keep mixed-color filaments intact when the extruder count changes
The extruder-count spinner resized the filament arrays in bulk at the tail,
which is where mixed-color slots live, so a new filament landed behind the
mix and the sidebar skipped a slot number. It now adds and removes one slot
at a time through the same calls the sidebar's +/- buttons use, so a new
slot opens ahead of the mixed tail and a removal renumbers object filament
ids, painted facets, custom g-code and mixed components rather than
clamping them away.
Drops the vector overload of set_num_filaments(), which this leaves without
callers.
Update perimeter traversal to pass each extrusion's closed/open state into `apply_fuzzy_skin`. This lets fuzzy skin logic distinguish contours from closed loops when processing perimeters.
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
build: drop dead private fields, close malformed comments (227 warnings)
Clears 227 of the clang-cl warnings tracked in #15374, taking a full
Windows build from 1,491 to 1,264. Five of the six changes are in
headers, which are re-diagnosed in every translation unit that includes
them, so the count is large for a 14-line diff.
Tabbook.hpp: delete two private fields, unread since the 2022 import.
m_parent also shadowed wxWindowBase::m_parent.
GUI_Utils.hpp: the wxEVT_SYS_COLOUR_CHANGED lambda body is empty on
Windows, so its `this` capture is unused there. (void) this; leaves the
handler bound, which is what stops the event propagating.
DevFirmware.h: mark m_owner [[maybe_unused]]. The class is never
instantiated, and the file tracks BambuStudio, so this is the smallest
divergence.
Eight DeviceTab/ files, AMSItem.cpp and SelectMachine.cpp: block
comments malformed so that they read as a nested /*.
No behavior change. -Wcomment goes to zero, and only the three intended
categories move.