Follows the first pass on the placement gizmo.
Handles and hit radii are twice the size, and the minimum frame with them,
so the corner zones cannot bury the move area on a small tile.
Each edge carries a bar that sets one tile extent, so width and height can
be set on the model rather than only in the panel. The four axis arrows
stay, further out on the same rays, kept apart from the bars by distance.
Dragging a width or height handle back through the tile's middle mirrors
the texture on that axis instead of sticking at the minimum extent. The
new mirror_u and mirror_v ride as a sign on the same division as the tile
extents, in apply_uv_transform and in all four shaders, and the shaded
shaders' normal gradient carries the sign too.
The frame was centred on uv 0, which is a corner of the image, so it
straddled the four tiles meeting there and rotation pivoted on that
corner. It is now centred on uv (0.5, 0.5): the frame bounds one whole
tile and rotating or scaling turns and resizes the image about its middle.
A scale drag read the extents straight off the cursor, so grabbing a
handle anywhere inside its hit radius jumped the tile by that much. The
offset of the grab from the handle is now subtracted.
The square-tile lock is an icon on the Tile size row instead of a text
link, reusing lock_closed.svg and lock_open.svg.
The on-canvas control for a texture layer's placement was a translucent
orange quad with two hairline GL arrows. It moved the texture and nothing
else, had no hover state, took no notice of the theme, and sized itself
from the volume's bounding box, which left it tiny on small parts and
huge on large ones. Rotation and tile size were panel-only numbers.
The gizmo is now one tile of the texture lying in the paint patch's
tangent plane, so it draws the three values it edits: where it sits is
the offset, how it is turned is the rotation, how big it is is the tile
extents. It carries four chevron arms for an axis-constrained move (the
silhouette of the panel's own Adjust placement icon), a six-dot move grip
taken from the drag icon, a corner grip on each corner for the extents,
and a ring on a short stem for the rotation. Colours come from
ImGuiWrapper's COL_ORCA and the icon grey rather than raw orange and
yellow.
It is drawn through ImGui's foreground draw list instead of the flat
shader, which is what allows antialiased sub-pixel strokes, rounded
joins, a contrast halo under every stroke and a numeric readout by the
cursor. That halo matters because a volume stays the same neutral grey
whatever the theme, so the accent alone cannot carry contrast; the halo
strength and the handle fill do. Handle sizes and hit radii are in screen
pixels, so the control is equally usable at any zoom or model size, and a
tile that projects below 44px is drawn at that floor and dashed to say it
is not to scale. Picking is a real point-in-quad test rather than a
circle through the corners, so a move can no longer start from empty
space beside the tile.
Rotating or resizing changes where a given offset places the tile, so
every drag recomputes the offset from the centre it means to keep. That
is what makes rotate and scale act in place instead of swinging the tile
around the anchor, and it leaves one place that writes offset.
Tile size gains a second extent. tiling_scale_v holds the v extent in mm
and anything <= 0 means "same as u", which is both the default and what
every layer written before this meant, so existing layers and older undo
snapshots still read back as the square tiles they were. The new
layer_tile_mm() states that fallback once and every consumer goes through
it: the bake, both preview shaders, the UV pane and the gizmo. The panel
shows one slider until the lock is opened, and the lock state is the data
rather than a separate flag that could fall out of step with it.
The extents now divide after the rotation in apply_uv_transform() and in
all four shaders. Dividing two different extents before it would shear
the tile rather than rotate it; with a square tile both orders are
algebraically identical, so no existing layer changes. The inverse in
UVEditorCanvas::uv_delta_to_unwrap() and the island matrix in
uv_editor_island_transforms() follow the same reordering, and the texel
size used for refinement and step cutting now takes the finer extent.
The green highlight and tint no longer cover a colour preview, and return while a stroke is
painted. The Fast view also keeps the other parts of a multi-part object.
Make the connected-net layout affordable on a dense patch
Laying a patch out as a connected net cost ~175 ms on a 42k-triangle patch,
against ~21 ms for the unwrap it works from, and the gizmo asks for it on every
preview, overlay and bake. Measured on a real project the grid behind it ran
~19 million triangle-pair tests per net, nearly all of them misses: a cell
holds every triangle whose box touches it, and a candidate really meets a
couple of them.
Keep a bounding box with each stored triangle and answer those misses with four
comparisons instead of a full intersection. The net drops to ~53 ms with
identical output - the seam metrics on the test project did not move by one.
Two further attempts were measured and dropped, and are recorded in the comment
so they are not tried again: a free-space pre-check per chart came out slower,
because a folded chart lands against the net by construction and the cells
under it are occupied anyway, and splitting the boxes into their own array for
locality lost more to growing two vectors per bucket than it gained.
Also pick a pair's fold line from the longest boundary they share rather than
whichever edge came first, and grow the net strongest-adjacency-first rather
than breadth-first by area. Only the fold a chart is reached by comes out
matching, so a chart claimed across a short boundary leaves the long one it
shared with its true neighbour torn.
texture_unwrap_dump reports an unwrap from a saved project - charts, their
topology, folded triangles, where the texture is discontinuous and how long
those seams are. All of the above was found with it, and it is what keeps a
claim about this code honest; reading the 3D view and guessing had produced
three wrong diagnoses in a row.
* Remove Unused Project Includes and Forward-Declare Where a Type Is Only Referenced
Generated with include-what-you-use and applied conservatively. Only OrcaSlicer's own headers, the ones under src/ and tests/, are removed or forward-declared; standard-library and third-party includes are left alone. An include is removed only when both the Release and the Debug configuration leave it unused, never from inside a conditional block, and never from a file with platform-specific blocks, which only gain includes. Files whose only use of a header sits behind a feature or debug macro (libvgcode's OpenGL ES and marker code, the ARACHNE/TESTS_EXPORT_SVGS debug output) keep their includes.
clonable_ptr.hpp gains #pragma once; it had no include guard and was only safe while Config.hpp was its sole includer.
* Remove Unused Project Includes From Files With Platform-Specific Code
A Linux include-what-you-use run cannot see the code inside _WIN32, __APPLE__ or __linux__ blocks, so its verdict is only taken where nothing the removed header declares, directly or through what it includes, is named inside those blocks. Removals also have to hold in both the Release and Debug configuration and never touch a line inside a conditional block.
* Restore the libslic3r Precompiled Header and Direct Includes Lost in the Platform Pass
The platform-file pass treated pchheader.hpp as an ordinary header and
emptied it, and left GUI_Preview.hpp and 14 other files relying on
headers they no longer reached directly.
* Restore MainFrame.hpp in ParamsDialog.cpp for the Windows-Only Reparent Call
* Include Headers That Files Reached Through Ones the Cleanup Removed
* Drop Includes Duplicated by the Cleanup or by Main's Own Additions
* Leave PreciseSeam.cpp as Main Has It After the Precise Seam Rework
* Add Missing Includes Across src/libslic3r
Every libslic3r source and header now directly includes the headers declaring what it uses, rather than relying on the precompiled header or transitive includes. Generated with clang-tidy misc-include-cleaner, with libslic3r headers spelled libslic3r/... so they resolve outside the library's private include paths. MultiMaterialSegmentation.hpp, Support/SupportParameters.hpp and Format/STEP.hpp are made self-contained by hand.
* Make the libslic3r Headers Compile on Their Own
Each now includes, or forward-declares, what it uses instead of relying on what its includers happened to include first. Left out: I18N.hpp, which errors on purpose when included from GUI code, and VoxelizeCSGMesh.hpp and SLA/bicubic.h, which nothing includes and which no longer compile at all.
* Add the Includes Missing From the Hand-Fixed libslic3r Headers
clang-tidy would not edit these headers while they failed to compile on their own, so the first pass skipped them. With the headers now self-contained, a second pass adds the rest.
* Keep Windows Setup Ahead of the Added libslic3r Includes
Print.cpp and Thread.cpp open with a _WIN32 block that has to come first; without the precompiled header, Print.cpp otherwise reaches windows.h through OCCT with NONLS defined and boost/regex fails. OpenVDBUtils.cpp and SLA/SupportTreeBuilder.cpp had includes inside #ifndef NOMINMAX, which libslic3r defines on Windows, so those were skipped there. .clang-tidy also ignores the MSVC STL and UCRT internals, Boost.Multiprecision's fwd.hpp and CPython's Windows include directory.
* Re-Add libslic3r Includes After the Clipper2 2.0.1 Migration
Rebasing onto main took main's version of the files the Clipper2 migration rewrote, so their added includes are restored here, along with includes for main's new code. Clipper2's individual headers are now ignored by clang-tidy: they only build the Z variant through clipper2_z.hpp, which defines USINGZ first, so including clipper.core.h and the like directly broke ClipperZUtils.cpp.
Refinement now tapers off away from the paint, and the unpainted surface is kept out of
simplification, so what one bake leaves unpainted is still the model's own triangles when a later
bake paints there. A second bake used to refine the slivers and long triangles the first one left
around its stroke, and came out many times denser, with walls off the texture's lines.
Meeting the triangle budget by merging flat faces alone no longer raises the warning, and the
warning now quotes the budget instead of the triangle count left after the flat faces were merged.
texture_displacement_patch_frame picks the world axis least aligned with
the patch's average normal. With no patch there is no normal either, and
the axis came out of the +Z fallback for it - so it was +X, while its
test asked for the upright frame the fallback is meant to give. An empty
patch now answers +Z outright.
Nothing removed the even mesh over a texture's flat parts unless the
budget was lowered until simplification had to run. Collapses stay under
a thirty-second of the resolution: on the test map 387584 -> 369876
triangles, with the print unchanged (0.02% of the extrusion).
An earlier attempt was reverted for a 21% heavier result. That was the
colour despeckle switching itself off, not the collapsing: it keyed off
the face parent map, which any collapse empties.
Relief preserved from an earlier bake is counted on top of the budget
instead of eating into it: baking a second area went from ~214 k
triangles to the ~1000 k it was given.
When the resolution needs more triangles than the budget allows, it is
said before the bake under Resolution and again afterwards.
- Bake: each layer is sampled only on its own painted area; analytic
projections used to stack every layer over every painted region, so the
top layer's texture showed on all of them (colour sampler too)
- Auto resolution follows the texture's texel size and sharpness again
- Unwrap: charts cut by each face's own normal (a cube gives 6 islands, not
12 triangles); non-disk charts (tubes, closed shells) are split until they
flatten; connected nets test real triangle overlap, grow from the largest
chart and are packed side by side
- UV edits are stored per unwrapped copy, so dragging a seam vertex no
longer moves its copies in neighbouring islands
- UV pane: tool strip with unwrap settings moved in from the panel, sharp
HiDPI icons, clearer island/edge/selection drawing with hover, texture
picker from the thumbnail, texture no longer lost on reopen (GL state
from the 3D view, background upload retries)
- Panel: whole-model select/erase as icons in the tools row; inactive
layers' paint shown muted; colour textures shown in colour in the picker
- Built-in displacement texture library
- Tests for unwrap segmentation, connected nets, UV edits and per-layer
sampling
Colour height maps now displace the same way up as grayscale ones. A
truncated or corrupt PNG in the texture folder or a project file now
loads as an empty texture instead of aborting the app, and a 16-bit
colour PNG is converted on load rather than displacing as noise.