Commit Graph

8 Commits

Author SHA1 Message Date
Skyler Lehmkuhl b301c63387 Address code-review findings across export, decode, and data model
Export correctness:
- Honor the user's color-range (Limited/Full) on the software encode path:
  thread full_range through gpu_yuv (new shader range uniform), the CPU
  swscale fallback (sws_setColorspaceDetails → BT.709 + range, fixing the
  BT.601 hue/level shift on odd-width exports), and the encoder color tags.
- Reject HDR + WebM up front with a clear message and log the forced HEVC
  override instead of producing an unplayable file.
- Delete dead render_frame_to_rgba_hdr (hardcoded Stretch; live HDR path
  already honors the fit mode).

Decode/playback (video.rs):
- Drain the decoder at EOF (send_eof + flush) so the final B-frame-delayed
  frames render instead of erroring; per-frame logic extracted to a helper.
- Missing-PTS frames continue monotonically rather than snapping to ts=0.
- Force exact thumbnail width so sub-128px sources aren't shown stretched.

Resource leaks (gpu-video-encoder):
- dmabuf import_raw: RAII guard frees the duped fd + partial VkImages/memory
  on every error path.
- vaapi alloc: free device/frames-ctx/AVFrames on the unexpected-DRM path.

Data model / robustness:
- collapse_boundary_spikes requires a full curve reversal (all control
  points) so it no longer deletes a real lens/sliver and drops the fill.
- Export audio spin-wait ignores a stale `finished` flag when a forward
  seek is pending (was rendering silence over real audio).
- RasterDiff apply_before/after take current dims and skip on a post-resize
  mismatch.
- beam_archive read_media_full caps the preallocation from untrusted total_len.

UI/visual:
- SVG export skips hidden layers/empty groups; import folds fill-opacity into
  gradients and surfaces failures as a notification.
- Active raster-layer border uses playback_time + overlay_transform.
- gpu_brush remove_layer_texture also evicts the stale low-res proxy.
- ensure_raster_resident_for_undo registers faulted frames in the LRU so
  resident RAM stays bounded.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 17:47:32 -04:00
Skyler Lehmkuhl 83057b754a Clean up build warnings
Resolve all compiler warnings across daw-backend, lightningbeam-core, and
lightningbeam-editor:

- Delete dead code: the superseded CPU raster tools in raster_tool.rs
  (EffectBrush/Smudge/Gradient/Transform/Warp/Liquify/Selection — replaced by
  the GPU path), plus orphaned helpers and never-read struct fields.
- Mechanical fixes: drop unused imports/variables/mut, underscore unused params,
  `drop(&x)` -> `let _ = x`, deprecated egui::Rounding -> CornerRadius, snake_case
  rename, elided-lifetime Cow<'_, [u8]>.
- Keep the WIP CSS theming system (theme.rs/theme_render.rs) under
  #[allow(dead_code)] rather than deleting it.

Editor checks warning-free; 293 core tests pass.
2026-06-21 16:48:59 -04:00
Skyler Lehmkuhl a1acecf396 Implement shape tweens (same-topology lerp)
`tween_after == Shape` was stored on keyframes but never read. Now the
render path morphs geometry across a shape-tween span:

- VectorGraph::interpolated(other, t): same-topology lerp of vertex
  positions, edge curves, stroke widths and stroke/fill colours. Returns
  None when topology differs (counts, deleted flags, edge endpoints, fill
  boundaries), so the caller holds the source keyframe.
- VectorLayer::tweened_graph_at(time): returns an owned morphed graph for
  a shape-tween span whose two keyframes share topology, else borrows the
  held keyframe. Editing still uses graph_at_time (the held keyframe).
- Renderer (Vello + CPU paths) renders via tweened_graph_at.
- SetTweenAction + wired the previously-stubbed "Add Shape Tween" menu.

