Make the connected-net layout affordable on a dense patch
Laying a patch out as a connected net cost ~175 ms on a 42k-triangle patch,
against ~21 ms for the unwrap it works from, and the gizmo asks for it on every
preview, overlay and bake. Measured on a real project the grid behind it ran
~19 million triangle-pair tests per net, nearly all of them misses: a cell
holds every triangle whose box touches it, and a candidate really meets a
couple of them.
Keep a bounding box with each stored triangle and answer those misses with four
comparisons instead of a full intersection. The net drops to ~53 ms with
identical output - the seam metrics on the test project did not move by one.
Two further attempts were measured and dropped, and are recorded in the comment
so they are not tried again: a free-space pre-check per chart came out slower,
because a folded chart lands against the net by construction and the cells
under it are occupied anyway, and splitting the boxes into their own array for
locality lost more to growing two vectors per bucket than it gained.
Also pick a pair's fold line from the longest boundary they share rather than
whichever edge came first, and grow the net strongest-adjacency-first rather
than breadth-first by area. Only the fold a chart is reached by comes out
matching, so a chart claimed across a short boundary leaves the long one it
shared with its true neighbour torn.
texture_unwrap_dump reports an unwrap from a saved project - charts, their
topology, folded triangles, where the texture is discontinuous and how long
those seams are. All of the above was found with it, and it is what keeps a
claim about this code honest; reading the 3D view and guessing had produced
three wrong diagnoses in a row.
* Explain the texture displacement views that cannot be used, and show them
Checker and Distortion are views of a layer's unwrap, so they mean nothing on
any other mapping - but they were offered on all of them and simply drew
nothing when picked. Fade them out on anything but Unwrap (LSCM), with the
reason in the tooltip, and have a click bring the UV editor up on the view it
selected, since that pane is where the unwrap is actually worked on.
Neither view was visible even when it did apply. The overlay is built from the
base patch and drawn with a polygon offset, which biases depth values rather
than moving geometry, so it cannot win against the displaced preview standing
in front of it. Leave that preview out while a UV-check view is on and draw the
undisplaced surface instead, which is what the offset assumes and what the
mapping being inspected belongs to.
In the UV editor, a tool that cannot be used right now is faded rather than
disabled. A disabled window gets no mouse events on GTK or MSW, so every one of
those tools - Cut, Join, Unjoin, Clear seams, Clear UV edits, the select modes,
Snap, Frame - silently had no tooltip in the state where the user most needs to
know what is missing. Each now says what to do instead. The tile size, the
island statistics, the status line and the three select modes gained tooltips
of their own; the select modes now name the gestures they enable, which were
documented nowhere.
* UV editor: keep the mouse capture balanced
The canvas captured the mouse on every button press without checking whether
it already held one, released it in a single place, and handled no capture
loss at all. Two sequences leaked a capture: pressing a second button during a
drag nested a second one that the single release on button-up could not undo,
and a modal R/S skipped that release entirely while waiting for a confirming
click that may never come.
A leaked capture is not a local problem on macOS, where wxEVT_MOUSE_CAPTURE_LOST
is never sent and nothing recovers it. While any wx window holds a capture,
wxOSX routes every mouse event to that window and never calls through to
NSWindow, so the application stops seeing motion and enter/leave, and native
tooltips stop appearing anywhere in it.
Capture through grab_mouse()/drop_mouse() so there is at most one, give it back
on any button-up including a modal gesture (which tracks the pointer and needs
no capture), and cancel on wxEVT_MOUSE_CAPTURE_LOST: commit nothing, put back
what a modal rotate or scale already applied, and do not release a capture that
is already gone.
---------
Co-authored-by: ExPikaPaka <mrfsfyt@gmail.com>
* Fix a crash on loading a 3MF with empty project settings
opt_float() dereferences what option<>() returns without checking it, and
option<>() is called with create = false. Three CLI sites read printable_height
that way, so a 3mf whose Metadata/project_settings.config holds an empty object
takes the CLI down with a null dereference. Both models shipped in
resources/handy_models are such files, so `--info` on either of them segfaults.
Guard the three reads the way the neighbouring reads of
extruder_clearance_height_to_rod and friends already are. All three target
variables are initialised to 0 and the consumer tests for > 0, so an absent
setting already had a defined meaning and nothing changes for a project that
carries the setting.
* Add a CLI regression test for a project with empty settings
Runs --info over a copy of a shipped model whose Metadata/project_settings.config
has been rewritten to an empty object, so the test keeps covering the crash no
matter what settings the shipped models carry later.
Verified both ways: the test passes against this branch and fails with a
segmentation fault against a build without the guards.
---------
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
libpng reports a bad file by longjmp()ing back to the buffer set with
setjmp(), and the frame it lands in must own nothing that needs
destroying: with exceptions enabled MSVC unwinds the stack as part of
longjmp, and returning from a frame unwound that way crashes. It did on
Windows while working everywhere else.
The read callback also returned quietly on a short read, leaving libpng
to decode whatever happened to be in the output buffer.
The calls that can fail now sit in two helpers that own nothing but
pointers, so every C++ object the decoders need stays in their own
frames, and a short read is reported through png_error().
Every BambuStudio project opened with a "BambuStudio Project" info dialog
(or, from BambuStudio 2.8.2, one saying the file is newer than the
compatible version and to update the software), followed by the
configuration-substitution dialogs for the project and its embedded
presets. None of them asks anything and all of them fire for every
BambuStudio file.
For BambuStudio projects (untagged files newer than 2.3.2, the existing
test) log the version with the unrecognized settings, and each replaced
value, instead. The geometry-only, invalid-values and G-code safety
dialogs stay, and other 3MFs are unchanged.
The Slice-plate hover popup (FilamentGroupPopup, a wxPopupTransientWindow)
takes the mouse capture while it is shown, and on macOS its OnIdle handler
reacquires that capture whenever the cursor sits outside the popup. If the
popup is still shown when the modal filament grouping dialog opens, wx routes
every dialog mouse event to the now-hidden popup, because WX_filterSendEvent
short-circuits to the capture window while GetCapture() is non-null. The
dialog's filament blocks never receive a mouse-down, so they can't be dragged
and the whole app looks frozen even though its modal loop is healthy and the
keyboard still works.
Dismiss the popup synchronously before the dialog opens: Dismiss() hides it
and releases the capture, and hiding it stops OnIdle from reacquiring. This is
a no-op where the popup is never shown (Linux, where the hover popup is
disabled, and any non-dual-nozzle printer).
* build_linux.sh: add -J to build several dependencies at once
The top-level deps build is fixed at -j1, so one dependency compiles at a
time while the small ones leave most cores idle. -J N raises that level.
-j still applies in full to each dependency, so the worst case is -J times
-j compile jobs: ninja has no job server to share a pool across the nested
builds. Without -J nothing changes.
* Quote the job count for shellcheck (SC2086)
---------
Co-authored-by: ExPikaPaka <mrfsfyt@gmail.com>
A plugin enabled at startup loads before the main frame exists, so a
dock panel it opens from on_load was dropped by the one-shot CallAfter
that found no plater. Opened a moment later, before the frame was laid
out, the pane was sized against the unsized frame and track_docked_size
kept that width. Poll until the plater is shown on screen, then build
the pane; release the reserved id instead when the app is closing.
The bed-axes toggle added for the Design tab's reference planes reads
m_design_sketch_tool, which only exists under SLIC3R_CAD. Compute the
flag once and read the sketch tool inside the same guard as its other
uses.
The last headers with a using or namespace alias at namespace scope:
- TCPConsole.hpp imported boost::asio::ip::tcp into Slic3r::Utils for
two member declarations. The alias is now a private member of the
class.
- WebSocketClient.hpp declared four namespace aliases and a tcp alias
at global scope, each used only by the header. The names are spelled
out.
- Repair.hpp aliased CGAL::Polygon_mesh_processing as PMP in
Slic3r::tex2color. The three functions that use it declare the alias
themselves.
- PreciseSeam.hpp, Thumbnails.hpp and MarchingSquares.hpp used a
using-declaration or directive for one or two spots each; those spots
are qualified. Thumbnails.hpp's "PNG"sv default argument becomes
"PNG", which converts to the std::string_view parameter the same way.
- tests/sla_print/sla_test_utils.hpp had "using namespace Slic3r;" and
tests/filament_group/fg_test_serialization.hpp "using json =
nlohmann::json;" at global scope. The headers qualify their own names;
the two SLA test sources get the directive themselves.
Also removed: twelve type aliases in headers that nothing references
(ConflictObjName, CircleSqf, CircleSqd, TRawBuffer, DistanceFunction,
SamePair, ExtruderNozzleInfos, Vec2dEvent, Vec2dsEvent, Vec3dEvent,
t_option, t_optgroups, Plater::fs_path) and a duplicate
fn_ft_job_msg_destroy alias in FileTransferUtils.hpp.
46 files include the same header twice at file scope, outside any #if,
66 times in all:
Model.cpp included Model.hpp twice, Utils.hpp <algorithm> and
<string_view> twice, seven GUI headers <wx/dataview.h> and
<wx/artprov.h> twice. The second include of each is removed.
GCodeSender.cpp and GCodeSender.hpp have been commented out of
libslic3r/CMakeLists.txt since 2022 and their only two includes are
commented out as well. Both files go, with the commented lines, and
the CMake entry for SLA/SupportTreeIGL.cpp, a file that no longer
exists.
The mixed-colour metadata options are parallel per-slot arrays in the project
config. A project saved before they were sized per slot stores a single value
for the gradient ones, and one saved before they existed stores none. The GUI
sizes all seven to the filament count when it opens a project; the CLI kept
the stored arrays and exported one-element defaults for absent ones, so a
project it exported carried one-element arrays where the GUI writes one entry
per filament. Slicing is unaffected, every reader treats a missing entry as
not mixed / no gradient, but the GUI-vs-CLI comparison reported the four
gradient keys on every mixed-filament project.
The resize helper moves from PresetBundle.cpp, where it was file-local, to
PrintConfig.cpp next to set_filament_dev_options(). It creates an option the
config lacks before sizing it, a no-op for the bundle's project config where
all seven always exist. The CLI calls it with its filament count once the
project and loaded filaments are merged, after the check that every mixed
slot has a filament of its own.
## Speeds up OrcaSlicer incremental rebuild on Linux
Profiled `build_linux_image.sh`: 96 s, of which 51 s in the dependency
audit.
**`appimage_is_elf_file()`** ran `file` and `grep` per candidate. An
AppDir holds ~9.6k of them, 4.8k being the bundled Python runtime and
none of them ELF: ~19k processes, 14 s. Reads the four-byte magic
instead. Checked against the old result on 4000 files, no disagreement.
**The dependency walk** popped its queue with `"${queue[@]:1}"`, which
rebuilds the whole array each time. At ~4.8k entries that was 22 s of
copying an array around. Uses a read index.
Audit still passes. `shellcheck` v0.11.0, the version CI uses, is clean.
## Notes
The 96 s -> 12.7 s. Measured on a 32-core / 48 GB machine, but the audit
is a serial bash loop, so cores and RAM is not the bottleneck. On slower
hardware the saving should be larger
## Images
<img width="1987" height="782" alt="Screenshot_20261007_092516"
src="https://github.com/user-attachments/assets/96fcb917-38e5-49e7-8cbe-b37be1a2f23a"
/>
<img width="1807" height="742" alt="Screenshot_20261007_092621"
src="https://github.com/user-attachments/assets/4a65ffae-4d59-41f0-a1c7-ee5b49f3c4be"
/>
# CHANGES / TESTS
• Uses "Extruders" as tab name if it has multiple or it uses "Extruder" for single ones
• Keeps selected extruder while switching between "Extruders" and "Motion ability" tab
• Revert functions are working
• New extruders generated with values so they will shown in "Unchanged values" dialog if you try to change preset while its edited. revert functions not works properly without this
• BBL printers visible as Left / Right while normal printers visible as T1 / T2. i think there should be a separate option for how many toolheads and how many extruders it has. we might see 4 nozzles on same toolhead if one brand is brave enough :)
• Sidebar and other sections updates itself properly
<img width="751" height="173" alt="Screenshot-20261005173918" src="https://github.com/user-attachments/assets/3be0a6bd-84bd-4d15-822c-ed34acd98a9f" />
<img width="768" height="184" alt="Screenshot-20261005173905" src="https://github.com/user-attachments/assets/46164926-e385-4482-9fd1-41325eb9f61d" />
<img width="755" height="289" alt="Screenshot-20261005175318" src="https://github.com/user-attachments/assets/4550fa51-4c71-4a0a-b15e-9ca82dd0f1ad" />
# FIXES
• Extruders count on parameters section not updated when extruder count changed on printer settings. fixed on this PR
<img width="800" height="478" alt="Screenshot-20261005174702" src="https://github.com/user-attachments/assets/734e53df-f23f-4f83-8f87-2ecfeb6c162c" />
• New extruders gets randomly modifed parameters. fixed on this PR
<img width="871" height="87" alt="Screenshot-20261005174840" src="https://github.com/user-attachments/assets/254dae2a-fcfa-44ed-b3b0-038faf019abb" />
• Changed parameters not triggers revert / modified on extruder tabs. fixed on this PR
• Multi switch on motion ability tab not updated on extruder count change. fixed on this PR
<img width="813" height="184" alt="Screenshot-20261005174929" src="https://github.com/user-attachments/assets/f4f33f8f-b1bd-4a30-b91b-6ff632d08c2a" />
The device drying options hold several values per filament, as many as
the filament preset gives, and a project stores them as the filaments'
values one after another. The CLI filament merge wrote them like an
option with one value per filament, putting each preset's first value at
the filament's own index, so a project with three filaments whose preset
gives "1", "0" was exported with 1;1;1;0;1;0 where the GUI writes
1;0;1;0;1;0.
The merge now leaves these options out of the per-filament pass and
rebuilds them afterwards from every filament's values in slot order.
Without a fixed number of values per filament one slot cannot be
replaced in place, so the stored values are kept when any slot has no
config to rebuild from.
The Bambu network plug-in's code protector rewrites one page of its own signed __TEXT after loading. The hardened runtime tolerates that until the page is evicted; the next read of it then kills OrcaSlicer with CODESIGNING Invalid Page. Bambu Studio signs with allow-unsigned-executable-memory for this reason; with it added, the same build survives critical memory pressure that killed it in 30 s without.
A project's listed settings are carried onto its base preset by update_non_diff_values_to_base_config, which matched variants by exact name and id. A variant the base gained after the project was saved got the base's value, while the same value in a user preset now falls back to the preset's first variant of that extruder. So an old project opened with its printer preset already modified, and saving it wrote the base's values into the 3MF.
The function now maps variants with map_variant_indices, as update_diff_values_to_child_config does: a base variant the project does not list takes the project's first variant of the same extruder. The variant lists themselves stay the base's, so a fallback never writes one variant's name over another's.
The 02.08.02 series appended queue_plate_id to PrintParams and nothing
after it changed the ABI OrcaSlicer calls, so adding the field brings
the current layout up to 02.08.04. Make 02.08.04 the latest series and
drop 02.08.01 from the whitelist: its PrintParams no longer matches, and
its malformed bind table is refused by dyld on macOS 27, so it cannot
load there. A stored 02.08.01 falls back to the latest series through
the existing unsupported-version path.
Profiling build_linux_image.sh: 96 s, of which 51 s in the dependency audit.
appimage_is_elf_file() ran file(1) and grep per candidate. An AppDir holds ~9.6k
of them, 4.8k being the bundled Python runtime, none of them ELF: ~19k processes
for 14 s. Read the four-byte magic instead; checked against the old result on
4000 files, no disagreement.
The dependency walk popped its queue with "${queue[@]:1}", which rebuilds the
whole array each time. At ~4.8k entries that was 22 s of copying. Use a read
index.
96 s -> 12.7 s. The audit still passes.
The directive sat at global scope in a header that DeviceManager.hpp
includes, so most of the GUI compiled with all of std in the global
namespace. 42 files had come to rely on it, mostly for string, vector
and unordered_map, four of them for the ""sv and ""ms literals.
Those sites are qualified. GCodeViewer.cpp spelled the type as
std::vector<::string>, which only resolved through the directive. The
files that use the ""sv and ""ms literals get a file-scope
"using namespace std::string_view_literals;" or
"using namespace std::chrono_literals;", as other sources already do.