Selecting a non-path property (Position) or a stale selection disabled Closed, unlike
RotoBezier and the other Mask and Shape Path commands, which fall back to every mask of
the selected layers. A selected mask property (Feather, Opacity, Expansion) now selects
its mask. A selected locked mask still counts as a match, so it never falls back to its
unlocked siblings.
A layer Move, path-vertex drag or Pan Behind drag held to one axis with
Shift snapped with the full 2D rule, so a point target (another layer's
corner or midpoint, a path vertex, the comp centre) gave the snap both of
its coordinates and pulled the dragged feature off the axis.
The new engine function viewer::snap_along snaps only the free coordinate:
a point acts as a line through it across the drag, reaching it within the
tolerance on each axis; lines along the drag are left out. A point hit
reports the point and the short line from it to where the feature landed,
so the viewer draws the alignment. The viewer's SnapQuery carries the axis
one_axis picks (drag_axis); Move, Vertices and Pan Behind pass it. snap()
itself is unchanged.
Fixes#3229
Moving a circle so its edge point met another circle's point snapped at
200 % but missed at 100 %. A layer's point lies on its own edge line and
centre row, so a vertical and a horizontal line through it tie with it, and
the point only won that tie by 1e-9. Any other line a little nearer on one
axis (the comp's centre row, a guide) then made a pair nearer than the
point, taking x from the edge and y from that line and leaving the moved
circle off the point. At 100 % the tolerance (8 screen points) covers more
comp pixels and reaches those lines; zoomed in they were out of reach.
Before #2855 a single nearer line was enough, which is how it was reported
on 0.18.0.
snap() now lets a line pair with a line through the point beat that point
only when the pair is nearer by POINT_BIAS of the tolerance (2 of the 8
screen points at any zoom), in place of the exact tie. A pair whose lines
both miss the point gets no margin, so a guide crossing right beside a
layer's point stays reachable; two clearly nearer lines still win, as
#2855 intended.
Tests: two Ellipse-tool circles, parametric and converted to Bezier paths,
at 1x, 2x and 4x on device scales 1, 1.25 and 1.5, dropped just off the
point and nearer the comp's centre row than the circle's own row, with and
without snapping to a guide between them: the moved point lands exactly on
the other's, a single point hit (a path point for the Bezier circles). The
margin: a pair through the point only a little nearer leaves the point, a
clearly nearer one wins; a guide crossing 1 px beside a point is reached
next to the crossing.
Moving a layer snaps the feature nearest where it was grabbed, as before
(the snap handle, as in After Effects): grab the circle near its edge point
to snap that point; grabbed in the middle, its centre snaps.
Fixes#2681
* Viewer exposure on the full float range of 32 bpc frames (#2797)
32 bpc viewer frames on the desktop are rendered without the HDR step (skip_hdr_step,
#2916) and kept as half floats in the RAM preview. A display pass on egui-wgpu's device
turns each frame into one RGBA8 texture with mips per viewer, in this order: decode,
exposure in linear light, Compand / Tone Map, encode, display colour, Show Channel,
rounding. Before, exposure was an 8-bit lookup applied after tone mapping, clamping and
the display conversion, so -2 EV could not bring values above 1.0 back.
- engine: viewer::DisplayPass describes the pass as data; its pixel() is the CPU
fallback (no device) and the shader's reference. It replaces exposure_lut /
display_transform. FrameEncoding records a frame's curve and the HDR step it still
needs. 32 bpc snapshots are taken without the HDR step; snapshot_rgba8 applies it.
- ui-egui: FrameImage::CpuF16 (half crate, F16C at run time), byte accounting at 8 bytes
a pixel in the cache and the prefetch estimates; display_gpu.rs + display_gpu.wgsl;
main viewer, snapshot and passive viewers draw through the pass; the 8-bit image other
panels read is made on demand with the HDR step; the Info panel shows float values.
- Half-float frames are not written to the disk cache yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Viewer display pass: f16 disk cache entries, window-device gating, review fixes
- Disk cache: half-float frame entries (format byte in the entry header, byte planes +
LZ4); 8-bit entries keep format 0 and stay valid. 32 bpc viewer frames are written and
read again, and the timeline's disk bar sees them. A damaged half-float entry is
deleted.
- The display pass runs on the window's egui-wgpu device, with or without the GPU
compositor (still building, failed, GL fallback). Its pipelines are made inside error
scopes; a backend that rejects them gets the CPU pass instead of a blank viewer.
- A new LUT of the same size (another ICC profile, Preserve RGB, another display) runs
the pass again.
- f32 to f16: one pass per L1-sized block, the NaN / infinity fix-up on the bits, no
fill of the buffer (4K: 4.7 ms, as the 8-bit conversion).
- Mips of odd-sized levels include the last column / row; the snapshot's half floats
and texture go with the snapshot; no placeholder texture ids; u64 size checks.
- Tests: LUT profiles and negative values against the shader, Bake reruns, the passive
viewer's colour, f16 disk round trips; exact comparisons allow 1 LSB on software
rasterizers. Docs: the display pass and the f16 disk entries in architecture.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Viewer f16 disk-cache test: temp dir removed on failure too, wait for the queued disk write
Review points: the test's directory was only removed by its last statement
(now tempfile::TempDir), and the frame is released before its disk write is
queued, so flush() could return early (now waits for the entry).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Viewer: oversized half-float frames use the CPU display pass, so exposure/HDR come before the averaging down
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Viewer: fmt and a debug assert for the half-float upload path
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Disk cache: persist_missing also writes half-float frames
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* Passive viewer: oversized half-float frames take the CPU display pass instead of leaving a stale texture
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A double-click on a creation tool in the Tools bar makes what it draws, as in After Effects: a text layer from the Type tools; from the shape tools a shape that fills the comp - into the selected shape layer's Contents, as a mask on the selected layer (or when Tool Creates Mask is on), or as a new shape layer when neither applies. The shape geometry defaults now match AE: the Rounded Rectangle tool's Roundness is a fixed 20 instead of growing with the drawn size, and the Polygon tool draws five points.