use std::{cell::RefCell, rc::Rc};
use sim_kernel::{Expr, Result};
use sim_lib_view_device::{DeviceProfile, EncodedScene, LocalAdapter};
use crate::{PoseView, Reprojector};
pub fn clamp_predicted(pose: &PoseView, max_predict_ms: u64) -> PoseView {
let mut clamped = pose.clone();
clamped.predict_ns = clamped
.predict_ns
.min(max_predict_ms.saturating_mul(1_000_000));
clamped
}
#[derive(Debug)]
pub struct ClampedReprojector {
inner: Reprojector,
last_good: RefCell<Option<Rc<Expr>>>,
}
impl ClampedReprojector {
pub fn new(max_predict_ms: u64) -> Self {
Self {
inner: Reprojector::new(max_predict_ms),
last_good: RefCell::new(None),
}
}
pub fn max_predict_ms(&self) -> u64 {
self.inner.max_predict_ms
}
pub fn inner(&self) -> &Reprojector {
&self.inner
}
}
impl LocalAdapter for ClampedReprojector {
type State = PoseView;
fn adapt(
&self,
scene: &EncodedScene,
state: &Self::State,
profile: &DeviceProfile,
) -> Result<Rc<Expr>> {
if pose_exceeds_clamp(state, self.max_predict_ms()) {
return Ok(self
.last_good
.borrow()
.clone()
.unwrap_or_else(|| scene.shared()));
}
let clamped = clamp_predicted(state, self.max_predict_ms());
let out = self.inner.adapt(scene, &clamped, profile)?;
self.last_good.replace(Some(Rc::clone(&out)));
Ok(out)
}
}
pub(crate) fn pose_exceeds_clamp(pose: &PoseView, max_predict_ms: u64) -> bool {
pose.age_ms > max_predict_ms
}