The typical workflow — keyframe, duplicate it (same topology), move
vertices, Add Shape Tween — now morphs between the two. Non-matching
topology falls back to a hold.
2026-06-21 15:46:53 -04:00
Skyler Lehmkuhl 87bcffd427 Collapse boundary spikes in region cut; embed dump regression fixtures
A dense self-intersecting freehand lasso leaves clusters of near-coincident
duplicate sub-pixel edges (split products the coincident-edge dedupe can't
reach). The planar face trace bounces back and forth across them, producing
a degenerate "spike" boundary (an edge used twice). Add
`collapse_boundary_spikes`, run on each traced face before it becomes a
fill: it removes consecutive out-and-back entries (where the boundary
returns to where it started) until the loop is simple.

Embed the captured region-select dumps as committed fixtures under
tests/region_dumps/ (replayed by `dumped_region_selects_are_valid`) so the
regression survives /tmp being cleared. dump3 is the boundary-spike repro;
it fails this test without the collapse and passes with it. Loosen the
boundary-connectivity test tolerance to 1e-2 (above sub-micropixel float
drift, far below any real gap).
2026-06-21 15:02:30 -04:00
Skyler Lehmkuhl 39978e59b3 Unify selection systems and make region/lasso cut robust
Collapse the two parallel selection systems into one. The RegionSelect
tool (rect + lasso) now cuts the geometry along the region outline and
selects the resulting sub-pieces into the standard `Selection` ID-sets,
exactly like every other tool. The vestigial floating `RegionSelection`
(drag never wired; commit/delete/copy were stubbed) and all its plumbing
are removed, so Group, Convert-to-Movie-Clip, Delete, and Properties all
operate uniformly from lasso, rect, marquee, and click selections.

Region cutting is reworked onto a robust planar arrangement:

- Replace fragile incremental "split a fill by one cut edge" logic with
  planar face re-tracing (`retrace_fills_after_cut` + `trace_faces`),
  which correctly handles arbitrary holed/concave fills.
- `extract_subgraph` no longer frees vertices still referenced by kept
  boundary edges (fixed Group leaving freed-but-referenced vertices that
  a later alloc reused and corrupted).
- `split_fill_by_*` direction fix (was producing disconnected boundaries
  rendered as stray diagonals).
- `fill_interior_point` (area-centroid + inward-step fallback) for
  reliable inside/outside classification of non-convex pieces.
- Coincident-edge dedupe + degenerate-fill removal (edge-adjacent shapes
  no longer make zero-area sliver fills).
- Dangling-edge pruning, near-coincident endpoint welding, induced-
  subgraph expansion, and tracking of `split_edge` sub-edges, so
  self-intersecting freehand lassos cut correctly.

Region-select capture is available behind LIGHTNINGBEAM_DUMP_REGION=1 for
turning a misbehaving cut into a deterministic test. Extensive regression
tests added in vector_graph/tests/region_cut_select.rs.
2026-06-21 14:47:11 -04:00
Skyler Lehmkuhl 0d253d9629 Motion tweens: implement Group + Convert to Movie Clip for DCEL geometry
Both actions were DCEL-stubs (no-ops). They now extract the selected geometry from a
vector layer's active keyframe into a new VectorClip (group vs movie clip) and place a
ClipInstance in its place (identity transform → renders where the geometry was), which
the existing transform-animation system can motion-tween.

- Shared `clip_from_geometry::extract_geometry_to_clip` (+ undo) does the work; the
  actions are thin wrappers. Undo snapshots the source graph + removes the clip/instance.
- `extract_subgraph` now DERIVES shared-fill boundary edges internally (an inside edge
  still used by a non-extracted fill must be duplicated, not moved) and unions them with
  the caller's `explicit_boundary` — so a plain geometry selection needs no boundary
  analysis (the selection already includes fill boundary edges via `select_fill`). The
  region-select caller keeps passing its lasso boundary.
- Handlers: Group / Convert to Movie Clip on a geometry selection now build these actions
  from `selected_fills`/`selected_edges`.

Next: shape tweens (same-topology lerp).
2026-06-21 09:12:46 -04:00
Skyler Lehmkuhl f16e651610 work on vector graph 2026-03-22 18:16:17 -04:00
Skyler Lehmkuhl c9a9c2c5f0 rewrite vector backend again 2026-03-13 18:53:33 -04:00