Keyframe diamonds: pointing-hand cursor + prefetch during playback
- Pointing-hand cursor when hovering a clickable keyframe diamond. - Prefetch (Phase 3e, playback only): each update during playback, page in the next few upcoming keyframes (PREFETCH_AHEAD=4) per raster layer that aren't resident, via the existing async worker. Their full pixels land before the playhead reaches them, so playback shows full frames instead of the low-res proxy on every frame (the proxy→full pop was the "flicker"). Reactive faults still cover scrubbing.
This commit is contained in:
parent
3188fc8bb6
commit
ed022995bd
|
|
@ -5283,13 +5283,30 @@ impl eframe::App for EditorApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Dispatch background page-ins for newly-requested keyframes.
|
// 2) Dispatch background page-ins: reactive misses, plus (during playback)
|
||||||
let wanted: Vec<uuid::Uuid> = {
|
// a prefetch of upcoming keyframes so their full pixels are resident
|
||||||
|
// before the playhead reaches them — otherwise every frame shows the
|
||||||
|
// low-res proxy and the proxy→full pops read as flicker.
|
||||||
|
let mut to_load: Vec<uuid::Uuid> = {
|
||||||
let mut s = self.raster_fault_requests.lock().unwrap();
|
let mut s = self.raster_fault_requests.lock().unwrap();
|
||||||
s.drain().collect()
|
s.drain().collect()
|
||||||
};
|
};
|
||||||
|
if self.is_playing && self.raster_store.has_path() {
|
||||||
|
const PREFETCH_AHEAD: usize = 4;
|
||||||
|
let t = self.playback_time;
|
||||||
|
let doc = self.action_executor.document();
|
||||||
|
for layer in doc.all_layers() {
|
||||||
|
if let lightningbeam_core::layer::AnyLayer::Raster(rl) = layer {
|
||||||
|
for kf in rl.keyframes.iter().filter(|kf| kf.time >= t).take(PREFETCH_AHEAD) {
|
||||||
|
if kf.raw_pixels.is_empty() && kf.needs_fault_in {
|
||||||
|
to_load.push(kf.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if self.raster_store.has_path() {
|
if self.raster_store.has_path() {
|
||||||
for kf_id in wanted {
|
for kf_id in to_load {
|
||||||
if self.raster_loads_inflight.contains(&kf_id) {
|
if self.raster_loads_inflight.contains(&kf_id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4867,6 +4867,13 @@ impl TimelinePane {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pointing-hand cursor when hovering a clickable keyframe diamond.
|
||||||
|
if let Some(hover) = response.hover_pos() {
|
||||||
|
if self.keyframe_diamond_hits.iter().any(|(r, _)| r.contains(hover)) {
|
||||||
|
ui.ctx().set_cursor_icon(egui::CursorIcon::PointingHand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Click a keyframe diamond → snap the playhead exactly to that keyframe.
|
// Click a keyframe diamond → snap the playhead exactly to that keyframe.
|
||||||
// (Hit targets come from the previous frame's render_layers; diamonds don't
|
// (Hit targets come from the previous frame's render_layers; diamonds don't
|
||||||
// move between frames, so a click lands on the right one.)
|
// move between frames, so a click lands on the right one.)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue