mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-18 13:10:54 +00:00
hanif/python-bytecode-bundle
100
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
4ee1b9c6e9 |
Add a ResourceTexture plugin capability for height-map texture packs (#16473)
# Description
Adds a fifth Python plugin capability type, `ResourceTexture`, which
contributes
height-map textures to the Texture Displacement picker. A plugin returns
a
directory of images; they appear as selectable textures in the picker,
grouped
under one collapsible section per pack. Disabling or uninstalling a pack
removes
them again, and projects that already use one of its textures keep
working,
because a layer holds its own image bytes.
**The plugin-facing contract** is one method:
```python
class WoodPack(orca.resource_texture.ResourceTexturePluginCapabilityBase):
def get_name(self):
return "Wood Pack"
def get_texture_dir(self):
return os.path.join(os.path.dirname(__file__), "textures")
```
The host scans one non-recursive level of that directory, accepting the
same
formats a hand-picked image already accepts (`.png/.jpg/.jpeg/.bmp`),
and decodes
them through the same `load_texture_image_data()` the picker uses for
the user's
own images, so a pack texture and a hand-picked one behave identically.
**Distribution is `.whl` only for v1.** `install_plugin` copies exactly
one
file, so a `.py` plugin cannot ship sibling images; a wheel is a single
file and
the loader already extracts it on demand.
**Files of interest**
- `src/slic3r/plugin/pluginTypes/resourceTexture/` — the capability, its
trampoline and its pybind base, mirroring the Pages type.
- `src/slic3r/plugin/host/PluginResourceTextures.{hpp,cpp}` — host
registry,
free of wx and GUI includes so it can sit beside `PluginManager`.
- `src/slic3r/GUI/TextureLibrary.{hpp,cpp}` — the third texture source,
the
`pack_name` provenance on an entry, and a generation counter.
- `src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp` — the picker.
- `src/slic3r/plugin/PluginFsUtils.{hpp,cpp}` —
`collect_resource_texture_files()`.
**Behaviour change worth a reviewer's attention:** the picker popup is
now a
fixed size that scrolls rather than sizing itself to its content, and it
gains
one collapsible section per pack. The sizing applies to every user, not
only
those with packs installed. With no packs installed the picker otherwise
behaves
exactly as before.
**Not in scope for v1:** folder or `.zip` install for non-programmers,
and
preset-referenceable pack textures (which would need a plugin-backed
`ConfigOptionDef::plugin_type`).
# Screenshots/Recordings/Graphs
https://github.com/user-attachments/assets/b96787cf-b475-4698-826d-5db8b9f386f1
## Tests
New suite `tests/slic3rutils/test_plugin_resource_texture.cpp`, 19
cases:
- Validator: a file inside the root is listed; a parent-directory escape
and an
absolute directory outside the root are refused; a symlink pointing
outside is
skipped; files in a subdirectory are not listed; non-regular entries are
skipped; the extension whitelist is case-insensitive and rejects
near-misses;
the listing stops at 64 files; a missing directory yields an error.
- Listing and lifecycle: a pack's images appear and clear on disable and
unload;
an empty pack contributes nothing; two distinctly named packs each stay
one
contiguous run; a second pack declaring a loaded capability name is
refused;
reinstalling with different bytes at the same path changes the decoded
content.
- Hostile overrides: `get_texture_dir()` returning `data_dir()` or
`resources_dir()` is refused and the pack loads with no textures; a
raising
override still loads the pack.
- Decoding: PNG and BMP from a pack decode through the same path as the
same
files picked by hand.
- Persistence: a project keeps a pack texture after the pack is
uninstalled,
bytes unchanged across a re-save.
- Wheel metadata: a minimal resource-texture wheel is accepted.
Known gaps, for transparency: the wheel path is covered only at the
metadata
gate, not through a full extraction-and-import lifecycle; there is no
test for a
registry callback after interpreter shutdown, as there is no seam for it
without
reaching into `src/`; and `.jpg` decode parity is covered by the listing
rather
than by a real fixture, since no JPEG encoder is available to synthesise
one.
Manually exercised in-app on Linux with a locally built pack wheel (five
colour
PNGs): install, enable, textures listed under the pack's own section,
then
disable and uninstall remove them. The new suite itself has not been run
locally — CI is the first execution.
|
||
|
|
bc8d0a7858 | Wait for the cloud preset sync before offering to migrate filament presets (#16523) | ||
|
|
e0651ec31d | Let ccache cache precompiled-header compiles in Linux builds (#16519) | ||
|
|
86905a8a20 |
Use a keyboard icon for the shortcut button and fix unreadable guide tooltips (#16515)
* Fix unreadable text in wiki and video guide tooltips * Use a keyboard icon for the gizmo shortcut button * Fix blank tooltips on the Move and Scale gizmo combo boxes |
||
|
|
51efb24752 | Complete traditional Chinese translations (#16513) | ||
|
|
cf9ec18df5 | Complete the Simplified Chinese translations (#16512) | ||
|
|
1cbf97568d |
Texture displacement: tooltips beside the panel, with illustrations (#16472)
Draft - description to follow. |
||
|
|
96464ccdf6 |
Fix Align/Distribute and add it to the Move gizmo (#16479)
# Description Follow-up to #13373, which added Align/Distribute to the object context menu. This fixes the problems found in its review and brings BambuStudio's align and distribute controls to the Move gizmo. Align and distribute now work when all copies of an object are selected, on parts of rotated, scaled or mirrored objects, and on objects with several copies, whose other copies used to lose the part move. Aligning a single object arranges its solid parts and leaves modifiers and negative volumes in place. Moves in Z are offered only when Auto-Drop would not undo them. Commands that would do nothing are disabled, each operation is a single undo step, and other plates keep their slicing result. The same fix stops the automatic drop to the bed after a move, rotate, scale or mirror from also moving copies of other selected objects. The Move gizmo gets BambuStudio's align row. It aligns or distributes the selected objects or parts, or aligns them to their object or to the plate, and previews the target while you hover an icon. While the Move gizmo is open, Ctrl+click adds objects to the selection, and Alt+click adds or removes parts of the selected object. No change to slicing output or project files. # Screenshots/Recordings/Graphs https://github.com/user-attachments/assets/44c308c3-faff-4f51-a3b7-88f264f03743 ## 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) |
||
|
|
76e0168d1e | Stop Windows builds failing when the Chocolatey feed is down (#16482) | ||
|
|
e77ba5f672 | Open .gcode files with their own settings, as .gcode.3mf files are (#16463) | ||
|
|
1591423f91 | Fix crash when opening a G-code file exported by OrcaSlicer (#16441) | ||
|
|
7131dd30e7 | Lower peak memory when the G-code preview loads (#16440) | ||
|
|
df392508b7 |
Fix texture projection UV orientation (#16393)
# Description An image laid onto a model came out upside down under the box (tri-planar) projection, and on three of a cube's six faces it was also mirrored left to right. The sampler treats `v = 0` as the height map's top pixel row, but every projection built `v` from world +Z, so `v` grew upward. The mirroring is a separate defect: both faces sharing a world plane got the same `u`. Note: re-baking an existing project now places its texture upright, so it will look different from before. Geometry already baked into a 3mf is unaffected. # Images <img width="2420" height="1655" alt="image" src="https://github.com/user-attachments/assets/dcf7f62f-0f51-4966-97e4-d0386eb454c2" /> # Tests 6 tests added in `tests/libslic3r/test_texture_displacement.cpp`, covering all six cube faces and every mapping mode, plus a full bake of a known asymmetric image. <!-- > 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) |
||
|
|
11493a2236 | Merge branch 'main' into fix-texture-uv-orientation | ||
|
|
df4c8cd531 |
Free G-code result and preview memory on reset (#16065)
GCodeProcessorResult declares a copy assignment, which suppresses the implicit move assignment, so `*result = std::move(processor.extract_result())` binds to the copy and duplicates the whole moves array: 96 bytes per move, measured at 147.7 MiB in one allocation for a 597k facet model at 0.08 mm, with the source staying alive until the export returns. Add the move assignment. It assigns exactly the same 39 members in the same order as the copy, including the ones the copy deliberately leaves alone, so a target that carries its own filament maps and nozzle type keeps them. A move constructor is intentionally not added: the type holds a std::mutex, so it is neither copy nor move constructible today and a partial one would leave ten members uninitialised. reset() now releases the two print sized vectors rather than clearing them. Its callers are the paths that discard a result, so the memory went back only at the next slice. ViewerImpl::reset() does the same for the two vectors sized by the print, which is what keeps a discarded preview resident, and counts m_vertices_colors in the reported CPU memory, where it was missing. |
||
|
|
3ca182a98e |
Fix H2C start G-code record-data comments (#16406)
This fixes the H2C start G-code template by commenting the two `========== record data ==========` separator lines. Those lines are currently emitted as raw text inside `machine_start_gcode`. Since they are not comments or G-code commands, they can make the generated start sequence invalid or firmware-dependent when the template is used. The fix preserves the separators as comments. Fixes #16218. Validation: - Parsed the modified JSON profile with Python `json.loads`. - Checked both `record data` separator lines now start with `;` after unescaping the G-code string. |
||
|
|
5e19fc0e6c |
Stop leaking layers on re-slice and honor each object's slice closing radius (#16066)
# Description Re-slicing no longer leaks layers in two places. Tree supports dropped the support layers above the topmost overhang without freeing them. And an object that had sliced itself, then became identical to another object (for example a copy whose original lost a per-object setting or modifier), leaked its own layers when it switched to sharing that object's slices; it now frees them once it takes the shared layers over. If slicing is cancelled before that point, they still leak, as before. Tree support also stops copying its collision and avoidance areas on every lookup, and releases its working cache once supports are generated instead of keeping it until the next slice. Elephant-foot compensation now uses each object's own slice closing radius, where the first object sliced in a session used to fix the value for every later slice. Slicing output changes only on layers with more than one region printed with elephant-foot compensation and no raft, and only where an object's slice closing radius differs from the value the session had fixed. # Screenshots/Recordings/Graphs <!-- > Please attach relevant screenshots to showcase the UI changes. > Please attach images that can help explain the changes. --> ## Tests Adds a regression test for an object that switches to sharing another object's slices. The `fff_print` suite passes. <!-- > 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) 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
3f4709aaa7 |
Fix stale and hidden highlights in the texture displacement gizmo (#16409)
# Description Fixes highlights in the texture displacement gizmo that stayed on screen after the state behind them changed, or were drawn where they could not be seen. Erase whole model, Select whole model and Capture current view update the paint highlight at once instead of on the next right-click. A stroke released outside the 3D view ends on the next mouse move, in every paint gizmo, rather than leaving the brush stuck in its pressed colour. The layer textures stop showing an image that has been replaced. Selecting islands in the UV editor switches a Normal view to Fast, where their highlight is visible instead of buried under the displaced relief, and Normal comes back once no island is selected unless another view was picked in the meantime. No change to slicing output; the changes are confined to the paint gizmos and the UV editor. # 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) |
||
|
|
f49d49b5a6 |
Texture displacement: typed values on every panel slider (#16395)
Every slider in the texture displacement panel can now be given an exact number, either by Ctrl+clicking the track or via a small edit icon at its right end. Both routes reuse ImGui's own temp-input mode. Each slider also gets a tooltip with its description and its range, and the panel's `?` popup lists both ways in. Draft: description to be refined. |
||
|
|
08f2037cbd |
Texture displacement: save layers, textures and paint in the .3mf (#16148)
## General Nothing about texture displacement was written to the `.3mf`, so a painted relief did not survive closing the project. Everything the user set up is saved now, so a project reopens with the relief intact and still editable. ### What is saved - The layer stack: every per-layer setting (depth, midlevel, smoothing, tiling, projection blend mode, colour) and the per-volume options - Each layer's texture, as a file in the archive (why? because user might want to move .3mf to another computer where custom textures are missing, or he saves .3mf then deletes textures, and returns back to .3mf) - The painted region, one mask per layer slot - The UV work: LSCM seams, island placement, per-vertex overrides - Editor state: the selected layer and Standard/Pro, so the panel reopens where it was left ### What is not saved - The preview mesh. It is a second copy of the model in the file, for something the app rebuilds quickly on reopen. - Panel docked/undocked, which goes to the application config instead ## Format - `<volume id>.json` - the layer stack and the per-volume options - `<volume id>_<slot>.png` - each layer's texture, referenced from the JSON through `path_in_3mf` Paint masks ride along as one per-triangle attribute per slot (`paint_texture_0..7`), beside the attributes the existing paint tools already write. ## Compatibility Both ways: - an older build ignores what it does not know and still opens the project, losing only the relief - a newer build finds nothing in an older project and leaves the volume as today. |
||
|
|
d2675f15d1 |
Fix Qidi start G-code ignoring the selected plate type (#16372)
# Description With "Support multi bed types" enabled on a Qidi printer, the first-layer bed temperature was always taken from the Smooth PEI / High Temp Plate setting, whichever plate type was selected. The slicer computes the right value (`first_layer_bed_temperature` in the G-code footer follows the selected plate), but the machine start G-code of these presets hardcoded `[hot_plate_temp_initial_layer]`: - `fdm_qidi_x3_common` (base of X-Max 3, X-Plus 3, X-Smart 3, X-Plus 4, Q1 Pro) - `Qidi Q1 Pro 0.4 nozzle` - `Qidi X-CF Pro 0.4 nozzle` They now use `[bed_temperature_initial_layer_single]`, which follows the selected plate type, as most other profiles do. The Qidi bundle version is bumped to `02.04.00.17`. With "Support multi bed types" disabled, these printers use the default plate (Smooth PEI / High Temp Plate), so the temperature is unchanged there. # Screenshots/Recordings/Graphs N/A — profile change only. ## Tests `python3 scripts/orca_profile_tool.py check` passes. Sliced on Qidi X-Max 3 0.4 nozzle with "Support multi bed types" enabled, `0.20mm Standard @Qidi XMax3`, `Generic PLA @Qidi`, with a different bed temperature set for each plate type (first layer / other layers). Before, with first layer set to 50–55 °C: `M190 S54` for every plate type. After, a two-layer print: | Plate type | Set (first / other) | `M190` at start | `M140` at layer 2 | | --- | --- | --- | --- | | Cool Plate SuperTack | 51 / 61 | 51 | 61 | | Cool Plate | 52 / 62 | 52 | 62 | | Textured Cool Plate | 53 / 63 | 53 | 63 | | Engineering Plate | 54 / 64 | 54 | 64 | | Smooth PEI / High Temp Plate | 55 / 65 | 55 | 65 | | Textured PEI Plate | 56 / 66 | 56 | 66 | 🤖 Generated with [Claude Code](https://claude.com/claude-code)4 |
||
|
|
a243941b72 |
Add favorite filaments to AMS filament dropdown (#13946)
# Description ## Summary: Adds favorite filament support to the AMS material selection dropdown. Users can now click a star icon next to a selectable filament in the AMS Materials Setting dialog to mark it as a favorite. Favorited filaments appear in a new `Favorite filaments` section at the top of the dropdown, while all compatible filaments remain available in the `All filaments` section. This PR also adds generic right-side action icon support to Orca's custom dropdown widget: - Adds optional action icons to `DropDown::Item`. - Adds a new `EVT_DROPDOWN_ITEM_ACTION` event for clicks on the action icon. - Relays the action event through `ComboBox`. - Adds `ComboBox::RefreshDropdownIfOpen()` so callers can refresh an already-open dropdown without changing normal `ForceDropdownOpen()` behavior. The AMS favorites implementation: - Uses existing bundled star assets: - `score_star_dark` for non-favorited filaments - `score_star_light` for favorited filaments - Stores favorite filament IDs in app config under `ams_favorite_filament_ids`. - Stores stable filament IDs instead of display names - Uses existing C-style string escaping helpers for persistence. - Keeps Bambu/RFID/read-only slot behavior unchanged No new external dependencies. **Note:** `AMSMaterialsSetting` now uses Orca's custom `ComboBox` on macOS as well, because the favorite-star UI depends on the custom `DropDown` item renderer. I was able to test this on Windows, but macOS/Linux smoke testing is still needed and would be appreciated. # Screenshots/Recordings: https://github.com/user-attachments/assets/41e881be-d4de-4a7d-8f99-4297567adef2 <img width="494" height="36" alt="Screenshot 2026-05-30 103432" src="https://github.com/user-attachments/assets/e7c34ed3-db7a-4705-a1cd-4bfe7ac1616a" /> ## Tests Tested on Windows: - Built OrcaSlicer locally - Opened the Device tab with Bambu Lab printer with AMS - Opened the AMS Materials Setting dialog from an editable AMS slot - Confirmed clicking a star toggles favorite state. - Star clicks do not select the filament row. - Dropdown remains open after toggling a favorite. - Confirmed favorited filaments appear under `Favorite filaments`. - All compatible filaments remain visible under `All filaments`. - Confirmed Filament still selected as before - Confirmed favorites persist after closing and reopening the dialog. - Confirmed favorites persist after restarting OrcaSlicer. - Confirmed the favorite IDs are saved in `OrcaSlicer.conf` under `ams_favorite_filament_ids`. - Bambu/RFID/read-only filament slots continue using the existing read-only display behavior. Not tested: - macOS - Linux/Wayland These should be tested, `ComboBox` behavior not tested on macOS. [How to Download Pull Requests Artifacts for Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts) |
||
|
|
cab7a7d75f | Translate the web dialogs and pages through the .po catalogs (#16363) | ||
|
|
bd125d32da | Support searching the Speed Dial by English names in any UI language (#16369) | ||
|
|
bae8f64b8b |
Complete and refine Simplified Chinese translations (#16356)
* Complete Simplified Chinese translations * Fix Simplified Chinese 3D view, camera and extruder terms * Use Chinese CAD view names on the navigator cube |
||
|
|
00cfb5b259 | Refresh translation catalogs and fix xgettext warnings (#16346) | ||
|
|
cd5b786704 |
Add AnkerMake PLA+ filament profiles (Basic, Matte, Metallic, Silk, Glitter) (#16293)
# Description Adds Anker's own AnkerMake PLA+ filament line to the Anker vendor bundle: **Basic, Matte, Metallic, Silk, Glitter**. Until now the bundle only had `Generic PLA+ @Anker`. Each filament follows the existing Anker layout. A `@Anker base` profile (`instantiation: false`, inherits `Generic PLA+ @Anker base`, `filament_vendor: AnkerMake`) holds the settings. An instantiated `@Anker` profile holds only `compatible_printers`. `filament_id` and `setting_id` were minted with `scripts/orca_profile_tool.py generate-id`, and `Anker.json` was re-indexed with `update-index`. The Anker vendor version goes from `02.04.00.05` to `02.04.00.06`. ## Source of the values The values come from the AnkerMake filament profiles bundled with **eufyMake Studio** (Anker's PrusaSlicer 2.6 fork, AGPL-3.0, source at https://github.com/eufymake/eufyMake-PrusaSlicer-Release), in `profiles/Anker-ini/AnkerMake base/base.ini`. OrcaSlicer is also AGPL-3.0. Conversion notes: - PrusaSlicer keys are mapped to their Orca equivalents. For example, `bed_temperature`/`first_layer_bed_temperature` go to `hot_plate_temp*` and `textured_plate_temp*`, `fan_below_layer_time` goes to `fan_cooling_layer_time`, `slowdown_below_layer_time` goes to `slow_down_layer_time`, and `extrusion_multiplier` goes to `filament_flow_ratio`. Only keys that differ from the inherited `Generic PLA+ @Anker base` chain are written. - Where Studio sets retraction but leaves deretraction unset (Metallic, Silk), `filament_deretraction_speed` is set equal to the retraction speed. That matches Prusa's "0 = same as retract" meaning. - **Max volumetric speed is new.** Studio ships `filament_max_volumetric_speed = 0` (uncapped) for these filaments, and Orca has no equivalent. The caps were derived from the peak flow that Studio's own M5C "Fast" process pushes: Basic/Matte/Glitter 22 mm³/s, Metallic 20, Silk 13. Please treat these as the least-validated numbers in the PR. - Studio has pressure advance disabled for these filaments, so no PA values are carried over. - Colour variants are not included because they differ only in colour. `default_filament_colour` uses each family's base colour. - `compatible_printers` follows Studio's `compatible_printers_condition` for each family, limited to the 0.4/0.6 printers that `Generic PLA+ @Anker` covers: - Basic, Glitter: M5, M5 All-Metal, M5C at 0.4 and 0.6 - Silk: 0.4 on all three, plus M5C 0.6 and M5 All-Metal 0.6 (Studio excludes M5 0.6) - Matte, Metallic: 0.4 only (Studio restricts these to 0.4) - Studio also allows Basic on 0.2 nozzles. That variant is not added, because the 0.2 Generic profiles use a separate low-flow cap. # Screenshots/Recordings/Graphs N/A (profile-only change). ## Tests - `scripts/check_profile.sh` (local twin of the CI job, run against the full profile tree with the nightly macOS validator) passes all five checks: `profile_tool`, `validate_system`, `validate_slice`, `validate_filament_subtypes`, `validate_custom` (fixtures v1.9.0 to v2.4.2). - `python3 -m unittest discover -s scripts/tests -t scripts`: OK. - The submitter printed with these filament settings in eufyMake Studio on the M5C's stock brass 0.4 nozzle without issues. This Orca conversion has been loaded and sliced in Orca 2.4.2 (as user presets inheriting the Anker generic PLA+) but not yet printed on brass. The printer now has a different nozzle fitted. [How to Download Pull Requests Artifacts for Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts) 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
e5d5fb47ca |
Fix BBL infill retraction reduction default (#16201)
# Description Restore `"reduce_infill_retraction": "1"` in the shared Bambu Lab process profile. The BambuStudio profile sync (#15851) replaced it with `reduce_infill_retraction_mode`, which OrcaSlicer does not support, causing the setting to fall back to disabled. This restores the pre-sync behavior and bumps the BBL bundle version to 02.08.00.13. # Validation - All 233 selectable BBL process presets inherit the restored setting with no other resolved settings change. - Static profile validation, system loading, filament validation, and all 1,263 slice cases pass. Fixes #16194 <!-- > 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) |
||
|
|
63918b44a8 | Merge branch 'main' into anker-ankermake-pla-plus-filaments | ||
|
|
53c57c94fd |
Fix the 3D view stuttering every few seconds while signed in to Orca Cloud (#16340)
# Description Orbiting or panning the 3D view no longer hitches every five seconds on Windows and macOS while signed in to Orca Cloud. The stutter is a regression from #15710. No change to slicing or to the Orca Cloud connection status shown in the GUI. # 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) |
||
|
|
aa14598e32 |
iXex: Parallel Printing Support for IDEX and IQEX Printers (#13086)
## Summary This PR adds first-class parallel printing support to OrcaSlicer for printers with multiple independent X-axis carriages — the **IDEX** and **IQEX** hardware families. The feature is named **IMEX** (independent multi-extruder) internally, which captures the supported topology space more accurately than either acronym alone, and is exposed in the UI under the user-facing label **IDEX/IQEX Configuration**. It is designed to be printer-agnostic and firmware-flexible, with Klipper, RepRapFirmware, and Marlin all supported for per-tool Pressure Advance and per-layer temperature management. MMU/AFC setups where multiple logical filament slots share one physical extruder are supported via a `physical_extruder_map` profile option. Printers whose firmware handles copy/mirror placement internally — RepRapFirmware IDEX duplication mode on Flashforge Creator Pro 2 / Creator 3 Pro is the canonical example — are supported through a firmware-managed-zones flag that emits a centered single-half slice for the firmware to fan out. The implementation spans printer configuration, process settings UI, bed visualization, per-plate mode selection, ghost-object rendering with per-plate filament overrides, placement validation, pre-slice conflict warnings, G-code generation (with per-tool PA, per-layer temperature management, and optional center-origin slice frame), and layer preview animation. It supports five distinct topology paradigms: - **1 gantry × 2–4 tools** — classic IDEX with 2 tools (BCN3D Sigma, Snapmaker J1, Tenlog Hands-2 style — two independent X carriages on a shared Y gantry); multi-extruder on a shared rail when extended to 3 or 4. - **2 gantries × 1 tool each** — two fully-independent XY systems sharing a bed (Vivedino Xplorer style). Both Y rails independent — effectively "half an IQEX." - **2×2 grid, independent quadrants** — IQEX running four separate prints in parallel. - **2×2 grid, paired-gantry multicolor** — IQEX where cross-gantry tools share color responsibilities via the **Span** tile state. - **Firmware-managed center-origin** — slicer emits a centered single-half slice; firmware decides where to physically fan it out. Overlays on any of the above hardware topologies; canonical example is Flashforge IDEX with RepRapFirmware. --- ## Feature Walkthrough ### Printer Configuration Printer preset options that declare IMEX capability and geometry: | Option | Type | Description | |--------|------|-------------| | `is_imex` | bool | Marks this printer as IMEX-capable | | `imex_firmware_managed_zones` | bool | Emit centered single-half slice; firmware handles copy/mirror placement (default `false`) | | `imex_gantry_count` | int | Number of independent Y-axis gantries (rows) | | `imex_tools_per_gantry` | int (1–4) | Toolheads per gantry along X (columns) | | `imex_nozzle_clearance_x` / `imex_nozzle_clearance_y` | float | Nozzle-to-collision-edge distance in mm (literal, not halved) | | `imex_tool_layout` | string | Physical orientation: front-left / front-right / rear-left / rear-right | | `imex_mode_names` | string[] | Names of user-defined parallel modes; first entry is the reserved `primary` sentinel | | `imex_mode_active_tools` | string[] | Tool role assignments per mode (e.g. `0:P,1:C,2:M,3:M`, or `0:P,1:S,2:M,3:M` with Span) | | `imex_mode_gcodes` | string[] | Firmware macro to activate per mode | | `physical_extruder_map` | string[] | 0-indexed map from logical filament slots to physical extruders (for MMU/AFC — see below) | Tool roles per mode: **Primary** (P), **Copy** (C), **Mirror** (M), **Span** (S), **Inactive**. ### Parallel Mode Editor [Kooha-2026-05-14-13-45-35.webm](https://github.com/user-attachments/assets/af7650e6-d636-478b-9398-3f02ec662f03) The **IDEX/IQEX Configuration** and **IDEX/IQEX Parallel Modes** sections live in the printer preset's **Multimaterial** page (visible only when `is_imex = true`). The mode editor is a visual grid: - Each row defines one named parallel mode. The first row is a reserved, non-deletable **Primary** row stored as the sentinel `primary` in `imex_mode_names`. - The Primary tool is always T0; **Tool 0 Position** chooses which physical corner it occupies, and its tile is read-only. The other tool buttons cycle Inactive → Copy → Mirror → Span → Inactive, color-coded, with Span offered only where it applies. - **Span** is only offered when `imex_gantry_count >= 2` AND the tile is on the primary's gantry row — it declares "this tool is the multi-color partner of Primary on the same gantry," distinct from a Copy/Mirror role on a non-primary gantry. - A G-code field per mode holds the firmware macro to activate that mode (e.g. `IMEX_COPY` for Klipper). A placeholder-browser button per row opens the `EditGCodeDialog` for quick insertion. - Modes can be added and removed (removed via a dedicated `imex_remove.svg` ScalableButton). - Deleting the active mode resets affected plates to Primary. - Tool assignments are preserved across `imex_gantry_count` changes: going from IQEX (4 carriages) → IDEX (2 carriages) → IQEX restores all previously assigned roles, and the visible grid anchors to the gantry row containing the Primary assignment. <!-- TODO: replace this placeholder with a re-recorded parallel-mode-editor video showing the Span tile state, the remove button, and the placeholder-browser button. Old URL (out of date): https://github.com/user-attachments/assets/cabf1f70-206d-4f84-9c2e-594b38b83951 --> ### Span Tile State — Paired-Gantry Multicolor <img width="2833" height="1300" alt="2026-05-14-135412_grim" src="https://github.com/user-attachments/assets/52203133-7380-459a-973f-0502a1edc3c2" /> For IQEX printers (`imex_gantry_count >= 2`), the **Span (S)** tile role enables paired-gantry multicolor mirror mode. The same active-tools string `0:P,1:C,2:M,3:M` is ambiguous between two distinct hardware jobs — four independent quadrants vs. paired-gantry multicolor mirror — so the topology has to be declared explicitly rather than inferred. Span on the primary's gantry row is the declaration. Behavior driven by Span presence: - **Multicolor block rule**: requires Span on primary's gantry to allow multi-color slicing in a parallel mode. Without Span, multi-color slicing in a parallel mode is blocked with an actionable error message. - **Ghost aggregation**: one aggregated ghost per non-primary gantry when Span is present, using the column-paired representative tool. Mixed-role gantries fall back to per-tool. - **Zone aggregation**: one row-strip zone per non-primary gantry when Span is present (cell at primary's column collapses col-sep; `make_boxes` expands to full-X strip). - **Aggregated mirror drag**: ghost translates 1:1 with primary in X (copy-style), with X-flip baked into the mesh-local frame so geometry still reads as mirrored. Gantries don't share an X rail, so reflecting motion serves no collision purpose. - **Carriage collision strip audit**: X-boundary checks require `zr == pri_row_k` (matching the existing Y-boundary `c == pri_col` constraint). Prevents spurious strips on primary's right edge in paired-gantry mc-mirror, where T3 sits diagonally and can't actually collide with primary's carriage. Single source of truth: `IMEXHelpers::group_imex_active_tools_by_gantry(active_tools_str, tools_per_gantry)`. Ghost factory and zone calculator both consume it, so pairing logic lives in one place. ### Per-Plate Mode Selection Each build plate has an IMEX mode icon in its toolbar (normal, hover, dark, and dark-hover SVG variants). The mode can be set independently per plate: - **Left-click** cycles through all non-sentinel modes in order. - **Right-click** opens a popup menu listing all modes as radio items for direct selection. - Mode changes are recorded in the undo/redo snapshot system. - The selected mode is persisted in the 3MF project file per plate (`imex_parallel_mode` key). https://github.com/user-attachments/assets/5ab497e3-9c2f-476a-ac67-ef34a592395b When a parallel mode is active alongside multi-material objects on the same plate, a warning badge (`obj_warning.svg`) overlays the plate icon — see **Pre-Slice Warning System** below. ### Bed Visualization + Auto-Arrange Constraints When an IMEX mode is active, the build plate renders the carriage grid: <img width="2761" height="1447" alt="IMEX bed visualization with active primary zone and dimmed secondary zones" src="https://github.com/user-attachments/assets/3ee64b7b-a3ed-40aa-ad07-fa2f1cb74edf" /> - The **active (primary) zone** is full brightness. - **Inactive zones** are dimmed with a color-coded overlay (blue for copy, orange for mirror). - **Zone dividers** are rendered as lines across the bed. - The grid is a full 2D layout: `imex_tools_per_gantry` columns × `imex_gantry_count` rows. Zone sizing is based on the **active** tool count only — inactive tools donate their bed share to active neighbors. - Span-present configs render as a single row-strip zone per non-primary gantry rather than per-tool quadrants, reflecting that the firmware will paint the multi-color across the entire strip. - Colors are drawn from the Okabe-Ito palette for colorblind accessibility, with a deuteranopia/protanopia-safe alternate theme. - **Auto-arrange** is constrained to the primary zone when a parallel mode is active — `ArrangeJob::process()` replaces full-bed `bedpts` with the primary zone corners via `PartPlate::imex_primary_zone()`. Collision strips are additionally registered as hard obstacles through `m_unselected` (the working NFP placer input, not the dead `excluded_regions` field), so placement cannot drop parts into the danger strips. ### Placement Validation https://github.com/user-attachments/assets/5cb5a94a-981e-4fe9-898e-7e2f891b4f40 Objects placed outside the primary zone block slicing: - `has_imex_placement_violations()` in `PartPlate` checks each object's convex hull against the primary zone boundaries and collision strips. - Violations inject into the existing `update_background_process` validation pathway — the Slice button is disabled and an error notification is shown. - Mirror tools additionally generate X-axis collision strips (copy tools move in the same direction and cannot collide). Y-direction strips are scoped to same-column tools to avoid false positives from diagonal mirror pairs. - Strip width is taken **literally** from `imex_nozzle_clearance_x` (the measurement is nozzle-to-collision-edge distance, not carriage half-width). - Multi-color block path: a pre-slice rule blocks multi-color slicing in parallel modes that can't physically support it (e.g. a "fake IMEX" mode where all tools sit on a single gantry without a Span partner). The rule is centralized in `imex_multicolor_block_reason()` with unit-test coverage of every gating case. ### Ghost Object Rendering + Per-Plate Filament Picker When a parallel mode is active, the slicer renders colored, transparent **ghost copies** of primary-head instances on the plate — one per secondary active head, transformed under its Copy/Mirror role (or aggregated per gantry when Span is present). - Ghosts track the primary through drag/rotate/scale/mirror and invalidate on mode, filament-map, or `physical_extruder_map` changes. - **Left-click** on a ghost opens the `IMEXFilamentPickerPopover` for that ghost's head — a compact `BitmapComboBox` that writes directly to the per-plate `imex_head_filament_map` (MMU lane override). - Mirror ghost geometry is a **true reflection about the zone-boundary plane** (`x = primary_zone_center.x + gantry_offset.x/2`), so the ghost stays anchored in the target zone as the primary moves and drag reflects correctly (primary +X → ghost −X, Y tracks 1:1). - Hover tooltip: `"Tn → filament N"` with a color swatch. When no filament resolves to a head, the tooltip surfaces an actionable message directing the user to extend the extruder count in the Machine tab. - Ghost rendering + picking are scoped to the active plate — non-active plates don't draw stale ghosts during arrange/preview transitions, and click-picking never falls through to a non-current plate's ghost geometry. - Per-plate `imex_head_filament_map` round-trips through the 3MF project file. ### Pre-Slice Warning System <img width="1786" height="911" alt="2026-05-14-135714_grim" src="https://github.com/user-attachments/assets/16532d47-2da5-4472-ab9c-4b8b00303bae" /> Before a plate slices, IMEX parallel-mode plates are checked for three classes of conflict: 1. **Multi-material on secondary tools** — when the mode has Copy/Mirror tools and the plate has multiple filaments active; plate icon gets a warning badge. 2. **Bed temperature mismatch** — any two carriages configured >5 °C apart. 3. **Filament type incompatibility** — filaments from different type families on active carriages. A dismissible Yes/No `RichMessageDialog` fires once per user action from both `on_action_slice_plate` and `on_action_slice_all`. The dialog has a **"Don't show again"** checkbox that persists to `app_config` as `imex_pre_slice_warnings=false`. A re-enable toggle lives in **Printer Settings → Multimaterial → IDEX/IQEX Configuration** so suppressed warnings can be restored. ### Firmware-Managed Zones — Center-Origin Slice <img width="701" height="197" alt="2026-05-14-135842_grim" src="https://github.com/user-attachments/assets/3e2dfaab-fb4f-42b1-bf9d-c88dc0c95110" /> The `imex_firmware_managed_zones` printer-config option (default `false`) supports IDEX/IQEX printers whose firmware applies its own copy/mirror offsets in non-primary modes. Canonical examples: **RepRapFirmware IDEX duplication mode** on **Flashforge Creator Pro 2 / Creator 3 Pro**. These printers expect a centered single-half slice at bed origin and fan toolheads out from there — the slicer-managed paradigm of placing toolpaths at zone-relative positions produces gcode the firmware can't reconcile, since it'd double-apply offsets. When the flag is on and the active mode is non-primary, the slicer subtracts the primary zone's plate-local center from the gcode emission frame: - **Writer offset** is augmented by the primary zone center so emitted gcode is centered at bed origin. - **Processor offset** stays at plate_origin only, so the gcode-preview visualizer renders the centered toolpath at bed center rather than at the prepare-view zone placement. The user sees what'll physically print after firmware fan-out. - **`translate_to_print_space()`** is augmented for frame coherence so `first_layer_print_min/max` placeholders consumed by user start_gcode (e.g. Flashforge's M118 "max delta from zero" header) reflect the centered frame. Slice-handoff runs per-slice: `PartPlate::refresh_imex_slice_offset()` is called from `Plater::priv::update_background_process` after `Print::apply()`, so reslicing with mode toggled but no plate change picks up the updated offset. When the flag is off, all related code paths reduce to no-ops byte-identical to standard slicer-managed behavior. The two stock-code touches at `Print.cpp:2553-2554` (gcode_offset composition) and `Print.cpp:2823-2829` (translate_to_print_space) are explicit additive shifts that collapse to identity when the offset is `Vec2d::Zero()`. ### G-code Injection The selected parallel mode's G-code is written into the output file immediately before `machine_start_gcode`: - Looks up the plate's active mode name in `imex_mode_names` and writes the corresponding `imex_mode_gcodes` entry. - Processed through `placeholder_parser_process()` first, so Klipper-style variable substitution works **and** any `{global}` declarations flow forward into `machine_start_gcode`. - Primary mode's G-code field is emitted too. - Guarded against headless CLI slicing — `ensure_imex_zones()` short-circuits when `m_plater` is null so the CLI path (used by upstream's regression-test CI step) doesn't segfault on `wxGetApp().preset_bundle` dereference. ### Placeholder Parser Integration <img width="535" height="393" alt="2026-05-14-140227_grim" src="https://github.com/user-attachments/assets/6d059c77-38f6-4418-bfe9-3bf963e8c836" /> Three placeholders register under **Slicing State** and are settable from anywhere downstream: | Placeholder | Type | Description | |---|---|---| | `imex_mode` | string | The active mode name | | `imex_mode_index` | int | Index into `imex_mode_names` | | `imex_mode_gcode` | string | The resolved mode G-code (post-parser) | ### Per-Tool Pressure Advance — Firmware-Agnostic `set_pressure_advance()` takes an optional tool index (default `-1`, preserving existing behavior for all non-IMEX call sites). Per firmware: - **Klipper**: `EXTRUDER=extruder[N]` when `tool >= 0`, bare command otherwise - **RepRapFirmware**: `M572 D<N>` when `tool >= 0`, `M572 D0` otherwise (preserves the pre-IMEX output; a bare `M572` applies to whatever tool is selected and errors when there is none) - **Marlin 2**: `M900 K<X> T<N>` when `tool >= 0`, bare `M900` otherwise - **Marlin Legacy / fallback**: `M900 K<X>` always - **Repetier**: `M233 X<X> Y<X>` (X is quadratic, Y is linear; same value applied to both) `m_imex_parallel_mode` is set once per export from the active plate mode. PA tool-qualification is gated on this being a **non-primary** parallel mode — primary-mode prints emit ordinary tool-change PA exactly like any non-IMEX printer. Secondary active tools in parallel modes receive explicit per-tool PA at print start since they never go through a tool-change sequence. ### Per-Layer Temperature Management In IMEX parallel modes, all active tools (primary + secondaries) get temperature commands in `layer_change_gcode`: - Layer 1 temperatures only emit on the first layer; subsequent layers use normal layer-change temperatures. - IMEX temperature handling is consolidated into the second-layer transition. - Layer-change temperature commands use `M104 T<N>` with `physical_extruder_map` translation when applicable. ### MMU / AFC Support via `physical_extruder_map` For printers where multiple logical filament slots share one physical extruder (MMU, AFC, toolchangers), the `physical_extruder_map` profile option translates tool slot indices to physical extruder qualifiers before G-code emission. - **Fallback**: on IMEX printers, `Print::apply()` uses the profile's map only when it has one entry per extruder (the `nozzle_diameter` count). Anything else, including the single-entry default, is replaced by the identity map `0..n-1`. - **Used by**: IMEX PA emission, layer-change temperature commands (`M104 T`, `EXTRUDER=`, `M572 D`), ghost color resolution, ghost cache key, tooltip lookup, click gate. - **Profile authoring example** for a 7-slot printer with a 4-lane MMU on extruder 0 and three independent direct drives on extruders 1/2/3: ```json "physical_extruder_map": ["0","0","0","0","1","2","3"] ``` Non-MMU printers need no action — the identity fallback handles them. - A centralized helper in `IMEXHelpers`, `effective_physical_extruder_map(explicit_pem, nozzle_count)` (with a `PresetBundle` overload that prefers the project's map over the printer's), routes all PA/temp/ghost-color lookups through a single code path. - **No UI for editing the map** in this PR — non-trivial MMU/AFC layouts require profile-authoring (hand-edit the printer JSON) or an updated printer profile shipped by a vendor. A future enhancement would expose a per-slot extruder picker in the Multimaterial section. ### Layer Preview Multi-Carriage Animation The sequential preview (scrubber) animates all active carriages simultaneously: - One toolhead marker (colored cube) per active carriage, in addition to the primary. - Secondary marker colors: cyan (T1), yellow (T2), magenta (T3). - **Copy** tools: marker placed at the same relative position within their bed zone as the primary is in the primary zone. - **Mirror** tools: reflect across the target zone's facing edge (left-of-copy reflects across copy zone's left edge; right-of-copy across the right edge). Y position is always zone-relative copy (all tools on a row share a physical Y rail). - Carriage footprint boxes use per-carriage `box_offset_x/y` so the nozzle marker sits at the physically correct edge of the footprint — zone-based X by default, collision-side edge for Mirror; gantry-behind Y for back-row primaries, flipped for front-row primaries with a back-row secondary. - The filament usage legend notes the active carriage count and mode name (e.g. `IMEX: ×2 (copy_mode)`). - **View menu toggle**: `View → Show IDEX/IQEX Toolhead` (visible only on the Preview tab, only when the active printer is IDEX/IQEX) hides/shows the per-carriage toolhead representation during preview playback. State persists to `app_config` as `show_imex_toolhead_boxes`. Useful when scrubbing through dense toolpaths and the boxes get in the way of seeing the underlying geometry: [Kooha-2026-05-14-14-04-09.webm](https://github.com/user-attachments/assets/9869cd4d-3b60-4a6b-8dca-7ee1fc573ac1) Copy mode: https://github.com/user-attachments/assets/0774d285-ba36-4b86-a594-fb6572c3aede Mirror mode: https://github.com/user-attachments/assets/51528926-94dc-4d90-9b1a-1b42d9044be7 --- ## Known Limitations **Per-layer G-code collision detection** The placement-time zone check catches gross violations (object placed in wrong zone) but does not verify that toolpaths on any given layer maintain adequate X separation between adjacent carriages. A per-layer check via `ConflictChecker` was designed but deferred. Without it, a print that passes placement validation could still crash carriages if the primary object's toolpaths reach too close to a zone boundary. **Brim avoidance of IMEX zones** Standard `bed_exclude_area` exclusion zones are already respected by brim generation. IMEX collision strips are not — the brim generator has no visibility into them. The correct fix (feeding computed strip polygons from `PartPlate` through the `Print` object to `Brim.cpp`) was designed but deferred. In practice, users should leave adequate clearance between printed objects and zone boundaries to account for brim width. **`extruder_printable_area` integration** IMEX zones are not clipped against per-extruder printable polygons, and there is no violation check for placing an object outside the intersection of its active extruder's printable area and the IMEX primary zone. Deferred pending clarification on the tool→extruder index mapping. **Ghost rendering in firmware-managed mode** When `imex_firmware_managed_zones` is on, ghost rendering is suppressed entirely. The existing `imex_head_transform` math is slicer-managed semantics (places ghosts at `primary_zone_center + gantry_offset`) and produces wrong positions when the toolpath is being emitted in a centered frame. Proper firmware-managed ghost rendering — showing where copies/mirrors will physically print after firmware fan-out — needs new transforms designed around firmware-frame positions rather than a coordinate-flip of the slicer-managed ones. Deferred to a follow-up. **Filament-accurate multi-region ghost color** For paired-gantry multicolor mirror (Span mode), the aggregated ghost currently uses the representative tool's filament color as a single solid swatch. A future enhancement would render the ghost split into per-source-tool regions, each colored by the secondary tool that mirrors it. Slicer-side correctness is already shipped — the G-code emits the right T-codes; the ghost is a visual aid only. **Ghost path overlays** Secondary carriage toolpaths are not rendered in the layer preview. The secondary markers animate correctly, but the paths they would trace are not drawn. Adding ghost path rendering would require duplicating and offsetting the toolpath geometry per secondary carriage, which is a significant addition to the libvgcode rendering pipeline. **No per-mode slicing** All carriages in a mode execute the same sliced toolpaths (transformed per zone). There is no support for slicing different objects for each carriage independently within one mode. **Global default IMEX mode** There is no job-level IMEX default mode. Each plate's mode must be set individually (default is always Primary). A future improvement would add a global default in the sidebar (following the same pattern as bed type and nozzle diameter), with per-plate overrides. **Dynamic GL-rendered mode icons** The per-plate icon currently uses static SVGs. A GL-rendered carriage-grid icon that visually represents the mode's tool layout would be a nicer UX but is deferred. **Slice-all thumbnail icon refresh** On the "Slice All" path, plates flagged as IMEX-violated do not refresh their toolbar icon. Root cause and fix identified, not yet applied. **Start-G-code filament placeholder** The resolved per-head filament map is not yet exposed as a `PlaceholderParser` vector. Exposing it would let MMU firmware macros pre-load lanes before print start. **No UI for `physical_extruder_map` authoring** The MMU/AFC slot-to-physical-extruder map is currently profile-only — there's no in-app dropdown or editor for it. Users with non-trivial MMU/AFC setups must hand-edit the printer-preset JSON (or rely on a vendor-supplied profile). A future enhancement would expose a per-slot extruder picker in the Multimaterial section so users can declare the mapping without touching JSON. **Bundled IQEX printer profile** A full IQEX printer profile with cover image, bed mesh, and matched process/filament profiles is not bundled with this PR. Users must currently author their own printer preset. Deferred to a follow-up profile-only PR. **Mode lifecycle gap** Per-plate mode is stored as a string (the mode name). If a mode is renamed or deleted from the printer preset after a project is saved, the plate's saved mode name will not resolve and will silently fall back to Primary on next load. A warning on load would be a useful addition. **Firmware-managed prepare→preview frame jump** In firmware-managed-zones mode, the prepare view shows the part at its placed-in-zone position while the preview view shows the centered slice. This is intentional — the views truthfully represent the prepare frame vs. the post-firmware-fan-out frame — but the visual jump can be confusing on first use. --- ## Firmware Assumptions - The implementation assumes the firmware handles all carriage synchronization and offset math. OrcaSlicer only injects the mode-activation macro before machine start and is entirely dependent on user configuration. - Per-tool Pressure Advance is firmware-aware (Klipper / RRF / Marlin 2 / Marlin Legacy / Repetier). Layer-change temperature commands use `M104 T<N>` with `physical_extruder_map` translation. - Tested against Klipper on a real IQEX printer. RepRapFirmware gcode emission is exercised via profile-driven slice tests (Flashforge Creator Pro 2 profile); Marlin and RRF paths have not been validated on real hardware print runs. - Mid-print mode switching is explicitly not supported. The mode is locked at print start. - Firmware-managed-zones mode requires the printer's firmware to translate centered slice coordinates into physical toolhead positions; the slicer does not attempt to model the firmware's offset logic. --- ## Files Changed (High-Level) | File | Change | |------|--------| | `src/libslic3r/PrintConfig.{cpp,hpp}` | IMEX config option definitions + declarations, `IMEXMode` enum, `physical_extruder_map`, `imex_head_filament_map` (plate option), `imex_firmware_managed_zones` | | `src/libslic3r/Preset.cpp` | IMEX keys registered in printer and process preset option lists | | `src/libslic3r/PrintApply.cpp` | `physical_extruder_map` identity fallback on IMEX printers | | `src/libslic3r/Print.{cpp,hpp}` | IMEX slice-offset field + accessors; `translate_to_print_space` augmentation for frame coherence | | `src/libslic3r/GCode.{cpp,hpp}` | Mode G-code injection, per-tool PA emission (firmware-agnostic), per-layer temperatures for all active tools, `m_imex_parallel_mode` state, `set_gcode_offset_with_imex_shift` writer/processor split | | `src/libslic3r/GCodeWriter.{cpp,hpp}` | `set_pressure_advance(tool_index = -1)` per-firmware implementation | | `src/libslic3r/IMEXHelpers.{cpp,hpp}` | `imex_head_transform` (Primary/Copy/Mirror), `parse_imex_active_tools`, `imex_primary_tool_for_mode`, `effective_physical_extruder_map`, per-head filament resolution, `group_imex_active_tools_by_gantry` (Span pairing), `compute_imex_slice_offset` (firmware-managed) | | `src/libslic3r/Format/bbs_3mf.cpp` | Per-plate IMEX mode and `imex_head_filament_map` serialization | | `src/slic3r/GUI/Tab.{cpp,hpp}` | `IMEXModesCtrl` in Multimaterial page, tool assignment persistence across gantry count changes, `primary` sentinel handling, Span tile state, firmware-managed-zones checkbox, null guard in `clear_pages()` | | `src/slic3r/GUI/PartPlate.{cpp,hpp}` | Zone visualization (Span row-strip aggregation), placement violation detection, per-plate mode icon, ghost volume rebuild on mode/map/object mutation, warning-badge overlay, pre-slice warning collection, `refresh_imex_slice_offset()`, ghost suppression in firmware-managed mode, headless-CLI guard | | `src/slic3r/GUI/Plater.cpp` | Validation pathway injection, per-plate mode popup, ghost click handling, pre-slice warning dialog with "Don't show again", IMEX multimaterial conflict routing, per-slice IMEX offset refresh in `update_background_process` | | `src/slic3r/GUI/GLCanvas3D.cpp` | Ghost rendering with per-head filament color and translucent blending, picking via volume composite id, active-plate scoping | | `src/slic3r/GUI/GCodeViewer.cpp` | Multi-carriage marker animation, Mirror math fix, carriage footprint box offsets, legend annotation | | `src/slic3r/GUI/IMEXFilamentPickerPopover.{cpp,hpp}` | Ghost-click filament picker | | `src/slic3r/GUI/Jobs/ArrangeJob.cpp` | Auto-arrange constrained to IMEX primary zone + collision strip exclusion via `m_unselected` | | `src/slic3r/GUI/OG_CustomCtrl.cpp` | Empty `option_set` guard for widget-only lines | | `resources/images/plate_imex_mode*.svg`, `imex_remove.svg` | Per-plate mode icons (light/dark/hover variants), remove button | | `tests/libslic3r/test_imex_helpers.cpp` | Coverage for IMEX head transforms, `effective_physical_extruder_map`, `imex_multicolor_block_reason` gating, `group_imex_active_tools_by_gantry` Span pairing, `compute_imex_slice_offset` | --- ## Testing Notes Validated on an IQEX printer (4 carriages, 2×2 grid, Klipper firmware) and against the Flashforge Creator Pro 2 profile (2-tool IDEX, RRF flavor, center-origin bed) with the following configurations: - **Primary only** — baseline, no regression vs. standard single-extruder workflow - **Copy mode** (T0 Primary, T1 Copy, same row) — carriage markers animate in sync offset by strip width; ghost tracks drag/rotate/scale - **Mirror mode** (T0 Primary, T1 Mirror, same row) — T1 marker reflects T0 across zone-boundary plane; ghost drag reflects X correctly while Y tracks 1:1 - **Cross-row copy + mirror** (T0 Primary row 0, T2 Copy row 1, T3 Mirror row 1) — T2 follows T0's zone-relative position; T3 mirrors T2's X; Y shared per row - **4-tool copy mode** (T0 Primary, T1/T2/T3 Copy) — zone sizing correct, all four markers + ghosts render in sync - **Paired-gantry multicolor (mc-mirror, Span)** — `0:P,1:S,2:M,3:M`: ghost aggregates to one per non-primary gantry, X-flipped, drag tracks 1:1 with primary; collision strip audit doesn't fire spurious strips on primary's right edge - **Firmware-managed copy mode** (Flashforge Creator Pro 2) — emitted gcode coordinates are centered at bed origin (X = −cube_half_width … +cube_half_width), `first_layer_print_min/max` placeholders evaluate symmetrically, M118 header produces correct "max delta from zero" values for Flashforge's existing template, ghosts suppressed - **Firmware-managed flag toggle** — flipping the checkbox off restores slicer-managed iMEX behavior (toolpath at zone position) byte-identically; flipping on restores center-origin slice - **Delete active mode** — no crash; plate resets to Primary - **Placement outside primary zone** — slicing blocked with error notification - **Multi-material conflict warning** — plate icon gets warning badge; Yes/No dialog fires on slice; "Don't show again" checkbox persists - **Multi-color block rule** — `0:P,1:C` on a single gantry blocks at slice time with actionable error message - **Ghost filament picker** — left-click on ghost opens picker; selection writes to `imex_head_filament_map` and round-trips through 3MF save/load - **Per-plate mode selection** — left-click cycles modes, right-click shows popup, undo/redo correctly reverts mode changes, mode persists through project save/load - **Gantry count change round-trip** — reducing from IQEX (4 carriages) to IDEX (2 carriages) and back restores all previously assigned tool roles - **MMU/AFC `physical_extruder_map`** — explicit map routes PA and temperature commands to correct physical extruder qualifiers; auto-derive fallback preserves 1:1 behavior for non-MMU printers - **Headless CLI slicing** — `orca-slicer --slice project.3mf` does not segfault on IMEX-enabled printers - **Dark mode** — all four plate-icon variants render correctly - **Pre-slice warnings suppress + restore** — `app_config` flag flips on checkbox; re-enable toggle in Multimaterial config restores dialog - **Stock non-IMEX printer regression check** — slicing a single-head Voron Trident 350 profile produces byte-identical gcode vs. baseline; the firmware-managed flag and Span tile state both no-op when not applicable - **Full unit test suite** — 247/247 passing, including Layer 1 coverage for `compute_imex_slice_offset`, `group_imex_active_tools_by_gantry` Span pairing, and `imex_multicolor_block_reason` gating |
||
|
|
b14ed3e0c1 |
Multi nozzle UI Fixes / Improvements (#16075)
# New multi nozzle icon for guidance new icon has tooltip for guidance <img width="407" height="77" alt="Screenshot-20261005181353" src="https://github.com/user-attachments/assets/f27bbf79-7570-4f30-ab3c-52fa972c9fa3" /> **Before** <img width="414" height="228" alt="Screenshot-20261002144627" src="https://github.com/user-attachments/assets/7941891a-5a27-478b-a63f-49cf386e430f" /> **After - Moved icon to pre label position** • reduces possibility of wrapping of labels • Aligns labels and improves readability <img width="399" height="239" alt="Screenshot-20261005181511" src="https://github.com/user-attachments/assets/93f6b555-bbec-496a-b708-8c12c3b3185b" /> # Fix > Modified state not applied on tabs **Before - modified colors not applied to control** <img width="751" height="157" alt="Screenshot-20261001004828" src="https://github.com/user-attachments/assets/0c149fce-45e8-498f-8daa-7b54803399e9" /> **After** <img width="752" height="150" alt="Screenshot-20261005181614" src="https://github.com/user-attachments/assets/5a930bb2-6487-4987-b58d-850de6ae6779" /> Applied color as border because changing text color was not readable <img width="159" height="71" alt="Screenshot-20261002152522" src="https://github.com/user-attachments/assets/f694fc8d-c9f6-46d7-9e06-7762003c9f20" /> and applying as background color was too eye catchy <img width="184" height="80" alt="Screenshot-20261002152533" src="https://github.com/user-attachments/assets/2b67c1dd-8977-46ea-88fc-ce57bfad55bd" /> # Usable tabs on Printer settings • Fix > Using long string makes "Motion ability" and "Notes" tab unreachable • Matches T1,T2.. terminology with nozzle section • Makes https://github.com/OrcaSlicer/OrcaSlicer/pull/14737 available to use now **Before** <img width="751" height="126" alt="Screenshot-20261002152643" src="https://github.com/user-attachments/assets/0241d3c4-acc1-491e-ab85-fa60385c5e85" /> **After** <img width="748" height="129" alt="Screenshot-20261002152628" src="https://github.com/user-attachments/assets/c475d6c8-4f0f-47df-aa04-9d894b1c358d" /> No issue with 8 items <img width="748" height="124" alt="Screenshot-20261002153018" src="https://github.com/user-attachments/assets/9a8c4e12-2cdc-4508-b82b-134476589d80" /> # Dynamic Padding • buttons uses dynamic horizontal padding now depends on item count. reduces padding size to reduce scrolling **Before** <img width="416" height="91" alt="Screenshot-20261002153309" src="https://github.com/user-attachments/assets/977b22db-e686-4967-95be-13772d77cefd" /> **After** <img width="403" height="79" alt="Screenshot-20261005181728" src="https://github.com/user-attachments/assets/9aac0d17-0729-408f-9237-62b17236488f" /> **Before** <img width="745" height="153" alt="Screenshot-20261002153659" src="https://github.com/user-attachments/assets/06951759-419a-40fb-8fc2-d93f5b04d6ea" /> **After** <img width="748" height="149" alt="Screenshot-20261005181833" src="https://github.com/user-attachments/assets/9ccec344-1dd0-4b03-ac12-20d298f413c8" /> **After** <img width="756" height="178" alt="Screenshot-20261009144637" src="https://github.com/user-attachments/assets/1343c39e-5cbd-4f9e-b501-df3797579961" /> <img width="761" height="198" alt="Screenshot-20261009144459" src="https://github.com/user-attachments/assets/efb1ef75-a602-4d3a-a17f-9354ed633357" /> <img width="758" height="196" alt="Screenshot-20261009144510" src="https://github.com/user-attachments/assets/df1d88c5-1b6f-4748-a6bd-a96659a83fe0" /> <img width="764" height="190" alt="Screenshot-20261009154210" src="https://github.com/user-attachments/assets/b876ed71-5fa0-47e4-83c8-a33100e0a229" /> # Keeping compact look & Making it more readable • Removed ":" from labels to gain space as much as possible and increased font size a bit but UI didnt allowed bigger font • Matched font sizes of nozzle section while keeping height of items. Previous font was too small. removed "mm" text to gain more space but added it in tooltip **Before-After** <img width="800" height="240" alt="Screenshot-20261002154132" src="https://github.com/user-attachments/assets/bc4ddcb1-2248-4fc7-9492-ab4fb68cb659" /> • Matched font sizes for BBL nozzle selectors **Before-After** <img width="806" height="200" alt="Screenshot-20261002154513" src="https://github.com/user-attachments/assets/b3d38317-8e4d-4c1e-a490-ce4959ed700a" /> <img width="794" height="156" alt="Screenshot-20261002154649" src="https://github.com/user-attachments/assets/00917584-8e1a-44b0-8c0b-79cec30059bf" /> # Layout and Styling fixes • Matched background color of non active buttons with (Global/Objects) switch **Before** <img width="405" height="159" alt="Screenshot-20261002154947" src="https://github.com/user-attachments/assets/8a8adcc8-431a-48be-aabd-a981335b6ab9" /> **After** <img width="407" height="159" alt="Screenshot-20261005182106" src="https://github.com/user-attachments/assets/7f837be3-ce85-49e6-909a-05350b3d8b30" /> # Other effected dialogs <img width="541" height="195" alt="Screenshot-20261002165003" src="https://github.com/user-attachments/assets/109abbc3-d7c0-4384-9b85-d943e2027963" /> <img width="547" height="308" alt="Screenshot-20261002165307" src="https://github.com/user-attachments/assets/951d9a8d-56f9-4659-aebe-77f236e8c838" /> <!-- > 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) |
||
|
|
e4142db820 |
Let texture bakes create a chosen number of mixed colours (#16320)
# Description Follow-up to #16242, which turned texture colour mixes into mixed filament slots but created a slot for every possible mix, even when only previewing. A new Mixed colors setting (default 8) caps how many mixed filaments a bake adds. They are picked from the texture's own colours, and only the ones the bake actually paints with are created. Previews no longer touch the project's filaments, both previews show a mix in the colour its slot will have, and the bake paints each mix with the slot it got, which went wrong whenever the project already held mixed slots. It also improves the colour preview: the green paint highlight no longer covers the colours, and the colours a bake writes stay visible in the gizmo. Only texture displacement changes. Models without a colour layer behave as before, and there is no change to project or profile formats. # Screenshots/Recordings/Graphs **Before** https://github.com/user-attachments/assets/554a0d0d-cd9f-4095-840e-ca764dde6d52 **After** https://github.com/user-attachments/assets/7fe10431-8c3f-4759-bd3f-78b4f7a12fc7 ## 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) |
||
|
|
cd0b529e31 | Reject 3MF component references that form a cycle (#16059) | ||
|
|
1bddcf3ab6 |
Retire the separate belt-printer nightly builds (#16308)
# Description Belt printer support is now part of `main` (#14394), so the separate `_belt` nightly builds from the `belt-printer` branch are no longer needed. Nightly builds are published from `main` only again, under their usual names. The README drops its section on the parallel belt builds and lists belt printer support among the main features, crediting its main author, Joseph Robertson (@HarrierPigeon). The nightly release page has already been updated to match. No change to slicing output or to main's nightly asset names — CI and README only. # 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) |
||
|
|
489e337bad |
Merge Belt Printing Into Upstream (#14394)
# Belt printing for OrcaSlicer
This merges the `belt-printer` branch into `main`. It adds support for
conveyor-belt ("infinite Z") printers like the BabyBelt Pro, the
IdeaFormer IR3 V2 and the CR-30 family, along with the things that had
to grow around it: tilted-plane slicing, supports that terminate on the
belt, belt-aware brims, a purge tower that works without a flat bed,
multi-colour belt prints, a preview that shows the part the way it was
designed, and starter profiles.
It has been a long road (the first attempt was #12733 back in March, the
pipeline has been rebuilt twice since) and a lot of people have put work
into it. Credits are at the bottom; please tell me if I've missed
anyone.
Closes #2628, closes #11344, closes #6885, closes #9004, closes #14188.
---
## How belt printing works
Slicers assume the bed sits on the XY plane and layers stack along Z. A
belt printer breaks that in two ways at once: the belt is tilted
(usually 45°) and the axis that advances the belt is the printer's Z, so
the "bed" lives on the XZ plane and is, in principle, infinitely long.
<img width="6360" height="2702" alt="A flat bed vs a tilted belt"
src="https://github.com/user-attachments/assets/3f5542f2-6dab-42bf-9233-f96d863b40c8"
/>
Rather than teach every part of the slicer about tilted beds, the branch
leaves the slicing engine alone and transforms what goes in and what
comes out. The pipeline has five steps.

<details>
<summary><b>The five steps in detail</b></summary>
### 1. Pre-slice rotation
The mesh is rotated by the belt angle before slicing
(`BeltSliceStrategy`, `BeltTransform`), so that the ordinary horizontal
slicer produces layers that are actually tilted planes relative to the
part. Rotation is about X by default (belt along Y); Y rotation and a Z
lift are supported too. A "global" mode rotates every object about one
common origin, which is what keeps several parts on one belt consistent
with each other.
### 2. Slice
Nothing special. The mesh is rotated, the slicer does what it always
does. This is the reason most of Orca's features (walls, infill, seams,
ironing, painting, …) just work on a belt without belt-specific code.
### 3. Supports
Supports are generated after slicing against a virtual floor: the belt
surface, expressed in the rotated frame (`BeltFloorContext`). Normal,
tree and organic supports all terminate on that plane instead of on Z=0,
and nothing may be generated below it. Painted supports and seams are
transformed with the same `trafo_sliced()` as the layers.

### 4. G-code back-transform
The G-code is rotated back into the model's Cartesian frame
(`BeltBackTransform`). A nice side effect: with step 5 switched off you
can slice at a non-standard angle and print the result on a normal
printer. The first belt-sliced Benchy was printed exactly that way, on a
Sovol SV08.
### 5. Machine frame
The printer doesn't know its bed is tilted. To make straight walls come
out straight, the axes are remapped (the default mapping is X → reversed
X, Y → Z, Z → Y) and the result is sheared and scaled:
```math
\begin{bmatrix} X \\ Y \\ Z \end{bmatrix}
\longrightarrow
\begin{bmatrix} X \\ \dfrac{Y}{\cos\alpha} \\ Z + Y\cdot\tan\alpha \end{bmatrix}
```
This lives in `GCodeWriter` behind a small `MachineKinematics` strategy
(`BeltKinematics` on belts, identity otherwise), so the writer itself
has one code path. The slicing angle and the machine angle can differ if
you want to, e.g. slice at 30° on a 45° machine — mind your nozzle
clearance if you do.
</details>
A short recording of the back-transform from the original PR:
https://github.com/user-attachments/assets/cdb9cc83-711d-48b7-9d86-a014a32c5e8e
---
## What had to change to make it work
Belt mode is gated on the `belt_printer` printer setting; with it off,
every code path below is the old one.
<details>
<summary><b>Slicing and geometry</b></summary>
- `PrintObjectSlice` / `PrintObject`: the rotation, Z lift and
per-object layer-grid shift, plus the invalidation that goes with them.
Modifiers and painted volumes are transformed with the same matrix as
the model.
- `FirstLayerPlane`: "the first layer" on a belt is a band along the
belt, not the first slicing layer. First-layer speed, line width and the
fan band are measured against it.
- `Print::validate`: clearance checks against the gantry instead of the
printable height; skirt, raft, draft shield, the classic prime tower,
arc fitting, spiral vase with brim, and scarf-joint seams are refused or
disabled on belts because each of them either doesn't exist on a belt or
moves the belt the wrong way (a scarf seam starts one layer low, which
on a belt is a 0.28 mm back-step into the previous layer at every seam).
- Z-hop defaults to 0 on belt profiles; a lift on a belt is a belt move.
</details>
<details>
<summary><b>Supports</b></summary>
- `SupportMaterial`, `TreeSupport`, `TreeSupport3D`, `TreeModelVolumes`:
a shared `BeltFloorContext` provides the belt plane; supports clip to
it, extension layers are numbered sequentially, and the first-layer
flange that used to be stamped under everything is gone.
- `build_plate_tilt_x/y` (from #12733) is now derived from the slicing
rotation in `Print::apply`, so GUI and CLI agree; it's capped below 90°.
- Organic supports that reach the belt no longer produce negative flow.
</details>
<details>
<summary><b>Brims (#15155)</b></summary>
A belt first layer is effectively a single line of contact, so a brim
matters more than usual. `BeltBrim` generates per-layer bands along the
belt plus an "apron" ahead of the part, in the object's brim filament.
Two belt-specific settings came with it: **Leading edge brim length**
(more lines on the side printed first) and **Extra brim width** (across
the belt), plus a **Leading edge only** brim type.
<img width="1849" height="1043" alt="belt brim"
src="https://github.com/user-attachments/assets/f963ed8e-53e7-48f8-a495-123cb9ae27f7"
/>
</details>
<details>
<summary><b>Multi-colour: the belt purge tower</b></summary>
The classic wipe tower can't exist on a belt (its G-code bypasses the
transform and it needs a flat bed to stand on). Instead the GUI
generates a long, thin "purge prism" beside the parts, flush with the
far edge of the belt, one per plate (`BeltPurgeTower.cpp`). It is a real
model object, so it is sliced like everything else, and
`Print::_plan_belt_purge` routes every filament change into it via
`flush_into_objects`. It's sized from the flush matrix, split into one
island per simultaneous tool change, snapped onto the parts' layer grid,
cut off after the last colour change and stripped of infill no change
claimed, so what prints is a good deal smaller than the model you see in
Prepare.
</details>
<details>
<summary><b>G-code generation and cooling</b></summary>
- `GCodeWriter` + `MachineKinematics`/`BeltKinematics`: the
back-transform, axis remap, shear and scale, lifts that are belt moves,
and the first-layer travel speed.
- `GCode.cpp` / `BeltGCode`: a belt header (slicing rotation, remaps,
machine tilt) that the preview reads back; it is written outside the
optional header block so printers with a BTT TFT thumbnail still get it.
Exclude-object outlines are emitted in the plate frame.
- `CoolingBuffer`: the "first layers" the fan stays off for are a band
above the belt, marked per extrusion segment by the generator
(`;_BELT_BAND_START/END`) and honoured on every layer.
- `GCodeProcessor`: belt header parsing, start-G-code Z handling, and
height checks that don't compare belt travel against the printable
height.
- `ToolOrdering` / `BeltPurge`: filament changes are detected by
scanning the ordering (an apron layer never carries the first-layer
flag).
</details>
<details>
<summary><b>GUI</b></summary>
- Printer settings tab: the belt group (slicing rotation, angle, global
mode, infinite Y, purge tower, floor settings). The axis remap and
pre-slice remap options are Develop-mode only.
- `ConfigManipulation`: everything that doesn't apply on a belt is
greyed out (skirt, raft, draft shield, the wipe tower group, scarf
seams, …).
- Preview: a "designed view" that back-transforms the toolpaths onto the
model so you see the part upright, with `B` toggling the raw
machine-frame G-code (`GCodeViewer`, `Shortcuts`). The tilt comes from
the belt header, so imported G-code behaves.
- Arrange: parts are packed from the end of the belt that prints first,
colours are grouped into runs so each filament change happens once, the
purge tower's strip and the brim width are reserved, and piles aimed at
an off-centre `best_object_pos` are clamped to the bed (`Arrange.cpp`,
`ArrangeJob.cpp`, one clamp in `libnest2d`).
- `PartPlate`: plate icons stay in the gap between plates on a long,
narrow bed; the plate is open along Y for containment tests on an
infinite-Y belt.
- Calibration: a belt temperature tower (overhang variant) that slices
correctly on a tilt.
- The old tilted-bed rendering in Prepare was dormant and has been
removed; the bed is shown as the slicing pipeline treats it.
</details>
<details>
<summary><b>Config options</b></summary>
Printer: `belt_printer`, `belt_printer_infinite_y`,
`belt_slice_rotation`, `belt_slice_rotation_angle`,
`belt_slice_rotation_global`, `belt_preslice_global`,
`belt_frame_tilt_decouple`, `belt_frame_tilt_angle`,
`belt_support_floor_mode`, `belt_support_floor_offset`,
`belt_support_z_offset_mode`, `enable_belt_purge_tower`,
`first_layer_plane`, `first_layer_plane_offset`,
`first_layer_plane_thickness`, `build_plate_tilt_x/y`,
`gcode_back_transform`, `gcode_remap_x/y/z`, `preslice_remap_x/y/z`,
`preslice_remap_global`.
Process: `belt_purge_tower_width`, `leading_brim_length`,
`extra_brim_width`, brim type `leading_edge_only`. Object:
`belt_purge_tower_object`.
All of them have defaults that leave non-belt printers untouched, and
old `belt_support_floor_mode` values map to `none`.
</details>
<details>
<summary><b>Tests</b></summary>
`tests/libslic3r/test_belt_brim.cpp` and `test_arrange.cpp`, and belt
cases in `fff_print` (`test_print.cpp`, `test_skirt_brim.cpp`,
`test_gcodewriter.cpp`, `test_gcode_processor.cpp`): scarf gate, fan
band, gantry clearance, organic supports on the belt, brim with and
without the purge tower, apron widths, machine mapping at non-45°
angles, first-travel lift, start-G-code Z, arrange clamp and colour
grouping. All three suites pass on Linux, and the tree-wide profile
check passes.
</details>
---
## Starter profiles
Three vendors ship belt profiles. Belt mode needs the printer settings
at **Advanced** or above to show its group.
<img alt="advanced mode"
src="https://github.com/user-attachments/assets/7a519ce5-b3b5-400c-a914-4f208bb577b0"
/>
| Printer | Vendor bundle | Nozzles | Processes | Filaments |
|---|---|---|---|---|
| **Generic Belt Printer** (`MyBeltPrinter`) | Custom | 0.2, 0.4, 0.6,
0.8 | 0.20mm Standard, 0.12mm Fine | library |
| **BabyBelt Pro** (Printcepts) | Printcepts | 0.4 | 0.20mm Standard |
Generic PLA, Generic PETG, eSUN PLA |
| **IdeaFormer IR3 V2** | IdeaFormer | 0.4 | 0.20mm Standard | Generic
PLA, Generic PETG, eSUN PLA |
To set up a printer that isn't listed: pick **Generic Belt Printer**,
set the belt width and length, save the profile, then copy in your
machine's start/end G-code and limits and tune from there.
<img alt="generic belt printer"
src="https://github.com/user-attachments/assets/90134d55-d6fe-4dba-8695-5ea44e78ec2b"
/>
<details>
<summary>BabyBelt Pro</summary>
<img width="2467" height="1392" alt="BabyBelt Pro"
src="https://github.com/user-attachments/assets/2b448cee-339e-43c9-964b-1ee9044044c7"
/>
</details>
---
## Contributions
### @HarrierPigeon
***Majority of design & implementation***
I did most of the work here by myself with AI tools (primarily Claude,
some Codex.)
PRs #12733, #12998, #14385, #15155, #15361, #15156, #15526, #16127
### The @Unlayered3D Team
***Rotation-Mode Pipeline***
The initial version of this sheared the model in the pre-slice pipeline.
Talking with them convinced me to switch to the current
rotate->slice->unrotate-> remap & shear method, which had significant
immediate improvements. Working with them has been a blast.
### @tommasobbianchi
***IdeaFormer IR3V2 Profile, eSUN PLA Tuning, G-Code Render / Preview***
TommyB came in at the perfect time to help keep me motivated and
contributed several things I hadn't had the werewithal to implemement
yet. Without their contributions and encouragement, we wouldn't be here
yet.
### The BabyBelt Community
**BabyBelt Pro** — @rexit1982 for the profile, and @RobMink of
Printcepts for the printer and a lot of patient testing.
**Field reports** — Many members of the BabyBelt community helped,
testing on their machines, providing G-Code and examples of issues, and
encouraging me to keep working on it. Among them:
- @RobMink - creator of the BabyBelt
- @rexit1982 - initial BabyBelt Pro profile, bug hunter
- @shubhracc - found a *lot* of technical bugs
- @NeoDLC - bug hunter
and BabyBelt Discord members who found bugs & gave feedback in no
particular order:
- @horatio42 - also provided a build machine while mine was down
- @HotCubCar - requested belt printer brim support
- Swap_File
- @Nyctelios
- Sup
- @matschi140
- @Rise-Run
- @shooby-dooby
### OrcaSlicer Maintainers
**Generic belt printer** — @SoftFever
**Keeping on top of upstream** @RF47 & @HanifKoh
**Review and fixes** — @HanifKoh (#15685 and the review on this PR).
Among them: plates after the first printed off the bed on belts; painted
supports and seams ignored the belt transform; support generation failed
at a 90° tilt; the object table crashed on the Support column on every
printer because tilt keys were in the per-object tables; apron brims
printed in the wrong filament; `build_plate_tilt` went stale outside the
GUI; the CLI reserved a wipe tower on belts; every G-code file was
treated as belt G-code because the config block carries the angle; tests
didn't compile on Clang/MSVC; plus a long list of smaller clean-ups and
the review questions that led to the clearance check, the header length
fix, the retired floor modes and the removal of the diagnostic logging.
### Additional Thanks
A special thanks to LDO Motors, who provided equipment for validating
multicolor, and my wife, who not only put up with with this obsession,
and the addition of three belt printers to our home, but has encouraged
me to keep going ever since I started this project six months ago.
---
## Known Issues
- The purge prism's first tool is chosen by the shared `ToolOrdering`
logic; on some layouts the print opens on the wrong filament and makes
one extra change at the thin tip of the prism (the "cannot absorb the
full purge volume" warning at a low height).
- Colour grouping in arrange is a soft cost: when the belt is too short
for clean runs, colours overlap rather than spill onto another plate.
- Three OrcaFilamentLibrary filaments still carry `filament_z_hop` 0.4;
belt profiles override it to 0.
Also: slicing at an angle other than the machine's (decoupled frame
tilt) is supported but not something the starter profiles exercise.
|
||
|
|
a5d21b9922 | Merge branch 'main' into belt-printer | ||
|
|
dee1f1715f | Merge branch 'main' into feature/texdisp-3mf-persistence | ||
|
|
6edc858f8b | Merge branch 'main' into belt-printer | ||
|
|
5072f6b614 | Merge branch 'main' into belt-printer | ||
|
|
bf59db1053 | Merge branch 'main' into extruder-variants-ui-2 | ||
|
|
7fdfea6efa | Merge branch 'main' into main | ||
|
|
6d02a945e0 |
Speed up the Linux incremental rebuild (optimizes packaging step) (#16244)
## 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"
/>
|
||
|
|
01afd3b5b9 |
Use multiswitch for extruders instead new tabs on printer settings & publish dialog (#16162)
# 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" /> |
||
|
|
67e29f69e7 | Merge branch 'main' into exturuder-tab-multi-switch | ||
|
|
3f36a86f39 |
Use PrusaSlicer's filament-change settings on Prusa MMU3 and INDX printers (#16209)
# Description Filament changes on the Prusa CORE One MMU3, MK4 MMU3 and CORE One INDX now use the settings PrusaSlicer 3.0 ships for them. On the MMU3 printers these are Prusa's per-material ramming, load and unload speeds, cooling moves and stamping. On the INDX they are Prusa's multi-tool ramming and 10 mm³ minimal purge, plus a filament start G-code that restores pressure advance after the purge station disables it and then sends `M573 R`, as PrusaSlicer does. This supersedes #16008. Thanks to @nuclearmistake for that work, which identified what these printers need for reliable filament changes. This PR reaches the same goal with the existing `include` mechanism rather than new printer-level overrides. The values live in shared templates in the Prusa bundle (PLA and PETG families with High Flow ramming variants, and one for the INDX), and the filament presets include them, so each material keeps its own values as in PrusaSlicer. For the MK4 MMU3, ten small presets inherit the MK4 filament tunes and include the templates; they cover the materials PrusaSlicer offers with the MMU3 and replace the library generics as that printer's defaults. The CORE One MMU3 0.6 nozzle now uses the 0.6 Generic PLA and Prusament rPLA profiles, as in PrusaSlicer. Unlike #16008, filaments from Orca's shared library keep Orca's defaults on these printers. No engine change, and printers without an MMU3 or INDX are unaffected. MK4 MMU3 users also get the MK4's material tuning, such as temperatures and cooling, from the new presets. # 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) |
||
|
|
748d86d89f |
Orca CAD feature improvements (#16158)
# Description This PR follows up on #16019 with fixes and workflow improvements to the Design tab. Sketching now waits for you to pick a plane, the reference planes stay out of the way until they are needed, and the camera follows the mouse controls set in Preferences, as suggested by @Felix14-v2 in https://github.com/OrcaSlicer/OrcaSlicer/pull/16019#issuecomment-5932747510. It also fixes rendering, camera and Move bugs, which are listed below. https://github.com/user-attachments/assets/6aac0a03-8405-403a-93b2-1fbf95da9fe7 **Improvements:** - Pan and orbit follow Preferences > Control while sketching too. A right-drag no longer ends the polyline chain or drops the point already placed, and in the Touchpad camera style Alt+move and Shift+move orbit and pan while a draw tool is selected. - The XY, XZ and YZ planes are separate labelled squares around the origin, in their axis colours, with dash-dot axes. They no longer cross through the bed as one grey smear. Hovering over a plane greys it out, and selecting one makes it solid. - The reference planes stay hidden until a sketch needs them. A new Origin row in the Feature tree keeps them on screen, and Ctrl+Shift+O toggles it. - A sketch opens only once its plane is chosen. If a flat face or a reference plane is already picked, the sketch opens on it at once. Otherwise the planes appear, and the next plane or face you click opens the sketch. Esc or Cancel leaves without one. - The Bed checkbox is now a row under Origin, and its state is remembered across sessions. Both rows sit above the feature list as fixed view switches. - Zoom to selection is available on Feature tree and Bodies rows and in the right-click menu. - A Sketch button replaces the FEATURES label, the import icons now have an arrow, and the document icons are sized consistently. **Fixes:** - Feature previews no longer z-fight with the bodies. The Hole preview now hides the bodies and shows only the result, as Fillet/Chamfer and Draft already do. - Body edge lines stay in sync with the bodies after undo, hide and delete. - The bed, grid and reference planes stay aligned on every plate, not only the first. - The Fit camera button frames the selection and sketches, or everything on show, instead of always framing the whole bed. - Grabbing a move arrow no longer makes the body jump on the first drag. - Move no longer gets stuck after Esc or a click off the gizmo. Esc and Cancel put the body back, and undo waits until the Move is confirmed or cancelled. - The camera stays still when the first body appears. - The view buttons no longer cover the status line at display scales above 100%. - The import buttons no longer stay highlighted after a click. - The Bodies right-click menu no longer closes at once on Linux. # Screenshots/Recordings/Graphs - **Z fighting issue** Before fix: https://github.com/user-attachments/assets/0da30897-8d81-494a-a206-9b4dfd8fa9c0 After fix: https://github.com/user-attachments/assets/04ccad39-dbbc-4bcf-8d5c-3ba4894cb755 - **Sketch plane rendering** Before: <img width="374" alt="{CCFCEB16-20FA-4202-A5F8-5F2219E44C0B}" src="https://github.com/user-attachments/assets/2dfd19b2-9991-45c7-91e3-e139d111229c" /> After: <img width="1706" height="1258" alt="image" src="https://github.com/user-attachments/assets/3ec89038-4614-4c04-9f20-37bfc50ee5ef" /> - **Wrong body frame lines** Before: https://github.com/user-attachments/assets/81ccae26-2a9d-4ecb-9928-678dbe9fb94c After ## 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) |
||
|
|
919f507cca | Merge branch 'main' into exturuder-tab-multi-switch | ||
|
|
e47fdcaef7 | Merge branch 'main' into exturuder-tab-multi-switch | ||
|
|
6dfd1c2a0a |
Design tab: one rule for Enter/Esc/mouse, kernel fixes, Text and Revolve-axis features, studio lighting"th 7cp6pk upstream (#16019)
# Description
Follow-up to #15238. A review of the Design tab, and then testing its
Linux AppImage on desktops, turned up UX inconsistencies, kernel bugs
and a crash. This PR fixes them and fills the gaps found along the way.
Everything stays behind `SLIC3R_CAD` and the `enable_cad_feature`
preference. With the preference off, Prepare and Preview behave and
render exactly as before.
The first four commits are Design-tab fixes that landed on the fork
after #15238 and were never sent upstream: the value-field label, the
`GUI.hpp` include, sketch tool batches 9–14 and honest tool messages.
The later commits build on them.
**Interaction: one rule for mouse, Enter and Esc** (charter
`docs/CAD/cad_ux_guidelines.md` §4.2)
- Enter does what ✓ does; Esc does what ✗ does. Esc steps back one level
(value field → gesture → tool → selection) and never deletes anything.
- A click on empty space clears the selection and never applies a
pending operation.
- A right-click with nothing pending opens the offer. The click is
recognised by drift alone; the 200 ms timing rule is gone, since §6.2
forbids timing-dependent gestures.
- The panel's CHAR_HOOK owns Delete, Esc, Ctrl+Z/Y and F, so the
duplicate handlers in `GLCanvas3D` are removed.
- Ctrl+Z/Y work inside a sketch, and Edit ▸ Undo/Redo drive the Design
history while that tab is shown.
- A value the geometry cannot take (zero length, sweep > 360°, …) is
refused inside the field, and the field says why.
**Kernel**
- Solver: tangency and point-on-line pick the correct side;
circle–circle tangency is handled; the partitioned solve maps sentinel
references; constraints that could not be applied are reported instead
of silently dropped.
- Trim, extend, offset and mirror are fixed for arcs and ellipses.
Negative scale is handled, and zero-radius circles no longer produce
geometry.
- Feature → body references resolve by identity, so hiding, reordering
or deleting a feature no longer re-targets later features.
- Hole standards table corrected: inch countersinks are 82°. New threads
use the nominal diameter; new patterns use inclusive spacing. Both are
gated by flags, so existing recipes rebuild unchanged.
- **A closed loop that crosses or folds back is not a region.** Such a
loop passed the closed-loop check and MakeFace, and extruded into an
invalid solid with no caps. `SketchEngine::wires_to_face` now checks the
face (BRepCheck) and fails with a reason; `sketch_loop_defect()` finds
the crossing or cusp exactly, and the sketch tints the loop red and
marks the point.
- Recipe: saves origin, body colours and the loop auto-close setting in
a trailing block; the v4 reader is frozen as `load_flat_v4`; the 3MF
reader caps the entry at 1 GiB and the legacy entry name never overrides
the current one. New fields (`dressup_edges`, the Text parameters,
`revolve_axis_entity`) are appended at the end of the framed recipe, so
existing projects load and rebuild unchanged.
- OCCT failures are caught before `std::exception` in the new code (OCCT
≥ 8).
**Modelling**
- **Several solid edges in one Fillet/Chamfer.** Shift/Ctrl+click adds
or removes edges of the picked body; one feature dresses them all at one
size, every id resolved against the same body. The card and the offer
name the count.
- **Sketch Offset takes the whole outline** the picked curve belongs to,
with a live preview, instead of one segment (on a text outline a segment
is a fraction of a millimetre, so nothing seemed to happen).
- **Revolve about a line of the sketch.** The axis was only the sketch
plane's X or Y axis. It can now be any line of the profile sketch: a
construction centerline (preselected when the sketch has exactly one) or
an edge of the profile. The gizmo draws the axis dashed. A profile on
both sides of the axis is refused with the reason (MakeRevol failed
there with none). Surface Revolve takes the same axes.
**Panel, offer, text**
- The offer menu: its strings are translatable (the generator emits
`L()` markers, and the files are added to `list.txt`); it opens with a
title naming the selection; blocked verbs stay in place, greyed, with
their reason; each verb has one refusal wording.
- Extrude defaults to Join when the profile touches a solid, otherwise
New body. All result menus use one vocabulary: New body / Join / Cut /
Intersect.
- Interference and volume/area reports go to the status line, in
mm³/mm². Delete Body no longer asks for confirmation, since it is
undoable.
- **Text is its own feature** ("Text N" in the tree). Its dialog offers
any installed font (bold, italic) and the height in mm; it is modeless
and opens at the top right of the window, and the outline is drawn in
the view where it will go while typing. Editing the feature reopens the
dialog with its string, font and height. The outlines are saved too, so
the project opens the same on a machine without that font.
- New feature names match the card header (`Extrude 3`) and are
translated. Terminology and units are unified ("Coordinate system",
"Angle (°)").
- The Prepare Sketch/Primitive gizmos can be selected only when the CAD
feature is on.
- MCP: write methods are refused while the tab is busy (including while
the Text dialog is open); a timed-out command never runs; only a socket
is ever unlinked; `fillet`/`chamfer` accept an array of edges.
**Rendering in the Design view**
- Once extruded, a part was hard to read: both lights of the object
shaders sit near the camera, so the sides of a part came out in nearly
the same tone, and nothing marked where one face ends.
- The phong shader gains a studio lighting model, selected by a new
`lighting_model` uniform: a sky/ground hemisphere in world space, a key
light from the upper left and a weak fill, a plastic-like highlight, and
a darker base with a faint sheen toward the silhouette.
`GLCanvas3D::set_studio_lighting()` enables it per canvas; only the
Design canvas does. Every canvas sets the uniform on each use (0 for the
slicer's canvases), so Prepare and Preview render exactly as before.
- Every B-rep edge of a body is drawn as a 2 px dark line, depth tested
and pulled a few pixels toward the eye, so it hides behind the faces in
front. Seams of closed surfaces and degenerate edges are left out
(`GeometryEngine::display_edges`).
**Crash fix (Linux AppImage)**
- Drawing anything in a sketch crashed the AppImage: the constraint list
labels were formatted from narrow literals holding `—`, `·` and `°`;
`AppRun` sets `LC_ALL=C`, so wx's conversion returned NULL and
`wxString::Format` dereferenced it. They now go through
`wxString::FromUTF8`, as the panel's other non-ASCII literals already
do.
Docs updated to describe the design as it now stands: `design_tab.md`,
`interaction-model.md` and the portability note.
No change to slicing, profiles or presets. Existing 3MF recipes load and
rebuild as before: the v3/v4/v5 fixture tests pass.
# Screenshots/Recordings/Graphs
None attached. The behaviour was checked on the fork's Linux tester
AppImages, driven under Xvfb (see Tests).
## Tests
- `libslic3r_tests` on this branch, rebased on `main` (
|
||
|
|
7495b9fda2 | Merge branch 'main' into claude/inspiring-knuth-7cp6pk-upstream | ||
|
|
257c589331 | Merge branch 'main' into claude/inspiring-knuth-7cp6pk-upstream | ||
|
|
19af2b79f7 | Merge branch 'main' into claude/inspiring-knuth-7cp6pk-upstream | ||
|
|
e63c6d0594 | Fix Windows ARM64 builds crashing on every HTTPS connection (#16073) | ||
|
|
96bf754af9 | Merge branch 'main' into claude/inspiring-knuth-7cp6pk-upstream | ||
|
|
3384daa6bc |
Fix bundled Python crashing on macOS 26 and older when built with Xcode 27 (#16035)
# Description With Xcode 27, building deps on macOS 26 fails at the Python install step with a segfault, and a libpython built with Xcode 27 crashes on macOS 12–26 the first time anything calls `os.pipe()`, which every plugin `subprocess` call does. The macOS 27 SDK declares `pipe2()` and `dup3()` as macOS 27-only, and CPython 3.12 calls them without a runtime check once configure finds them, so on older systems they resolve to NULL. This keeps CPython on the `pipe()`/`dup2()` fallbacks it already uses with older SDKs; upstream fixed it in 3.13+ ([python/cpython#153711](https://github.com/python/cpython/issues/153711)) but not in 3.12. No change for builds with Xcode 26 or older, or on Linux and Windows. # Screenshots/Recordings/Graphs <!-- > Please attach relevant screenshots to showcase the UI changes. > Please attach images that can help explain the changes. --> ## Tests Rebuilt deps with Xcode 27 on macOS 26.6: the Python install step now completes, the installed libpython no longer imports `pipe2`/`dup3`, and CPython's `test_os`, `test_subprocess` and `test_posix` pass, apart from one test that needs `_testcapi`, which `--disable-test-modules` leaves out. Running CPython's configure against the macOS 26.5 and 27.0 SDKs gives a byte-identical `pyconfig.h` for 26.5 with and without this change, and for 27.0 with it. The x86_64 cross-build path was configured on arm64 to confirm both of its configure runs pick up the change. <!-- > 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) |
||
|
|
377ebf2a03 | Merge branch 'main' into claude/inspiring-knuth-7cp6pk-upstream | ||
|
|
8aa5b1130a |
Allow nozzle variants to specify different cooling parameters (#16007)
# Description Include variant-aware validation, temperature and pressure controls, named nozzle selection, and filament sidebar refresh. ## Support nozzle-specific filament cooling and tuning Filament presets can require different cooling and tuning for Standard and High Flow nozzle variants. This change makes part and auxiliary cooling, pressure advance, temperature limits, and multitool ramming settings follow the selected variant, with matching UI controls and profile validation. The Snapmaker U1 profiles in #15755 / Snorca illustrate why this matters: | Profile | Standard cooling | High Flow cooling | |---|---|---| | Snapmaker ABS | Part fan: 15–15% | Part fan: 10–60% | | Snapmaker PETG HF, 0.4 mm | Part fan: 20–40% | Part fan: 30–60% | | Snapmaker PETG-CF | Part fan: 0–20%; auxiliary: 0% | Part fan: 5–40%; auxiliary: 20% | | Snapmaker PLA Matte | Auxiliary: 80% | Auxiliary: 100% | These differences need to survive variant selection, editing, and slicing. Shared single values continue to apply across variants, and short filament arrays fall back to element zero, matching the loader. ### Additional changes - Preserve named nozzle selections when refreshing the diameter selector. - Enable or disable the pressure-advance input for the selected variant. - Initialize profile-validation slicing with the printer’s declared nozzle volume type. - Refresh filament controls after preset loading. Profile changes remain separate in `u1-hf`. ### Validation - All 13 focused variant-tool tests passed. - Broader checks encountered an existing Windows path-separator assertion failure, reproduced with upstream code. - C++ build and GUI validation have not been run. [How to Download Pull Requests Artifacts for Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts) |
||
|
|
ba361d9882 |
Texture displacement (#14662)
## Summary Adds a new paint-style **Texture Displacement** gizmo that stamps grayscale height-map textures onto a model's surface and turns them into real relief - engraved or embossed detail - either as a live preview or baked into actual mesh geometry. You paint where a texture applies, stack up to **8 blended texture layers** (image-editor semantics: Add / Subtract / Multiply / Divide), choose how each is projected onto the surface (Triplanar / Cylindrical / Spherical / LSCM unwrap / From-view), and - for the LSCM projection - lay the charts out by hand in a new dockable 2D **UV Editor** pane. Coarse models can be **Subdivided** or **Remeshed** first so there are enough vertices to carry fine detail, and the result is committed with **Bake**, restricted to the painted area only. The tool only ever affects the **painted** region; everything left unpainted keeps its original surface, and bake blends the relief seamlessly into it with no remeshing or hole-filling at the seam. --- ## User-facing features - **Paint the affected area** with Brush (circle/sphere), single-Face, or Connected-area flood fill; or **Select whole model** - reusing the existing `TriangleSelector` / `FacetsAnnotation` painting machinery, one full mask per layer slot. - **Up to 8 texture layers**, each with its own paint mask, texture, and parameters, combined in slot order like image layers. - **Per-layer controls:** Depth, Tile size, Rotation, Midlevel (bidirectional emboss/engrave), Smoothing, Edge smoothing, Invert, Blend mode, Tile (Repeat / Mirrored-repeat / decal), and Projection. - **Projection methods:** Triplanar (blended, seam-free across sharp edges), Cylindrical, Spherical, **Unwrap (LSCM)** - a real CGAL conformal parameterization - and **From view** (slide-projector decals). - **UV Editor pane** for LSCM layers: move / rotate / scale / snap / cut / join islands, average texel density, Checker and Distortion overlays, manual mark- seam workflow, live model update while dragging. - **View modes:** Normal (true displaced geometry = what Bake produces), Fast (GPU bump-shaded approximation of the active layer), Checker, Distortion heatmap, and an independent Wireframe toggle. - **Mesh prep:** Subdivide (1–5* uniform 1->4 split) with cyan-wireframe preview, and CGAL isotropic **Remesh** to a target edge length. - **Texture library:** 10 shipped seamless 512×512 grayscale height maps, plus import of any PNG/JPG/BMP (converted to an 8-bit grayscale map and copied into the user data dir so app updates can't clobber it). - **Bake** runs in the background (off the UI thread); the preview is free to explore and only Bake changes the real mesh. --- ## How it works (implementation) - **Bake is accumulate-then-displace and topology-preserving.** The output mesh has exactly the input's vertices and triangles in the same order; only displaced vertex positions differ. Each layer is evaluated against the **base mesh** and folded per-vertex into a shared accumulator via its blend mode, then every touched vertex moves once along its precomputed undisplaced normal. This replaced an earlier sequential re-mesh-per-layer design that was the root cause of the "second layer never applies" bug and made blend modes impossible. - **Boundary vertices are pinned.** Any vertex shared with an unpainted triangle is never displaced, which is what keeps bakes seamless with zero remeshing. - **LSCM unwrap** uses a new `MeshBoolean::cgal::parameterize_lscm()` built on CGAL's already-vendored `Surface_mesh_parameterization` package - **no new external dependency**. - **Fast GPU preview** perturbs the shading normal from the height gradient (analytic mm-per-mm slope for triplanar; Mikkelsen's screen-space-derivative method for the conformal LSCM path), so apparent depth matches the bake. - **Background jobs:** preview compute and bake both run off the UI thread on the shared job worker (queued, not `replace_job`, so a preview never cancels an in-flight bake); a generation counter discards stale results. - **UV Editor** shares the app's single real `wxGLContext` and reuses the registered `flat`/`flat_texture` shaders; island drags update one affine matrix per island rather than re-uploading geometry. --- ## Backward compatibility & constraints - **Feature is fully gated behind the new gizmo** - it adds no new default behavior and does not touch existing slicing, profiles, or defaults. Models that never open the tool are unaffected. - **Cross-platform** - pure `libslic3r` / `libslic3r_gui` / `libslic3r_cgal` code; no new dependency and no `deps/` rebuild. (Built and tested on Windows; no platform-specific APIs introduced.) - **`.3mf` compatibility:** **baked** relief round-trips fine, since it becomes ordinary mesh geometry via the existing serialization path. **Unbaked** paint masks and layer definitions are **not yet serialized** - see Limitations. No existing project data is affected. --- ## Testing Unit tests in `tests/libslic3r/test_texture_displacement.cpp` - **run and passing** (7 cases, 116 assertions). Coverage: - `decode_height_texture` round-trip - Empty-layer no-op - Full-cube uniform displacement - Boundary-vertex pinning on a hand-built fan mesh - Regression: a **second layer over the same area actually contributes** (the bug the bake rewrite fixed) - Table-driven check of all four blend modes - The lowest painted layer ignoring its blend mode `BUILD_TESTS` is `OFF` in the checked-in cache; enable to run: ```bash cmake -S . -B build -DBUILD_TESTS=ON cmake --build build --config Release --target libslic3r_tests -- -m ./build/tests/libslic3r/Release/libslic3r_tests.exe "[TextureDisplacement]" --order rand ``` --- |
||
|
|
059e171954 | Merge branch 'main' into nozzle-variant-cooling | ||
|
|
e493289b62 | Merge branch 'main' into nozzle-variant-cooling | ||
|
|
1e4489eb16 | Merge branch 'main' into feature/texture_displacement | ||
|
|
afaa94b3bf | Merge branch 'main' into u1-hf | ||
|
|
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 |
||
|
|
d87fe1b290 | Merge branch 'main' into feature/pa_per_extruder_variant | ||
|
|
46fb512690 |
enable python unit test (#15593)
* enable python unit test * fix Windows * Require numpy for the plugin tests in CI |
||
|
|
f6514b798a | Merge branch 'main' into u1-hf | ||
|
|
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) |
||
|
|
9f34f37c27 | Merge branch 'main' into feature/slice-sweep-full-placeholder-coverage | ||
|
|
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) |
||
|
|
d48e63b5e3 | Merge branch 'main' into feature/add-multi-variant | ||
|
|
da951ad7f3 |
Load profile includes so synced Bambu Lab presets get their G-code back (#15869)
# Description This brings back the Bambu Lab profile sync with BambuStudio, reverted from main, along with its bed-model offset fix. The synced printers and filaments share their start and end G-code and dual-nozzle settings through template files that Orca did not read, so those printers had no machine G-code. Orca now loads these templates the same way BambuStudio does, so every synced preset comes in complete. `profile_include_dump`, a new developer tool, compares the result with BambuStudio's. Other vendors' profiles are unaffected. Bambu Lab profiles move to version 02.08.00.10, so installs that took the earlier sync update too. <!-- > 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? --> # Screenshots/Recordings/Graphs <!-- > Please attach relevant screenshots to showcase the UI changes. > Please attach images that can help explain the changes. --> ## Tests Unit tests cover how template settings combine with inherited and preset settings, loaded from JSON and from the preset cache. The profile validator passes on every shipped vendor, and every Bambu Lab preset gets the same template values in Orca as in BambuStudio. <!-- > 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) |
||
|
|
c5bbb6e031 | Merge branch 'main' into u1-hf | ||
|
|
61b503ca3a | Merge branch 'main' into u1-hf | ||
|
|
211dd7daaa | Merge branch 'main' into feature/texture_displacement | ||
|
|
c168d0c8db |
Stop estimating a prime tower for a single used filament (#15760)
# Description A plate using one filament no longer reserves or draws a prime tower in the plater just because multiple filament slots are configured. The shared footprint estimate gated "no tower" on the purge volume being zero, but on non-Bambu printers with the shipped defaults that volume comes from the SEMM flush matrix, which reads every configured slot and stays nonzero even when only one filament is used — so the preview showed a tower the print could never contain. The estimate now decides from the filament count alone, with wrapping detection and smooth timelapse staying the only reasons a single-filament plate keeps a tower, matching `Print::has_wipe_tower()`. The gate also moved above the flush-volume scan so the lone-filament path no longer pays for it. No change to slicing output — toolpath generation already omitted the tower for a single used filament; this removes the phantom preview, placement reservation, and validation footprint. # Screenshots/Recordings/Graphs Before the fix: https://github.com/user-attachments/assets/c5b0ea61-127d-408e-bafe-f1f76c58b996 After the fix: https://github.com/user-attachments/assets/ac6632b3-5d44-4013-aca3-73f6cfd1139c ## Tests <!-- > Please describe the tests that you have conducted to verify the changes made in this PR. --> Added a shipped-defaults single-filament case to `tests/libslic3r/test_wipe_tower_estimate.cpp`: it estimates a 5.04 mm-deep tower before the fix and zero depth after. `[WipeTowerEstimate]` and the fff_print `[WipeTower]` suites 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) |
||
|
|
3f001489bf | Speed Dial Enhancements (#15562) | ||
|
|
b4aa57fe2c | Merge branch 'main' into feature/texture_displacement | ||
|
|
1159ca5f7f | Merge branch 'main' into weilun/speed_dial | ||
|
|
56561242a7 | Merge branch 'main' into feature/texture_displacement | ||
|
|
db91d4b630 |
Design tab: sketch-first parametric CAD inside the slicer (#15238)
# Description Adds a sketch-first parametric CAD tab to the slicer: sketch → constrain → solid features → commit to plate. The feature recipe is persisted inside the 3MF, so reopening a project restores an editable model rather than a frozen mesh. Opening this at @SoftFever's request, so the code is easier to read than a fork. **The number worth reading first:** the diff is large, but almost all of it is new files. Existing upstream code is touched in **23 files, +622 / -88 total**. That is the entire negotiable surface. The largest single one is `GLCanvas3D.cpp` at +149/-14 (a pick path for the CAD viewport); everything else is under 60 lines. One thing about the raw diff: the file count includes everything new, and the negotiable surface is the 23 modified files above. Thanks for merging `main` in — the branch is current again, and I have kept building on top of it. The regenerated i18n catalogues (`OrcaSlicer.pot`, `OrcaSlicer_it.po`, `list.txt`) have been kept OUT of this branch deliberately — they were 27,314 added lines of build product standing between you and the code. They regenerate from source with `scripts/run_gettext.sh` whenever you want them refreshed. A Romanian catalogue that had been riding along was pulled out at the same time — a translation has no business being reviewed inside a CAD feature PR. | | | |---|---| | Kernel | OCCT — already linked for STEP import. The dependency delta is one line: `BUILD_MODULE_ModelingAlgorithms=OFF → ON`. Measured cost in [`docs/cad_dependency_weight.md`](https://github.com/tommasobbianchi/Orca-Cad/blob/cad-mainline/docs/CAD/cad_dependency_weight.md) | | Constraint solver | vendored SolveSpace `libslvs` subset, 21 files / ~10k lines under `src/libslic3r/slvs/` | | Build gate | `SLIC3R_CAD` (default ON). With it OFF the tab is not compiled and the deps prefix matches upstream exactly | | Persistence | CAD recipe embedded in both the 3MF and BBS-3MF writers | | User docs | [`docs/design_tab.md`](https://github.com/tommasobbianchi/Orca-Cad/blob/cad-mainline/docs/CAD/design_tab.md) | | Interaction model | object-driven — point at geometry, it offers the verbs that apply: [`docs/cad_ux_guidelines.md`](https://github.com/tommasobbianchi/Orca-Cad/blob/cad-mainline/docs/CAD/cad_ux_guidelines.md) | ### Why it belongs in the slicer Every round trip through an external CAD tool costs an export, a re-import, and the design intent both steps discard. A part changed after slicing should come back to its feature history, not to a mesh. Keeping the model in the slicer preserves that loop — nozzle diameter, build volume and material are known at design time. Longer argument in [`docs/design_tab_upstream_portability.md`](https://github.com/tommasobbianchi/Orca-Cad/blob/cad-mainline/docs/CAD/design_tab_upstream_portability.md). ### Two things I'd rather you hear from me than find **Licensing.** The vendored solver is **GPL-3.0**, not LGPL (`src/libslic3r/slvs/LICENSE`). The combined work is distributable under AGPL-3.0 and the compatibility argument is written out in the portability doc, but this is a project-level decision and I would like it confirmed explicitly rather than assumed. If GPL-3.0 in-tree is not acceptable, the solver is the separable part — the timeline, features and persistence do not depend on it. **One CMake change is larger than it looks.** `CMakeLists.txt` is +41/-56: it replaces a hand-maintained list of OCCT DLLs to copy on Windows with a glob plus an assertion that every linked toolkit actually has a DLL. The explicit list had already drifted from what `libslic3r` links and shipped a portable that died at launch with `error 126`. Happy to split that out into its own PR if you'd prefer it reviewed separately. ### Not verified - No automated GUI test. A green kernel run says nothing about the viewport — synthetic clicks never drift, so the suite and the UI are two separate realities. - Card wiring for 9 of the 16 late-wired tools has never been click-tested. - The click-test defect rate has not converged: one pass found nothing, four further days of work found five more defects. I would not present the quiet pass as evidence of stability. # Screenshots/Recordings/Graphs One part, start to finish: sketch it, feature it, print it — without leaving the slicer.  **1. Sketch, constrained and dimensioned.** A 100 × 90 rounded rectangle drawn straight onto the bed, R20 corners, live dimensions, and the solver's remaining degrees of freedom reported in the panel. The bed is the sketch plane, so the part is sized against the machine it will be printed on from the first line.  **2. The feature tree is the part.** `Sketch1 → Extrude2 → Chamfer3 → Sketch4 → Extrude5 → Hole6 → Thread7`. Every step stays editable and re-evaluates downstream — the modelled thread in the boss is a real helical feature, not a texture.  **3. Committed to the plate.** The same body arrives in Prepare as `Design Body`, 100 × 90 × 78 mm, 581,634 mm³, ready for a Sovol Zero and PETG. No export, no re-import, no lost design intent.  **4. Sliced.** The thread comes out as real helical toolpaths, and the estimate is 3h26m / 134.54 g. This is the whole argument for the feature in one frame: the geometry that was parametric two screens ago is now G-code, and it is still parametric if you go back. ## Tests 215 `TEST_CASE` blocks across 6 new test files, plus 2 `SCENARIO`s added to `tests/libslic3r/test_3mf.cpp` covering the CAD recipe's round trip through both 3MF writers. `scripts/kernel-test.sh` is the headless contract: it builds only `libslic3r_tests`, needs no display, and exit 0 means the CAD suite passed. Happy to slice this differently — kernel + solver first, GUI second — if that reviews better for you. |
||
|
|
f1f68ffc3f | Merge branch 'main' into cad-mainline | ||
|
|
f520e9221f |
Repair shipped default materials and obsolete settings, and validate them (#15741)
* add orca profile skill * add default material check Improve validation for default materials and filament profiles * Fix default materials and obsolete keys * clarifying orca-profiles skill |
||
|
|
ade9e77b6b |
Run every profile maintenance job from one tool (#15726)
* Run every profile maintenance job from one tool orca_id_tool.py becomes orca_profile_tool.py, and orca_extra_profile_check.py and orca_filament_lib.py fold into it as subcommands: check, generate-id, fix, trim, update-index and update-snapshot. The three scripts already overlapped -- the checker imported half of its rules from the id tool, which in turn kept a copy-pasted set of output helpers to avoid the resulting import cycle -- while disagreeing on how a vendor is enumerated, how a JSON file is read and what the exit code means. One file settles all three. check, normalize, trim and update-index reproduce their predecessors exactly; normalize and update-index were diffed byte-for-byte against the old scripts over a copy of the whole tree. Deliberate changes: the compatible-printers check no longer switches itself off when --check-materials is passed, an error exits 1 rather than -1, update-index honours --profile-type and reports a profile it cannot place instead of dropping it from the index, fix and update-index gained --dry-run, trim keeps an unindexed file some surviving profile still inherits from, and vendors are enumerated as directories with an index -- which is why blacklist.json, a data file that an unscoped index rebuild once wrote four empty list sections into, loses them here and will not collect them again. The dead rename_filament_system() helper is gone. The suite under scripts/tests now covers the maintenance commands too, and CI runs it; nothing there ran in CI before. No shipped profile data changes apart from those four keys. * update vendor index files with "python3 ./scripts/orca_profile_tool.py update-index" and "python3 ./scripts/orca_profile_tool.py normalize" |
||
|
|
3788a19730 |
Publish 3MF Workflow (#15251)
# Description This PR introduces a publish workflow for sharing selected slicer settings in .3mf projects without exposing or overriding the recipient's complete printer, filament, or process profiles. A published file specifies "requirements" for a model — printer, process, and per-slot filament requirements — while importing it preserves the rest of the recipient's workflow. Publish dialog (File → Publish, Ctrl+Shift+E) - Tabbed dialog (Printer / Filament / Process) with search, Select All / Select Visible, and DPI rescaling. - Per-material pages expose three kinds of content: individually selected filament keys, a Full Publish toggle that embeds the slot's entire filament preset, and required type and color rows for the slot. - Publishing is allowed with no settings selected (the file then carries only identity/requirement data). - Reuses configuration value formatting extracted into a shared ConfigValueFormatter. Export - Published 3MFs carry published, published_keys, and published_material_keys metadata. - A minimal export mode serializes only the selected values, material identity, and plate geometry, omits embedded preset files, and masks full-publish vector options to the author's slot so unrelated slot data never leaks into the file. Loading - Only author-selected settings are applied; the recipient's presets are otherwise preserved and structural/non-publishable keys are protected (skipped keys are reported). - Material settings match by filament ID, type, vendor, and slot. Per-slot type requirements keep a matching receiver material, replace a mismatched slot with the first same-type library filament (with a notification), and fall back to a temporary embedded preset or skipped keys when no match exists. Required colors are applied regardless of the type match. - A published 3MF loads as a new project: its path is not adopted as the project filename (Save prompts instead of overwriting the shared file), the title reverts to "Untitled", and the published metadata is stripped so a later save produces a normal 3MF. - Customized-preset and modified-G-code warnings are suppressed, since the author's presets and G-code are not applied. - Previously published 3MF files continue to load through the existing matching path. # Screenshots/Recordings/Graphs <img width="1405" height="734" alt="publish_dialog" src="https://github.com/user-attachments/assets/96b833c1-2b86-4c09-92b4-a4471a567e62" /> [publish_dialog_settings.webm](https://github.com/user-attachments/assets/acf22dd9-ae9b-4a58-b77d-8c2d9ffbc7a5) ## Tests Added tests covering: - Coverage for export slot masking, metadata round-trip, type-match/replace/fallback semantics, slot growth, and skipped-key reporting. |
||
|
|
0c07ec9c3c | Merge branch 'main' into weilun/speed_dial | ||
|
|
37e1582c4c |
redesign filament_id (#15513)
# Description This PR redesigns `filament_id` across OrcaSlicer's profile library, so that one filament product now carries one consistent id everywhere it ships, instead of a hand-written value that unrelated materials routinely shared. Minting scripts and CI checks come with it so future profiles comply by construction: a new filament takes its id from the tool, and the checks reject a hand-written, duplicated or drifted one before it can merge. Unique, non-duplicated ids are a precondition for AMS-style spool syncing to be dependable — the id is what a printer matches a physical spool against, and while two products share one, the match is a coin toss. This PR lays that groundwork. A follow-up PR will publish an OrcaSlicer materials reference on the wiki, giving every system profile one place to point at. `filament_id` names one filament product, and it is what a device matches a physical spool against: Bambu AMS, Creality CFS, the Qidi box, Klipper and Snapmaker all resolve a tray to a preset by id alone, first hit wins. Those ids were written by hand, and on `main` 99 of them stand for 674 different products — `GFL99` alone covers 132, from Anycubic PLA to Bambu PLA Matte. Every consequence is silent: a spool resolves to whichever preset happens to load first, tray names and support-material flags are read off the wrong material, and the second preset holding a duplicated id disappears from the tray-edit dialog entirely. The id is now a hash of `(filament_vendor, filament_type, filament name)`, so one spool product carries one id in every bundle that ships it, two vendors shipping the same product converge on it without coordinating, and a collision cannot be authored by hand. Every ambiguity across 48 vendors is fixed rather than excused — no grandfather list and no per-vendor carve-out, Bambu's bundle included — and the resulting landscape is frozen in `scripts/filament_id_snapshot.json`, so a change to any filament's identity lands as a reviewable diff to one file. CI now runs the duplicate-subtype validation tree-wide instead of over Bambu only. Letting the id follow the product meant correcting the identities themselves. Generics that shipped under a vendor prefix now have one name and one id everywhere (`Blocks Generic PETG` is `Generic PETG @Blocks`), presets whose `filament_vendor` or `filament_type` contradicted the spool are fixed, and duplicate pairs are collapsed onto the better-configured survivor. Renames carry `renamed_from`, so existing projects and user presets keep resolving. Bambu's printers, its AMS and its cloud know only Bambu's own catalog ids, so those ids leave the profiles entirely. The Bambu bundle mints like every other vendor, and the printer agent swaps in the catalog value only where an id crosses to or from a Bambu printer — outbound MQTT and FTP, the AMS mapping sent with a job, the ids written into a 3mf the printer will read — mapping back on the way in, so status messages, SD-card prints and projects saved by an older Orca or by BambuStudio all still resolve. The correspondence is generated from BambuStudio's own shipped bundle by `scripts/update_bambu_filament_ids.py`; an id with no row is forwarded untouched, a missing or malformed map degrades to no translation rather than taking the app down, and an agent whose printers already speak Orca's ids translates nothing. Two device-side bugs this work surfaced are fixed here as well. The Orca Filament Library was missing from the AMS material and calibration dialogs, which treated a filament with no `compatible_printers` as compatible with nothing while the rest of the app treats it as compatible with everything; and Creality CFS sync on a K2-family stock 0.4 nozzle picked the wrong preset, an imprecise matcher that duplicate ids had been masking. `docs/HLSD/filament_id.md` is the authoring rule for all of this. `scripts/orca_id_tool.py` mints both `filament_id` and `setting_id`, replacing `assign_vendor_setting_ids.py`, and the local `check_profile` scripts gained per-vendor scoping so one vendor can be checked without a tree-wide run. `scripts/tests/` covers the tooling; `tests/slic3rutils/` covers the boundary translation and the CFS matcher. Ids change for most products and nothing forwards the old value, so a tray or a calibration record still holding one falls back to matching by filament type until the filament is selected once. Beyond the profile fixes above no print settings change, except that a few presets stop claiming printers a dedicated variant already covers. # 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. --> `scripts/check_profile.sh`, the local twin of the "Check profiles" CI job, with `scripts/check_profile.bat` as its Windows entry point, passes on this branch: the extra JSON check reports no errors and no warnings, system validation and the now tree-wide filament-subtype check load all 66 vendors cleanly, all 1013 printer presets slice, and custom-preset validation passes against every fixture archive from v1.9.0 to v2.4.2. The id tooling has 176 unit tests (`python -m unittest discover -s scripts/tests`). The C++ suites pass too — 332 in `tests/libslic3r` and 126 in `tests/slic3rutils`, the latter including the boundary-translation and Creality CFS matching cases added here. <!-- > 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) |
||
|
|
e523acc164 |
Add script to run full profile checks locally (#15496)
* Run the CI profile checks locally |
||
|
|
7c063b2933 | Merge branch 'main' into publish_3mf | ||
|
|
56a452875e |
Port FFmpeg based camera view from BambuStudio (#15234)
* Add ffmepg dep
* NEW: reimpl wxMediaCtrl from ffmpeg
Jira: none
Change-Id: I46a47118a7649b2a50fcce8911e2888342ef25de
(cherry picked from commit d6c7f08769c8cfdbbf0e80ad280c9b3408a3c27d)
(cherry picked from commit 94d91be60bfe9bbbcdd21f85b46abc3faf126f17)
* FIX: reset bambu lib after restart network plugin
Change-Id: I4a3a4b7420745835ca3fa00c6edebe9d8d98cbf6
Jira: STUDIO-7571
(cherry picked from commit 28d9c6743fae80bfd40e4ee391e30d62cb16d4ab)
* FIX: ffmpeg decoder memory leak
Change-Id: I997572b5730618a969959f9b24c405d80fa9f83c
Jira: STUDIO-7597
(cherry picked from commit 342cea29bd9593fa89cbb33caff58055b46ebeec)
* FIX: install ffmpeg symbolic sos
Change-Id: Ia4a45182cefcf62a7a4b4a5c89c92251609c5a68
Jira: none
(cherry picked from commit b7f8fa1efdbe0ac2cc896ca24f063f5894fe9f90)
* FIX: ffmpeg swscale & frame_size
Change-Id: I9f4cb8c739b726f7e5cdbe0df7ed06b2eb2154d5
Jira: STUDIO-7624
(cherry picked from commit 5a2c75d835fb437667b590a803eef148baa30875)
* FIX: wxMediaCtrl3 idle image & center pos
Change-Id: Ib9652573e31bfd6229f174c0a1388942d9d98822
Jira: STUDIO-7633
(cherry picked from commit d51247c46e26460b151de79c598d81151280e79c)
* FIX: AVVideoDecoder sws_ctx_ == nullptr on zero size
Change-Id: I9698354bb1f341e276ec9780d4ef4fcd9f8a1028
Jira: STUDIO-7706
(cherry picked from commit ff622e25026a8471c39eb308cf5b115c4a9d84aa)
* fix:cannot open shared object file on linux
Change-Id: Ica66500506cfe8932eac3ae0a58fb7ff30d1da9b
jira:none
(cherry picked from commit febd1aeb4d453bc96571fa5e5727e9e10046cb80)
(cherry picked from commit 5ad579f929154779abd84b01438fd235c647dbf5)
* NEW:add ffmepg build Cmake
buildLinuxImage add ffmpeg so file
jira:nojira
Change-Id: I3e1be53aa58a179b8d9ae048ed7538de3ae8d111
(cherry picked from commit 2d70a1bcb6a5ba601525b08a38e7610f018fe106)
* FIX: ffmpeg cmake install error
jira:nojira
Change-Id: I74cc0f7c86b5364e55cad2af2bd9a82306ee6864
(cherry picked from commit 805df79e3bb044dac29ec1c06736751ccf3675f9)
* FIX: decode video to wxImage on Linux
Change-Id: I5e332a1b0622b3dfc70ac5c4c3bfa62b3411ebdc
Jira: none
(cherry picked from commit c787ba921a31f259e8eb23fd59f178e96279caf9)
* FIX: wxMediaCtrl3 enter Stopped state soon
Change-Id: I120e9d4b9f85599a184650d1d95fe2bec42af171
Jira: STUDIO-8280
(cherry picked from commit 7648d96305d510b9e97f22124961de5115cde830)
* FIX: reset decode buffer zero when scale width changed
Change-Id: Iaa2f99111dd5f7228b7b25e1be0a8cbdbfe982a6
Jira: STUDIO-8422
(cherry picked from commit 659ebc7d07a8f6045ba5443141b44277d7257cec)
* slic3r: Fix missing declarations in wxMediaCtrl3.h
src/slic3r/GUI/wxMediaCtrl3.h:80:10: error: ‘condition_variable’ in namespace ‘std’ does not name a type
80 | std::condition_variable m_cond;
| ^~~~~~~~~~~~~~~~~~
src/slic3r/GUI/wxMediaCtrl3.h:27:1: note: ‘std::condition_variable’ is defined in header ‘<condition_variable>’; did you forget to ‘#include <condition_variable>’?
26 | #include "Printer/BambuTunnel.h"
+++ |+#include <condition_variable>
27 |
src/slic3r/GUI/wxMediaCtrl3.h:81:10: error: ‘thread’ in namespace ‘std’ does not name a type
81 | std::thread m_thread;
| ^~~~~~
src/slic3r/GUI/wxMediaCtrl3.h:27:1: note: ‘std::thread’ is defined in header ‘<thread>’; did you forget to ‘#include <thread>’?
26 | #include "Printer/BambuTunnel.h"
+++ |+#include <thread>
27 |
In file included from src/slic3r/GUI/MediaPlayCtrl.h:17,
from src/slic3r/GUI/MediaPlayCtrl.cpp:1:
src/slic3r/GUI/wxMediaCtrl3.h:77:13: error: field ‘m_frame’ has incomplete type ‘wxImage’
77 | wxImage m_frame;
| ^~~~~~~
(cherry picked from commit 727a73333bd67acf5ff2b1c51ff284c2bacdb413)
* slic3r: Fix missing includes in AVVideoDecoder
In file included from src/slic3r/GUI/AVVideoDecoder.cpp:1:
src/slic3r/GUI/AVVideoDecoder.hpp:28:20: error: ‘wxImage’ has not been declared
28 | bool toWxImage(wxImage &image, wxSize const &size);
| ^~~~~~~
src/slic3r/GUI/AVVideoDecoder.hpp:28:36: error: ‘wxSize’ has not been declared
28 | bool toWxImage(wxImage &image, wxSize const &size);
| ^~~~~~
src/slic3r/GUI/AVVideoDecoder.hpp:38:10: error: ‘vector’ in namespace ‘std’ does not name a template type
38 | std::vector<uint8_t> bits_;
| ^~~~~~
src/slic3r/GUI/AVVideoDecoder.hpp:9:1: note: ‘std::vector’ is defined in header ‘<vector>’; did you forget to ‘#include <vector>’?
8 | #include <libswscale/swscale.h>
+++ |+#include <vector>
9 | }
src/slic3r/GUI/AVVideoDecoder.cpp:145:89: error: invalid use of incomplete type ‘class wxBitmap’
145 | bitmap = wxBitmap((char const *) bits_.data(), size.GetWidth(), size.GetHeight(), 32);
| ^
(cherry picked from commit 781ce14e061366da64fdc2d0d592fa35ee57e67e)
* slic3r: Fix missing includes in wxMediaCtrl2
src/slic3r/GUI/wxMediaCtrl2.cpp: In lambda function:
src/slic3r/GUI/wxMediaCtrl2.cpp:170:13: error: ‘wxMessageBox’ was not declared in this scope; did you mean ‘wxInfoMessageBox’?
170 | wxMessageBox(_L("Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Bambu Studio?)"), _L("Error"), wxOK);
| ^~~~~~~~~~~~
| wxInfoMessageBox
src/slic3r/GUI/wxMediaCtrl2.cpp: In member function ‘void wxMediaCtrl2::Load(wxURI)’:
src/slic3r/GUI/wxMediaCtrl2.cpp:179:5: error: ‘wxLog’ has not been declared
179 | wxLog::EnableLogging(false);
| ^~~~~
(cherry picked from commit 73908d38d8b1f7c8dcae92d55711bc08cbfff23c)
* slic3r: Fix missing wxPaintDC declaration
src/slic3r/GUI/wxMediaCtrl3.cpp: In member function ‘void wxMediaCtrl3::paintEvent(wxPaintEvent&)’:
src/slic3r/GUI/wxMediaCtrl3.cpp:121:5: error: ‘wxPaintDC’ was not declared in this scope; did you mean ‘wxPoint’?
121 | wxPaintDC dc(this);
| ^~~~~~~~~
| wxPoint
(cherry picked from commit 9ab5009235d212699f91e01d7f930f92849ed1e3)
* slic3r: Fix missing BOOST_LOG_TRIVIAL declaration
src/slic3r/GUI/wxMediaCtrl3.cpp:181:23: error: ‘info’ was not declared in this scope
181 | BOOST_LOG_TRIVIAL(info) << msg.ToUTF8().data();
| ^~~~
src/slic3r/GUI/wxMediaCtrl3.cpp:181:5: error: ‘BOOST_LOG_TRIVIAL’ was not declared in this scope
181 | BOOST_LOG_TRIVIAL(info) << msg.ToUTF8().data();
| ^~~~~~~~~~~~~~~~~
(cherry picked from commit c5c41e20ca2fc7f3b53a4c769961f73df6992008)
* FIX: wxMediaCtrl3 zero size crash
Change-Id: I16a3f7b3afe142bb957a1740b8e8c9820c92b349
Jira: STUDIO-8522
(cherry picked from commit 8cdaea1162ccbcc0bd03ecd99346f3b9cf52cf64)
* FIX: TabCtrl button margin
Change-Id: If8b05a4ef9efb8b57989ee1de6543631e5a3cf90
Jira: STUDIO-8265
(cherry picked from commit 1c5e65707109ad0582b6442cf8e515344f799c27)
* ENH: wxMediaCtrl3 display video frame at pts
Change-Id: I8847236d2307101e5f2befc6477cd20b3691841c
Jira: none
(cherry picked from commit 05328da4612c11d50f6fd90e872b97f5f8f46b1d)
* Fix: fix memory leak caused by ffmpeg decoding
Change-Id: I162ad4ea8d4601c1ffe17a65f292566c9dea6f0b
jira: no-jira
(cherry picked from commit eb20d03186c86b7398b97e3bae0a3c7a7b81c58c)
* ENH: update some missing codes
jira: no-jira
Change-Id: Icb2da53911430ac144b0fb601637a7ad31e7e8db
(cherry picked from commit 13b4213f8a24c76c16e49daf905fa29c0f646a5a)
* Fix build
* Update idle image
* Attempt to fix Windows CI build
* FIX: GTK video window resize ran in a free function without member access
wxMediaCtrl_OnSize referenced wxMediaCtrl2's private m_gtk_video_window,
which does not compile on Linux/GTK. Move the resizing into
wxMediaCtrl2::DoSetSize where the member is in scope.
* Install required tools for Linux
* Install required tools for macOS
* Add ffmpeg to flatpak
* Fix Linux build
* Try fix appimage build
* Fix Linux AppImage bundling of deps-built shared libraries
The AppImage dependency closure resolves each bundled ELF's DT_NEEDED
entries with plain ldd, which cannot resolve the deps-built FFmpeg stack
(libavcodec/libavutil/libswscale) once it is copied into the bundle:
those libs are not installed in any standard loader path and carry no
RUNPATH of their own, so ldd reports the siblings as missing and the
build aborts. Extend the loader path with the bundle directory plus the
source directories of already-bundled files (mirroring
scripts/check_appimage_libs.sh), and key the dedup set on the bundled
file path instead of the source path so dependencies resolved from the
bundle directory are not copied onto themselves.
Co-Authored-By: Claude <noreply@anthropic.com>
* Attempt to fix Linux unit test
* Fix Linux unit tests loading deps-built FFmpeg libraries
The test executables that link libslic3r_gui (which links PkgConfig::LIBAV)
have a load-time dependency on the deps-built FFmpeg shared libraries. The CI
unit-test runner only receives the tests artifact, so those libraries were
unresolvable there (Ubuntu 24.04 ships libavcodec.so.60, not .61). Copy the
libraries next to each affected test executable and give it an $ORIGIN rpath,
mirroring the Windows branch that copies DLLs next to every test executable.
orcaslicer_copy_sos now places the copies in the per-config output directory
for multi-config generators, like orcaslicer_copy_dlls does.
Co-Authored-By: Claude <noreply@anthropic.com>
* Add design doc for macOS FFmpeg player
Co-Authored-By: Claude <noreply@anthropic.com>
* Add implementation plan for macOS FFmpeg player
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: use FFmpeg media player on macOS with static FFmpeg
* build: build static-only FFmpeg for macOS deps
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: remove old BambuPlayer-based media player from macOS
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: add static FFmpeg NOTFOUND guard; drop dead wxMediaCtrl2.h include
* build: drop redundant --enable-shared in FFmpeg deps configure
The literal --enable-shared was always overridden by ${_link_cmd}
(--enable-static --disable-shared on Apple, --enable-shared elsewhere)
and FFmpeg configure processes these flags in order, last one wins.
Remove it and the stale comment documenting the workaround.
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: remove dead wxMediaCtrl2 player
wxMediaCtrl2 was never instantiated on any platform (USE_WX_MEDIA_CTRL_2
is 0 everywhere); wxMediaCtrl3 replaced it. Delete wxMediaCtrl2.cpp/h,
drop them from the Win/Linux source list and the gettext list.txt, and
collapse the preprocessor-dead #if USE_WX_MEDIA_CTRL_2 gate in
MediaPlayCtrl.h.
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: remove dead GStreamer bambusrc plugin and its build dep
gstbambusrc was the GStreamer source element for the old wxMediaCtrl2
Wayland player, its only consumer (deleted in the previous commit).
The new FFmpeg player handles bambu:/// URIs through the Bambu C API
instead. Drop the plugin and the gstreamer-1.0 / gstreamer-base-1.0
REQUIRED pkg-config dependencies that existed solely for it.
Co-Authored-By: Claude <noreply@anthropic.com>
* build: move FFmpeg media player sources to the common GUI list
wxMediaCtrl3 and AVVideoDecoder are platform-neutral C++ compiled on
all three platforms, so list them once in the common SLIC3R_GUI_SOURCES
instead of duplicating them in the APPLE and non-APPLE branches. The
else() branch is now empty and drops out entirely.
Co-Authored-By: Claude <noreply@anthropic.com>
* deps: disable FFmpeg VideoToolbox/AudioToolbox HW-accel on macOS
The static libavcodec.a/avutil.a compiled the auto-detected
videotoolbox/audiotoolbox objects, which reference VideoToolbox
framework symbols (_VTDecompressionSession*). The app link line
happened to satisfy them transitively, but the orca_stubgen module
link (CI-only) failed with undefined symbols. The player decodes in
software (swscale), so disable both HW-accel paths to keep the
static libs self-contained.
Co-Authored-By: Claude <noreply@anthropic.com>
* Copy the decoded frame instead of aliasing the decoder's buffer
wxImage with static_data set stores the pointer and never copies it, so the
frame handed to wxMediaCtrl3 aliased AVVideoDecoder::bits_. That buffer is
rewritten by the next sws_scale with the mutex released, reallocated by
bits_.resize() when the window grows, and freed outright when the decoder
leaves PlayThread's loop body at end of stream, all while the GUI thread may
be painting from it.
Windows is unaffected either way, since toWxBitmap already copies the bits
into GDI.
---------
Co-authored-by: chunmao.guo <chunmao.guo@bambulab.com>
Co-authored-by: BBL\chuan.he <chuan.he@bambulab.com>
Co-authored-by: MackBambu <yongfang.bian@bambulab.com>
Co-authored-by: Bastien Nocera <hadess@hadess.net>
Co-authored-by: chao.zhang <chao.zhang@bambulab.com>
Co-authored-by: lane.wei <lane.wei@bambulab.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: SoftFever <103989404+SoftFever@users.noreply.github.com>
Co-authored-by: SoftFever <softfeverever@gmail.com>
|
||
|
|
dfb102f68d | Merge branch 'main' into dev/ffmpeg-player | ||
|
|
149ae6c7fe | Merge branch 'main' into cad-mainline | ||
|
|
0aeb6df122 | Merge branch 'main' into cad-mainline | ||
|
|
fbcf1fe08e | trigger build for changes in build script | ||
|
|
d24aef36ae | set osx deployment target for openssl | ||
|
|
e001b66192 | Fixed a regression that bed type was not remembered and switched when switching bed types | ||
|
|
132e531fb8 |
Misc profiles fixes
fixed #2636 |
||
|
|
efaf2f8e34 | Add orca bot | ||
|
|
36ffb18059 | make folder name more consistent | ||
|
|
61e05f9bd1 | Fixed #2562: disable extra perimeters over overhangs for spiral vase |