mirror of
https://codeberg.org/icewind/vbspview.git
synced 2026-06-03 18:24:09 +02:00
wrapping angle interp
This commit is contained in:
parent
e100f6a732
commit
4eb601187b
4 changed files with 107 additions and 12 deletions
|
|
@ -1,3 +1,4 @@
|
|||
use crate::wrapping::Wrapping;
|
||||
use crate::DemoInfo;
|
||||
use splines::Spline;
|
||||
use std::ops::RangeInclusive;
|
||||
|
|
@ -138,8 +139,8 @@ impl DebugToggle {
|
|||
pub struct DemoCamera {
|
||||
demo: DemoInfo,
|
||||
positions: Spline<f32, Vec3>,
|
||||
pitch: Spline<f32, f32>,
|
||||
yaw: Spline<f32, f32>,
|
||||
pitch: Spline<f32, Wrapping<-180, 180>>,
|
||||
yaw: Spline<f32, Wrapping<-180, 180>>,
|
||||
playing: bool,
|
||||
start_tick: f64,
|
||||
playback_start_time: f64,
|
||||
|
|
@ -269,8 +270,8 @@ impl DemoCamera {
|
|||
.clamped_sample(tick as f32)
|
||||
.unwrap_or(vec3(0.0, 0.0, 0.0)),
|
||||
angles: [
|
||||
self.pitch.clamped_sample(tick as f32).unwrap_or_default(),
|
||||
self.yaw.clamped_sample(tick as f32).unwrap_or_default(),
|
||||
self.pitch.clamped_sample(tick as f32).unwrap_or_default().0,
|
||||
self.yaw.clamped_sample(tick as f32).unwrap_or_default().0,
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
17
src/demo.rs
17
src/demo.rs
|
|
@ -1,4 +1,5 @@
|
|||
use crate::bsp::{map_coords, UNIT_SCALE};
|
||||
use crate::wrapping::Wrapping;
|
||||
use crate::Error;
|
||||
use splines::{Interpolation, Key};
|
||||
use std::fs;
|
||||
|
|
@ -44,8 +45,8 @@ impl DemoInfo {
|
|||
#[derive(Default)]
|
||||
pub struct Positions {
|
||||
pub positions: Vec<Key<f32, Vec3>>,
|
||||
pub pitch: Vec<Key<f32, f32>>,
|
||||
pub yaw: Vec<Key<f32, f32>>,
|
||||
pub pitch: Vec<Key<f32, Wrapping<-180, 180>>>,
|
||||
pub yaw: Vec<Key<f32, Wrapping<-180, 180>>>,
|
||||
}
|
||||
|
||||
struct PovAnalyzer {
|
||||
|
|
@ -113,14 +114,14 @@ impl MessageHandler for PovAnalyzer {
|
|||
NON_LOCAL_PITCH_ANGLES => {
|
||||
self.positions.pitch.push(Key::new(
|
||||
tick as f32,
|
||||
f32::try_from(&prop.value).unwrap_or_default(),
|
||||
Wrapping(f32::try_from(&prop.value).unwrap_or_default()),
|
||||
Interpolation::Linear,
|
||||
));
|
||||
}
|
||||
NON_LOCAL_YAW_ANGLES => {
|
||||
self.positions.yaw.push(Key::new(
|
||||
tick as f32,
|
||||
f32::try_from(&prop.value).unwrap_or_default(),
|
||||
Wrapping(f32::try_from(&prop.value).unwrap_or_default()),
|
||||
Interpolation::Linear,
|
||||
));
|
||||
}
|
||||
|
|
@ -161,13 +162,13 @@ impl MessageHandler for PovAnalyzer {
|
|||
if self.is_pov {
|
||||
self.positions.pitch.push(Key::new(
|
||||
tick as f32,
|
||||
meta.view_angles[0].local_angles.y,
|
||||
Interpolation::CatmullRom,
|
||||
Wrapping(meta.view_angles[0].local_angles.y),
|
||||
Interpolation::Linear,
|
||||
));
|
||||
self.positions.yaw.push(Key::new(
|
||||
tick as f32,
|
||||
meta.view_angles[0].local_angles.x,
|
||||
Interpolation::CatmullRom,
|
||||
Wrapping(meta.view_angles[0].local_angles.x),
|
||||
Interpolation::Linear,
|
||||
));
|
||||
let pos = map_coords(meta.view_angles[0].origin);
|
||||
self.positions.positions.push(Key::new(
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ mod demo;
|
|||
mod loader;
|
||||
mod renderer;
|
||||
mod ui;
|
||||
mod wrapping;
|
||||
|
||||
use clap::Parser;
|
||||
use std::fs;
|
||||
|
|
|
|||
92
src/wrapping.rs
Normal file
92
src/wrapping.rs
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
use splines::Interpolate;
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug)]
|
||||
pub struct Wrapping<const MIN: i32, const MAX: i32>(pub f32);
|
||||
|
||||
/// Map input numbers such that the difference between the output % MAX is the wrapping difference between the input
|
||||
fn unwrap<const MIN: i32, const MAX: i32>(a: f32, b: f32) -> (f32, f32) {
|
||||
let offset = (MAX - MIN) as f32;
|
||||
if a - b < MIN as f32 {
|
||||
(a + offset, b)
|
||||
} else if b - a < MIN as f32 {
|
||||
(a, b + offset)
|
||||
} else {
|
||||
(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unwrap() {
|
||||
assert_eq!((101.0, 99.0), unwrap::<0, 100>(1.0, 99.0));
|
||||
assert_eq!((99.0, 101.0), unwrap::<0, 100>(99.0, 1.0));
|
||||
|
||||
assert_eq!((120.0, 99.0), unwrap::<-100, 100>(-80.0, 99.0));
|
||||
}
|
||||
|
||||
fn wrap<const MIN: i32, const MAX: i32>(num: f32) -> f32 {
|
||||
let offset = (MAX - MIN) as f32;
|
||||
if num > MAX as f32 {
|
||||
num - offset
|
||||
} else if num < MIN as f32 {
|
||||
num + offset
|
||||
} else {
|
||||
num
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MIN: i32, const MAX: i32> Interpolate<f32> for Wrapping<MIN, MAX> {
|
||||
fn step(t: f32, threshold: f32, a: Self, b: Self) -> Self {
|
||||
if t < threshold {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
fn lerp(t: f32, a: Self, b: Self) -> Self {
|
||||
let (a, b) = unwrap::<MIN, MAX>(a.0, b.0);
|
||||
let c = f32::lerp(t, a, b);
|
||||
Wrapping(wrap::<MIN, MAX>(c))
|
||||
}
|
||||
|
||||
fn cosine(t: f32, a: Self, b: Self) -> Self {
|
||||
let (a, b) = unwrap::<MIN, MAX>(a.0, b.0);
|
||||
let c = f32::cosine(t, a, b);
|
||||
Wrapping(wrap::<MIN, MAX>(c))
|
||||
}
|
||||
|
||||
fn cubic_hermite(
|
||||
_t: f32,
|
||||
_x: (f32, Self),
|
||||
_a: (f32, Self),
|
||||
_b: (f32, Self),
|
||||
_y: (f32, Self),
|
||||
) -> Self {
|
||||
todo!();
|
||||
}
|
||||
|
||||
fn quadratic_bezier(_t: f32, _a: Self, _u: Self, _b: Self) -> Self {
|
||||
todo!();
|
||||
}
|
||||
|
||||
fn cubic_bezier(_t: f32, _a: Self, _u: Self, _v: Self, _b: Self) -> Self {
|
||||
todo!();
|
||||
}
|
||||
|
||||
fn cubic_bezier_mirrored(_t: f32, _a: Self, _u: Self, _v: Self, _b: Self) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wrapping_interp() {
|
||||
use splines::{Interpolation, Key, Spline};
|
||||
|
||||
let spline = Spline::from_vec(vec![
|
||||
Key::new(0.0, Wrapping::<-180, 180>(160.0), Interpolation::Linear),
|
||||
Key::new(10.0, Wrapping::<-180, 180>(-160.0), Interpolation::Linear),
|
||||
]);
|
||||
assert_eq!(168.0, spline.sample(2.0).unwrap().0);
|
||||
assert_eq!(180.0, spline.sample(5.0).unwrap().0);
|
||||
assert_eq!(-172.0, spline.sample(7.0).unwrap().0);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue