Commit Graph
31461 Commits
Author SHA1 Message Date
Clifford GarwoodandClaude Opus 5 a3eccdc8b7 Resolve the IMEX mode the same way everywhere it is read
A plate can carry its own parallel mode, or leave it on Primary and inherit the
process preset's. set_imex_mode() erases the key on Primary precisely so the
preset's value survives the config merge, and the slicer honors it: Print::validate()
and the G-code path both read the merged object config, so such a plate slices, and
emits, in the preset's mode.

Three places that describe that plate did not resolve it the same way. They read
the plate's own value and stopped, so on a plate left at Primary:

  the multi-material conflict badge stayed dark on a plate validate() will refuse,
  which is the one invariant the comment above it claims to keep;
  the bed-temperature and filament-type warnings never ran, so the job went out in
  copy or mirror with a mismatched bed and no notice;
  the plate tooltip reported Primary for a plate about to print in another mode.

The geometric badge beside the first of those already resolved correctly, because
it goes through the zone layout, so one badge fired while its neighbour stayed
dark on the same plate.

The fallback had been written out by hand four times. Three are now collapsed onto
one accessor, get_effective_imex_mode(); the fourth is in libslic3r, which cannot
call a GUI method and resolves the two modes itself from arguments. The remaining
callers of the raw get_imex_mode() want the raw value and keep it: the accessor
itself, the zone layout call that passes both modes separately, the mode menu and
the left-click cycle, which act on what the plate stores, and the reset that looks
for plates whose own mode was removed.

The tooltip is the one place the two readings meet. It headlines the stored mode,
because it sits on the button whose menu and click act on that value, and names
the inherited mode after it when they differ -- so one control no longer says
three different things while still telling the user what will actually print.

Reachability, honestly: nothing in the UI writes the process preset's copy today,
so this needs a hand-edited preset, a vendor process profile or a project that
carries one. It is latent rather than live -- and it stops being latent the moment
a process-level mode selector exists. Note the key lives in the process preset, so
one value there would govern every Primary plate in every project using it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-30 20:54:17 -04:00
Clifford Garwood 8350bac123 Merge the per-toolhead extruder colors 2026-09-29 21:43:55 -04:00
Clifford GarwoodandClaude Opus 5 0c09327c1a Merge upstream, and index pressure advance by extruder variant
Upstream moved pressure advance onto the extruder variant: enable_pressure_advance,
pressure_advance and the four adaptive keys joined filament_options_with_variant,
the repeated inline blocks in set_extruder() became a helper, and the lookups
moved from the filament id to get_filament_config_index().

All three conflicts were the same collision, because this branch had modified two
of those same inline blocks to pass a tool qualifier so each carriage is addressed
explicitly in parallel modes. Taking either side whole would have lost something:
upstream's drops the qualifier and leaves parallel carriages with no pressure
advance, ours drops the per-variant indexing and reads the wrong column on a
multi-variant printer. The helper now takes an optional tool, defaulting to -1,
which omits the qualifier. imex_pem_tool_for() already returns -1 off IMEX and in
primary mode, so non-IMEX output is unchanged, and the three call sites that never
passed a tool keep upstream's behavior exactly.

The third conflict was two test cases appended at the same place. Both are kept.

Separately, one defect that merged cleanly and so was not flagged: the loop that
emits pressure advance for secondary carriages at the start of a print still
bounded and indexed those vectors with a raw filament id. They are variant
expanded now, so their length is columns rather than filament slots -- the value
read was the wrong column, and the bound no longer sat in slot space, letting an
out-of-slot filament through. It now bounds on filament_diameter and translates
with get_filament_config_index(), which is what the sibling second-layer
temperature loop already does.

Verified: both changed translation units compile clean under -Werror. The merge
was resolved independently twice and the two resolutions agree on every line of
code. Not yet run: the Release test suite and a parallel-mode slice sweep.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-29 21:43:47 -04:00
Clifford GarwoodandClaude Opus 5 bfac55335a Give each Xplorer toolhead its own color
Every extruder on every model carried the same yellow. The key exists so the
plater, the preview and the filament mapping can tell toolheads apart, which
matters most on the machine this bundle exists to demonstrate: four independent
heads that were indistinguishable at a glance.

Yellow, blue, plum and orange, assigned in tool order, so the two-tool models
take the first two. Red and green are avoided as a pair because they are the
hardest to separate for the commonest color vision deficiency.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-29 20:35:42 -04:00
789f848694 Write the estimated printing time comment after the config block, not before (#15897)
Co-authored-by: Fernando Marino <f.marino@rheagroup.com>
Co-authored-by: yw4z <ywsyildiz@gmail.com>
2026-09-29 19:18:15 -03:00
Rodrigo FaselliandIan Bassi 3a0694dce6 Remember last print action (#15774)
Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
2026-09-29 19:17:45 -03:00
Kris AustinandRodrigo Faselli f5679ad343 perf: load presets in parallel, cutting preset load time by over 60% (#15943)
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
2026-09-29 18:13:44 -03:00
HanifKoh 2769b12ce7 Give OBJ Quad and Flipped Faces the Texture Coordinates of Their Own Corners (#15977)
load_obj emits the second triangle of a quad from corners 0, 2 and 3,
but read its texture coordinates from corners 0, 1 and 2, so half of
every textured quad sampled the wrong part of the texture. The corner
indices are now passed down to where the coordinates are read.

A mesh with inward-facing triangles is flipped after loading, which
swaps corners 1 and 2 of every face. The texture coordinates were left
as they were. They are now swapped along with the corners.
2026-09-30 03:13:29 +08:00
HanifKoh 203bc63f35 Escape Project Metadata in the Project Page and Restrict Accessory Opening (#15956)
* Escape Project Metadata in the Project Page and Restrict Accessory Opening

The Project page rendered the model and profile name, author, description
and accessory file names from the 3MF as live HTML. Names, authors and file
names are now set as text, and the file list is built from DOM nodes with
bound click handlers instead of concatenated markup. Descriptions can
legitimately carry rich-text HTML, so they are rebuilt from an inert
DOMParser document, keeping only plain formatting tags, http(s) links and
http(s) images, with every other attribute dropped.

Opening an accessory from the page now only launches regular files that
lie inside the project's extracted auxiliary directory. The containment
check is a new libslic3r helper, is_absolute_path_within_root, built on
is_path_within_root so symlinks leading out of the root are rejected too.

* Tighten Project Page Description Rendering and Keep More Formatting

Link and image URLs in descriptions must now start with an http or https
scheme as written and parse as such with the URL parser. Preview images are
built as DOM nodes like the file list, and accessory names show their full
text as a tooltip.

Descriptions keep more plain formatting: del, ins, figure, figcaption, dl,
dt, dd, caption, q, abbr, kbd and wbr, plus alt, title, width and height on
images, colspan and rowspan on table cells and start on ordered lists.
Numeric attributes must be plain integers. Embedded YouTube players become
a link to the video.

* Confirm Before Opening Program Attachments and Load Only HTTPS Images

Opening a project attachment whose type runs as a program or script
(executables, installers, shortcuts, shell and PowerShell scripts, macOS
command files and apps, Linux desktop entries) now asks for confirmation
first. The check lives in libslic3r as is_executable_file_name and ignores
the trailing dots and spaces Windows strips from file names.

Images in project descriptions are kept only when they load over https,
so opening the Project tab no longer issues plain-http requests.

* Open Project Attachments Through One Guarded Helper

The Edit Project Info view launched attachments directly, without the
checks the project page has. Both now call
desktop_open_project_attachment, which checks that the file is inside
the auxiliary directory, asks for confirmation where needed and then
opens it.

The auxiliary root was built through encode_path, which returns code
page bytes on Windows, while boost::filesystem reads a narrow string as
UTF-8. With a non-ASCII temporary directory the root never matched and
no attachment opened. It is now built from the UTF-8 path directly.

The list of program extensions could not be kept complete and let
unknown types open without a prompt. It is replaced by
is_safe_to_open_file_name, a list of plain document, image, model and
video types that open directly. Everything else asks first.
2026-09-30 00:39:30 +08:00
HanifKoh e40030cf81 Stop Malformed Network Responses from Crashing the App (#15947)
* Stop Malformed Network Responses from Crashing the App

Duet, MKS and UltiMaker parsed print host replies with boost read_json
inside the HTTP completion callback with no try, so an HTML or truncated
reply threw out of the Physical Printer Test button and terminated the app,
or killed the upload queue thread. The five identical copies of the parser
(ESP3D's and Flashforge's were unused) are replaced by one shared
PrintHost::get_err_code_from_body that reports a non-JSON reply as an error.
The upload queue now catches a failing job per job, so one bad upload no
longer leaves later jobs queued forever.

Flashforge read material station slots with nlohmann value(), which throws
on off-type fields or non-object entries. The parsing moves into
Flashforge::parse_material_slots, which reads fields leniently with the
existing try_parse_json_int and skips bad entries.

UserManager::parse_json parsed the payload before its try block; the parse
now happens inside it.

* Keep UploadFinished Paired with UploadStarted When an Upload Throws

The exception from a throwing upload was caught around perform_job, so
the UploadFinished lifecycle event was skipped and plugins saw an
upload start that never finished.

The catch now sits around the upload call. The error is reported
through the job's error callback and UploadFinished is fired with an
error code, as for any other failed upload. The worker keeps running
for the next job. The started, upload and finished sequence moved to
PrintHostJobQueue::upload_job so it can be tested without the dialog.
2026-09-30 00:39:01 +08:00
HanifKoh ba468c842d Confine Updater and Plugin Archive Extraction to the Target Directory (#15957)
* Confine Updater Archive Extraction to the Target Directory

The preset updater extracted downloaded archives by appending each entry
name to the cache directory, and the network plugin installer did the same
for the plugin folder, without checking that the result stays inside it.

Move the updater's extraction into libslic3r as extract_archive_confined,
which validates every entry with is_path_within_root before writing
anything and fails the whole archive if one entry resolves outside the
target. The plugin installer now rejects such an entry the same way. Well
formed archives extract exactly as before.

* Harden Archive Extraction Against Symlinks

The plugin installer now creates a symlink entry only when its target is
relative and, joined to the link's own directory, passes
is_path_within_root, via the new is_symlink_target_within_root helper.
Before writing any entry it checks the destination with symlink_status, so
an existing symlink, dangling or not, is replaced rather than followed, and
it creates parent directories inside the existing error handling.
extract_archive_confined replaces a symlink at a destination file the same
way.

is_path_within_root now ignores a trailing separator on the root, which
previously made every path fail the check.

* Validate Plugin Symlink Targets Before Replacing Existing Files

A symlink entry's target is now read and checked before anything already
at its destination is removed or renamed aside, so an archive rejected
for its link target leaves the installed plugin files in place.

* Reject Paths with an Embedded NUL When Confining Extraction

is_path_within_root compared each component with "..", so a name such
as "..\0" passed the check. The filesystem calls stop at the NUL and
act on a shorter path than the one that was checked: a symlink target
read from a plugin archive as raw bytes was created as "..", pointing
out of the plugin directory.

A path containing a NUL is now rejected before anything touches the
filesystem, which covers every caller, including entry names taken from
the Unicode Path extra field.
2026-09-29 23:40:12 +08:00
SoftFever dd9b5dc0d4 Tune pressure advance separately for each extruder variant (#15986)
* Tune pressure advance separately for each extruder variant

Pressure advance, adaptive pressure advance and its model can now take a
different value for each extruder variant of a filament, such as Standard and
High Flow nozzles, like the other per-variant filament settings. Projects
saved with one value per filament apply it to every variant of that filament,
and the addnorth BBL filaments in the Orca Filament Library are updated to the
per-variant layout.

* Move Nozzle type to each extruder's settings page

Editing other settings on an Extruder page of a single-extruder
multi-material printer no longer triggers the nozzle diameter prompt.

* Fix command-line slicing when a filament leaves out a per-variant setting
2026-09-29 23:23:08 +08:00
HanifKoh e68694dbaf Percent-Encode Local File URLs for Embedded Web Pages (#15961)
* Percent-Encode Local File URLs for Embedded Web Pages

The Home tab, setup wizard, Project tab and other embedded pages were
loaded from file:// URLs built by pasting the resources path into a
string. A '#', '%' or '?' in the install path was then read as a URL
fragment, escape or query, so the pages failed to load, for example a
portable install under D:\#OneDrive showed a directory listing instead
of the setup wizard.

Add file_url_from_path(), built on wxFileSystem::FileNameToURL, and use
it wherever a local page or image URL is built from a path. Queries such
as ?lang= are appended after the path is encoded. The wizard's printer
cover images are passed to the page as file URLs too.

* Encode the Login Error Page URL and Cover More Windows Path Forms

The login dialog's error page was still loaded from a raw resources path;
it now uses file_url_from_path like the other local pages.

The Windows file URL tests now also cover a resources path joined with a
forward-slash relative path, as the callers build them, and a UNC path.

* Build the Flush Dialog Page URLs with the Shared Helper

WipingDialog and NozzleListTable still called
wxFileSystem::FileNameToURL directly. They now go through
file_url_from_path like every other local page, so the URLs are built
in one place.

Adds a test for a resources directory with a '#' in its name, which the
plugin page check did not recognise before.
2026-09-29 22:30:56 +08:00
SoftFever 1504bd7153 Fix command-line slicing when a filament leaves out a per-variant setting 2026-09-29 21:09:20 +08:00
SoftFever d87fe1b290 Merge branch 'main' into feature/pa_per_extruder_variant 2026-09-29 19:15:17 +08:00
Kris Austin 72cfe71b81 fix: link webkit2gtk and X11 on every Linux build, not only Flatpak (#15972)
libslic3r_gui calls webkit_* directly, and OrcaSlicer.cpp and libspnav
call Xlib, but both libraries were only linked when FLATPAK was set.
The default build links because the bundled static wxWidgets lists
them in wx-config. A shared wxWidgets does not, so any build against
one, like the Flatpak build or a distro package, fails with undefined
webkit_* and X* symbols.
2026-09-29 08:04:48 -03:00
SoftFever 50eea48408 Move Nozzle type to each extruder's settings page
Editing other settings on an Extruder page of a single-extruder
multi-material printer no longer triggers the nozzle diameter prompt.
2026-09-29 17:52:19 +08:00
SoftFever ef0c656932 Tune pressure advance separately for each extruder variant
Pressure advance, adaptive pressure advance and its model can now take a
different value for each extruder variant of a filament, such as Standard and
High Flow nozzles, like the other per-variant filament settings. Projects
saved with one value per filament apply it to every variant of that filament,
and the addnorth BBL filaments in the Orca Filament Library are updated to the
per-variant layout.
2026-09-29 17:52:13 +08:00
Clifford Garwood 3334c2ed2a Merge the Vivedino Xplorer printer profiles
Adds the four Xplorer configurations, their twelve machines and fifteen
processes, so the parallel printing modes can be exercised on a real printer
rather than only on hand-built configurations.
2026-09-29 05:03:26 -04:00
Clifford Garwood b6b2f0d3b8 Merge upstream into the parallel printing work
Brings in nine commits, including stricter slice validation of custom G-code and
filename formats across system profiles, OBJ and DRC import hardening, and the
Ender-3 V3 SE extrusion mode fix. None of them touch the files this branch
changes.
2026-09-29 05:03:21 -04:00
9a7e2681d4 Add Vivedino Xplorer printer profiles
The Xplorer ships in four configurations that differ in how many toolheads they
carry and how those heads are arranged: Single, IDEX with two heads on one
gantry, Dual Gantry with one head on each of two, and IQEX with two on each of
two. Each is offered at 0.4, 0.6 and 0.8 mm, giving four machine models, twelve
machines over a shared base, and a five-tier process ladder per nozzle.

The dual-gantry machines park the second gantry's tools over the plate, so the
area both gantries can reach is 57.5 mm shallower than the plate itself. Those
two declare 400 x 342.5 where Single and IDEX declare 400 x 400. That depth is
what the parallel print modes divide into equal zones, so it has to be the
reachable area rather than the physical one.

The bed textures are drawn to match. Texture coordinates are normalised per
axis, so a canvas whose aspect differs from printable_area is stretched and
anything drawn outside the plate is pulled onto it; each viewBox equals its own
model's area. They mark the real reach limits and nothing else, because the
print zones are computed and drawn per plate at run time and a static copy of
them only disagrees with the live one.

Motion limits are the firmware's: 5000 acceleration, 300 mm/s, 100 on Z, 120 on
the extruder, and a square corner velocity of 5 rather than a jerk, which Klipper
does not have. Every per-extruder and per-variant value is written at full width,
because padding a short array repeats its first value rather than its last pair
and would otherwise hand every extruder past the first a normal-mode figure in
its silent slot.

The processes are based on a profile tuned on the hardware. Line widths are
expressed as percentages of the nozzle so one statement serves all three sizes,
and the ladder varies only what belongs to layer height. Extruder variants are
declared rather than left to a default that would have capped volumetric flow at
a figure describing a plain V6.

Verified by slicing all fifteen tiers on all four models: every one completes,
emitted accelerations and widths match what the profiles resolve to, no
coordinate leaves the printable area, and the two pre-existing Troodon models in
the same bundle are unaffected. The bed graphics, the print zones and the
volumetric cap resolve through paths the command line does not exercise and want
confirming in the application. Values tuned against hardware the author does not
have - the 0.8 ladder in particular - are a starting point rather than a result.

Co-Authored-By: Dan_3dp <corexy.diy@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-29 04:58:22 -04:00
SoftFever 46fb512690 enable python unit test (#15593)
* enable python unit test

* fix Windows

* Require numpy for the plugin tests in CI
2026-09-29 12:49:54 +08:00
HanifKoh 8ffd3e514e Harden OBJ and DRC Import Against Malformed Files (#15948)
* Validate OBJ Texture-Coordinate Indices

load_obj read the texture coordinates of a face without checking the
vt index, so a face referencing a vt past the end of the list read out
of bounds and crashed, and a face vertex with no vt read index -1.
Out-of-range or missing indices now fall back to a zero UV. The face
keeps its entry in the per-face UV list, so the following faces stay
aligned, and the geometry loads as before.

Negative (relative) vt indices were also rebased by dividing the float
count by 3, but each vt stores two floats.

* Reject DRC Meshes Without Positions or with Invalid Face Indices

load_drc dereferenced the POSITION attribute without checking that the
mesh has one, and trusted the decoded face indices, which the Draco
decoder does not check against the point count. Both now fail the load
cleanly. A failed vertex conversion is treated the same way.

The libslic3r tests link Draco so they can encode the malformed meshes
in-test.

* Keep OBJ Texture Coordinates That Carry a W Component

The vt parser stopped reading the optional third component when texture
coordinates were cut down to u and v, but the check that nothing is left
on the line stayed. A legal "vt u v w" line was therefore rejected and
silently dropped, shifting every later texture index. The w component is
parsed again and discarded.

The texture coordinate stride is now a named constant, OBJ_TEXCOORD_LENGTH,
used by the parser and the importer, so the relative-index rebase cannot
drift from the storage layout again.
2026-09-29 12:25:16 +08:00
Paulcake 7d8318f275 profiles: initialize Ender-3 V3 SE extrusion mode before purge (#15489)
# Description

The Ender-3 V3 SE machine start G-code performs its purge using
absolute-style extrusion positions:

```gcode
G1 ... E15
G1 ... E30
```

However, the machine start G-code does not explicitly initialize the
positioning or extrusion mode before these commands.

OrcaSlicer emits the printer's custom `machine_start_gcode` before its
own generated `G90` / `M82` or `M83` preamble. This means the purge can
inherit the extrusion mode left active by the printer.

For example, if `M83` relative extrusion is still active, such as after
a cancelled print where normal end G-code was not executed:

- `E15` extrudes 15 mm
- `E30` extrudes another 30 mm

Instead of the intended 15 mm followed by another 15 mm.

This change explicitly adds:

```gcode
G90 ;Absolute positioning
M82 ;Absolute extrusion mode
```

before the purge sequence so startup behaviour is deterministic and does
not depend on inherited printer state.

The change is applied consistently to all Ender-3 V3 SE nozzle variants:

- 0.2 mm
- 0.4 mm
- 0.6 mm
- 0.8 mm

No print speeds, temperatures, retraction values, machine limits, or
other profile settings are changed.

# Screenshots/Recordings/Graphs

Not applicable. This is a machine start G-code profile fix.

## Tests

- Confirmed all four Ender-3 V3 SE profiles use the same `E15` / `E30`
purge sequence.
- Confirmed the current profiles do not explicitly issue `G90`, `M82`,
or `M83` before that purge.
- Confirmed OrcaSlicer emits `machine_start_gcode` before its generated
positioning/extrusion-mode preamble.
- Verified the modified JSON for all four machine profiles parses
successfully.
- Verified the added commands make the purge explicitly use absolute XYZ
and absolute extrusion state.
2026-09-29 11:15:28 +08:00
SoftFever 9688f0ae62 Slice-validate every custom G-code and filename_format in system profiles (#15966)
# Description

Follow-up to #15950, where a `filename_format` using
`initial_no_support_extruder` shipped broken because the profile
validator's slice sweep never expands `filename_format`. The sweep now
expands every custom G-code and `filename_format` text shipped in any
system profile. Each printer's slice also fires the pause, template
custom G-code and clumping-detection hooks and names the output file,
and the first printer shipping a `printing_by_object_gcode` also slices
by object. Beyond each printer's default process and filament, every
compatible system process and filament carrying a template text no
earlier slice has expanded is sliced once, which takes the sweep from
1,110 to 1,248 slices (about 49 s locally, up from 43 s). While the
sweep runs, the placeholder parser also resolves variable names inside
`{if}` branches a slice does not take, so one expansion checks every
branch.

The stricter sweep found two profile bugs, fixed here: the Anycubic
Kobra X filament change G-code carried an unreachable block reading
variables only Anycubic's own slicer defines, and the Wanhao France D12
template custom G-code had an unterminated `{if}`, so adding a template
custom G-code on those printers failed the slice. It also fixes a parser
bug where a declaration such as `{local a = layer_height + 1}` failed to
parse inside a branch that is not taken.

No change to slicing output for templates that already worked: the
untaken-branch check is enabled only by the validator's slice mode, and
the parser fix only lets previously rejected templates parse.

# Screenshots/Recordings/Graphs

<!--
> Please attach relevant screenshots to showcase the UI changes.
> Please attach images that can help explain the changes.
-->

## Tests

New placeholder-parser cases cover the parse fix and the untaken-branch
check: off by default it changes nothing; on, it rejects undefined names
in branches not taken, accepts names declared there, and leaves boolean
expressions (compatibility conditions) alone. The full sweep passes on
all system profiles, and planting an undefined variable in an untaken
branch of a printer's start G-code, of a non-default filament's start
G-code or of a non-default process's `filename_format`, or reverting
#15950, each fails it and names the preset. `scripts/check_profile.sh`,
`libslic3r_tests` and `fff_print_tests` pass.

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-09-29 10:39:17 +08:00
Clifford GarwoodandClaude Opus 5 bd8b7ced6a Colour the carriage markers by filament where the preview does
Multi-material previews now open in Filament view, where toolpaths are coloured
by the filament printing them, and a marker carrying a fixed palette colour can
sit on toolpaths of that same colour. The plan already resolves which physical
head each carriage is, so in that view every carriage - the primary marker
included - takes its head's filament colour, from the accessor the ghosts
restamp themselves with, and marker, ghost and toolpath agree on what is loaded
where. The primary marker is the one every preview draws, so it goes back to its
own colour when no parallel mode is active.

Every other view keeps the Okabe-Ito palette, which is what identifies the
carriages when colour means something else, and so does a head whose filament
does not resolve. Each head is resolved once per frame and shared by its marker
and its toolhead box, the way the ghosts already hoist the map they all read.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-28 17:31:27 -04:00
Clifford GarwoodandClaude Opus 5 4e65b741cc Draw the IDEX/IQEX ghosts in the X-Ray pass that replaced their own
X-Ray takes both shaded passes over and returns, and it draws only the volume
collection, which the ghosts are not part of. They disappeared while their
picking pass, hover tooltip and filament picker all kept answering, so a plate
in a parallel mode offered an invisible click target.

They go through the X-Ray shader rather than their own, so a ghost reads as one
more see-through body, which is what the mode is for. The pass supplies z_range
and clipping_plane itself, since the volume collection sets them for the whole
pass it runs and the vertex shader discards everything outside z_range. It also
draws two-sided, so a hollow ghost shows its far wall like a real body does, and
hands the shader an opaque colour: X-Ray derives coverage from the view angle
and multiplies the colour's alpha into it, so a ghost carrying its own
translucency as well would composite far fainter than the body it mirrors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-28 17:31:27 -04:00
Clifford Garwood 299093844f Merge upstream main: multi-variant printers, X-Ray view, preview and startup work
The two conflicts are both places where upstream landed on top of IDEX/IQEX
code. In GCode.cpp the relocated file header block meets the IMEX placeholder
block, and the placeholders are set first: file_start_gcode is processed through
the placeholder parser now, which throws on a name it does not know, so a script
naming {imex_mode} would abort the export if the header ran first. In
test_multifilament.cpp both sides appended a case at the end of the file.
2026-09-28 17:12:53 -04:00
Santiago Postorivo 79afb020db fix(device): resolve current-print thumbnail placeholder in Device panel (#15911) 2026-09-28 17:15:29 -03:00
45bc39a47a Fix cli opengl context version (#15745)
Co-authored-by: chris <basque-estate.0b@icloud.com>
Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
2026-09-28 15:33:21 -03:00
HanifKoh d35ea27ea5 Validate Zip Entry Sizes Before Parsing 3MF XML (#15958)
The 3MF importers read XML entries into a single expat buffer whose size is
an int, while the archive extraction used the entry's 64-bit declared size.
The two could disagree for entries declaring more than INT_MAX bytes.

Reject such entries before allocating, and use one size for the buffer, the
extraction and the parse. This applies to the BBS importer, the PrusaSlicer
importer and the PrusaSlicer fingerprint probe. The load now fails with an
error instead.
2026-09-29 02:32:50 +08:00
HanifKoh 490d134507 Harden 3MF Loading Against Malformed Plate IDs and Paint Data (#15959)
* Reject 3MF Plate IDs Below 1 Instead of Indexing Before the Plate List

The plate importer copied each plater_id from model_settings.config into the
1-based plate list after checking only the upper bound, so plater_id="0"
wrote to plate_data_list[-1] and crashed on load. Both copy sites now reject
ids below 1 with the same "invalid plate index" error already used for ids
past the end.

* Drop Malformed 3MF Paint Data Instead of Reading Past the Bitstream

Painted facets are decoded from a bitstream a nibble at a time with no bound
check, so a truncated or corrupt paint string in a 3MF (for example split
codes with no children behind them) read past the end and crashed on load and
slice. A one- or two-side split naming side 3 also indexed past the triangle's
vertices.

Every nibble read now goes through a bounds-checked reader. Loading validates
each triangle's tree and drops a malformed one with a warning, so the stored
data, used extruder states and later decoding all agree. deserialize() also
unwinds and clears any triangle whose tree is incomplete or malformed, and
has_facets() stops at a truncated triangle. Valid streams decode unchanged.
2026-09-29 02:31:26 +08:00
HanifKoh 41eeaf3883 Sanitize Server-Supplied Download File Names (#15955)
* Sanitize Server-Supplied Download File Names

The URL downloader used the file name from the Content-Disposition header
as given, without the cleaning and unused-name search applied to the
URL-derived name.

Reduce the header name to a sanitized base name with the new
sanitize_file_basename helper, which splits on both path separators and
rejects names made only of dots and spaces. Run the result through the
same unused-name search as the URL-derived name, now shared in
find_unused_filename, and fall back to the URL-derived name when nothing
usable remains.

* Sanitize Download Names Before Choosing an Unused One

The unused-name search probed the name as given and sanitized the
result afterwards, so a name whose special characters are replaced
could be mapped onto a file that already exists.

Move the search into libslic3r as find_unused_filename, sanitize first
and probe the name that is actually written. The download marker path
is shared through download_marker_path. Restore the last tried name in
the error reported when no free name is found, and cover the search
with unit tests.

* Keep Downloads on an Unused Name Until They Complete

When the server supplied the name, the download marker stayed under the
URL-derived name, so the adopted name was not reserved against other
downloads. The final rename also replaced any file that took the name
while the download ran.

Move the marker to the adopted name before any data is written, and
check the name again right before the final rename, picking the next
free name if it is taken by then.

* Sanitize the File Name of Model Import Links

The model import took the file name from the link as given and only
avoided an existing file with a substring match on the folder listing.

Reduce the name to a sanitized base name, falling back to untitled.3mf,
choose the name with the shared unused-name search, and check it again
before the final rename.

* Handle Filesystem Errors When Finishing a Model Import Download

Choosing the final name and moving the downloaded project into place
could throw from inside the download callback. Any such error now removes
the temporary file and reports the existing import failure message.
2026-09-29 02:19:24 +08:00
Rodrigo FaselliandIan Bassi 11e9e07f20 Non-crossing infill optimization (#15931)
* Non-crossing infill optimization

* test triangles

* test grid

* cleaning

* Align and clip rectilinear infill paths

Generate infill coverage in the pattern's local frame, rotate triangular patterns by layer, and clip centerlines to the surface vicinity. Start closed outlines outside the surface so clipping splits them cleanly.

* Update test_fill.cpp

* Update multiline-infill.md

---------

Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
2026-09-28 15:13:57 -03:00
SoftFever 9f34f37c27 Merge branch 'main' into feature/slice-sweep-full-placeholder-coverage 2026-09-29 01:57:28 +08:00
SoftFever 9d8257d2eb Support extruder variants on every printer (#15964)
# Description

Extruder variants (Standard, High Flow, extra high flow) now work on any
printer. Any vendor profile can declare them, and a multi-variant
filament picks up the right variant on every printer. In the sidebar,
users can switch the printer variant and set the nozzle volume type of
each extruder on multi-extruder printers. This also fixes a later
filament printing at the first filament's temperature on a P1S or X1C
with a High Flow nozzle. The profile checks now reject variant arrays of
the wrong size and outdated variant strings. Every shipped vendor
profile passes them, and the orca-profiles skill documents the rules.

Slicing output changes only where the wrong variant was used before. 
# Screenshots/Recordings/Graphs
<img width="393" height="218" alt="Screenshot 2026-09-28 at 11 28 07 PM"
src="https://github.com/user-attachments/assets/8bee4b0e-c38c-4039-8c11-096ace6fbad0"
/>
<img width="448" height="267" alt="Screenshot 2026-09-28 at 11 28 37 PM"
src="https://github.com/user-attachments/assets/e767cd97-a5d0-4728-b010-c8ea2bc94ca7"
/>
<img width="746" height="603" alt="Screenshot 2026-09-28 at 11 28 54 PM"
src="https://github.com/user-attachments/assets/23c8af3b-c679-46e5-9fd0-2e43df0449b3"
/>




https://github.com/user-attachments/assets/10d75d72-86a3-42e8-8a95-b1627bd58e91



## Tests

<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-09-29 01:57:01 +08:00
SoftFever 185cfe4323 Slice-validate every custom G-code and filename_format in system profiles 2026-09-29 01:53:30 +08:00
SoftFever 78fb4f767a Fix the Wanhao France D12 template custom G-code failing to parse 2026-09-29 01:53:30 +08:00
SoftFever 05da6bbcc8 Remove unreachable ACE block from the Kobra X filament change G-code
The block ran only when flush_length_4 is -1392 and read ace_t_box_vector / ace_t_slot_vector, which only Anycubic's own slicer defines. It emitted comments only, so the printed G-code is unchanged.
2026-09-29 01:53:30 +08:00
Ian Chua 0a55e6ef83 fix: expose initial_no_support_extruder to the filename format template (#15950) 2026-09-29 01:52:25 +08:00
1846407e93 Add Precise Seam placement feature (#12974)
Co-authored-by: Ioannis Giannakas <59056762+igiannakas@users.noreply.github.com>
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
Co-authored-by: Ian Bassi <ian.bassi@outlook.com>
2026-09-28 14:40:55 -03:00
SoftFever 52679ea1bc Bump the version of every vendor bundle this branch changes 2026-09-28 23:48:22 +08:00
SoftFever d48e63b5e3 Merge branch 'main' into feature/add-multi-variant 2026-09-28 23:30:14 +08:00
SoftFever 7a2daaa351 Make all vendor profiles pass the updated profile checks 2026-09-28 23:02:04 +08:00
Ian Chua 08f086daf3 fix: tolerate unsupported OFL publisher branches (pre 2.5.x) (#15962) 2026-09-28 20:40:24 +08:00
Ian Chua 293aa3e0ed fix: OFL workflow checkpoint and clear ordering (#15960)
# Description

<!--
> Please provide a summary of the changes made in this PR. Include
details such as:
  > * What issue does this PR address or fix?
  > * What new features or enhancements does this PR introduce?
> * Are there any breaking changes or dependencies that need to be
considered?
-->
This PR re-orders the OFL OTA auto-publish workflow by using successful
cron runs as checkpoints, marking and waiting for every dispatched
profile publisher to finish, and clearing the pending queue once
centrally only after all publishers succeed.

# Screenshots/Recordings/Graphs

<!--
> Please attach relevant screenshots to showcase the UI changes.
> Please attach images that can help explain the changes.
-->

## Tests

<!--
> Please describe the tests that you have conducted to verify the
changes made in this PR.
-->

<!--
> A guide for users on how to download the artifacts from this PR.
-->

[How to Download Pull Requests Artifacts for
Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts)
2026-09-28 20:00:04 +08:00
Ian Chua faeb84da72 fix: change checkpointing to use last cronjob instead 2026-09-28 19:59:01 +08:00
anjisandyw4z c30c9beb09 Fix clipped tall models in G-code preview for gcode files (#15360)
Fix clipped tall models in G-code preview

Co-authored-by: yw4z <ywsyildiz@gmail.com>
2026-09-28 14:58:24 +03:00
Ian Chua 77f8c64d37 fix: OFL workflow checkpoint and clear ordering 2026-09-28 19:53:23 +08:00
SoftFever 00a2c5a087 update profile checks 2026-09-28 19:08:35 +08:00