interp wip

This commit is contained in:
Robin Appelman 2022-04-03 18:02:01 +02:00
commit 7850af5b11
4 changed files with 160 additions and 37 deletions

10
Cargo.lock generated
View file

@ -2481,6 +2481,15 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "splines"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85d3c90d443c10f66d69fc45269f3bf1d3b0171c239751fe6129b7d79a82c535"
dependencies = [
"cgmath",
]
[[package]] [[package]]
name = "static_assertions" name = "static_assertions"
version = "1.1.0" version = "1.1.0"
@ -3024,6 +3033,7 @@ dependencies = [
"delaunator", "delaunator",
"itertools", "itertools",
"miette", "miette",
"splines",
"steamid-ng", "steamid-ng",
"steamlocate", "steamlocate",
"tf-demo-parser", "tf-demo-parser",

View file

@ -22,6 +22,7 @@ cgmath = "0.18.0"
tf-demo-parser = { version = "0.4.0", path = "../demostf/tf-demo-parser" } tf-demo-parser = { version = "0.4.0", path = "../demostf/tf-demo-parser" }
steamid-ng = "1.0.0" steamid-ng = "1.0.0"
clap = { version = "3.1.8", features = ["derive"] } clap = { version = "3.1.8", features = ["derive"] }
splines = { version = "4.1.0", features = ["cgmath"] }
[profile.dev.package."*"] [profile.dev.package."*"]
opt-level = 2 opt-level = 2

View file

@ -1,4 +1,5 @@
use crate::DemoInfo; use crate::DemoInfo;
use splines::{Interpolate, Spline};
use std::ops::RangeInclusive; use std::ops::RangeInclusive;
use three_d::egui::{Slider, Ui}; use three_d::egui::{Slider, Ui};
use three_d::*; use three_d::*;
@ -136,6 +137,7 @@ impl DebugToggle {
pub struct DemoCamera { pub struct DemoCamera {
demo: DemoInfo, demo: DemoInfo,
spline: Spline<f32, TickData>,
playing: bool, playing: bool,
start_tick: f64, start_tick: f64,
playback_start_time: f64, playback_start_time: f64,
@ -149,7 +151,7 @@ pub struct DemoCamera {
impl Control for DemoCamera { impl Control for DemoCamera {
fn handle( fn handle(
&mut self, &mut self,
_camera: &mut Camera, camera: &mut Camera,
events: &mut [Event], events: &mut [Event],
_elapsed_time: f64, _elapsed_time: f64,
accumulated_time: f64, accumulated_time: f64,
@ -191,9 +193,8 @@ impl Control for DemoCamera {
play_time = accumulated_time - self.playback_start_time, play_time = accumulated_time - self.playback_start_time,
"playing tick" "playing tick"
); );
// todo: interpolate let data = self.get_tick(tick);
let (position, [pitch, yaw]) = self.demo.positions[tick as usize]; self.apply_view(camera, data.position, data.angles[1], data.angles[0]);
self.apply_view(_camera, position, yaw, pitch);
} }
self.force_update = false; self.force_update = false;
} }
@ -220,8 +221,18 @@ impl Control for DemoCamera {
impl DemoCamera { impl DemoCamera {
pub fn new(demo: DemoInfo) -> Self { pub fn new(demo: DemoInfo) -> Self {
let spline = Spline::from_iter(demo.positions.iter().cloned().map(
|(tick, position, angles)| {
splines::Key::new(
(tick - demo.start_tick) as f32,
TickData { position, angles },
splines::Interpolation::Cosine,
)
},
));
DemoCamera { DemoCamera {
demo, demo,
spline,
playing: false, playing: false,
start_tick: 0.0, start_tick: 0.0,
playback_start_time: 0.0, playback_start_time: 0.0,
@ -256,6 +267,10 @@ impl DemoCamera {
self.playback_start_time = time; self.playback_start_time = time;
self.force_update = true; self.force_update = true;
} }
fn get_tick(&self, tick: f64) -> TickData {
self.spline.sample(tick as f32).unwrap()
}
} }
fn apply_camera_action( fn apply_camera_action(
@ -305,3 +320,107 @@ fn apply_camera_action(
} }
Ok(control_type != CameraAction::None) Ok(control_type != CameraAction::None)
} }
#[derive(Copy, Clone, Debug)]
struct TickData {
position: Vec3,
angles: [f32; 2],
}
impl Interpolate<f32> for TickData {
fn step(t: f32, threshold: f32, a: Self, b: Self) -> Self {
TickData {
position: Vec3::step(t, threshold, a.position, b.position),
angles: [
f32::step(t, threshold, a.angles[0], b.angles[0]),
f32::step(t, threshold, a.angles[1], b.angles[1]),
],
}
}
fn lerp(t: f32, a: Self, b: Self) -> Self {
TickData {
position: <Vec3 as Interpolate<f32>>::lerp(t, a.position, b.position),
angles: [
f32::lerp(t, a.angles[0], b.angles[0]),
f32::lerp(t, a.angles[1], b.angles[1]),
],
}
}
fn cosine(t: f32, a: Self, b: Self) -> Self {
TickData {
position: Vec3::cosine(t, a.position, b.position),
angles: [
f32::cosine(t, a.angles[0], b.angles[0]),
f32::cosine(t, a.angles[1], b.angles[1]),
],
}
}
fn cubic_hermite(
t: f32,
x: (f32, Self),
a: (f32, Self),
b: (f32, Self),
y: (f32, Self),
) -> Self {
TickData {
position: Vec3::cubic_hermite(
t,
(x.0, x.1.position),
(a.0, a.1.position),
(b.0, b.1.position),
(y.0, y.1.position),
),
angles: [
f32::cubic_hermite(
t,
(x.0, x.1.angles[0]),
(a.0, a.1.angles[0]),
(b.0, b.1.angles[0]),
(y.0, y.1.angles[0]),
),
f32::cubic_hermite(
t,
(x.0, x.1.angles[1]),
(a.0, a.1.angles[1]),
(b.0, b.1.angles[1]),
(y.0, y.1.angles[1]),
),
],
}
}
fn quadratic_bezier(t: f32, a: Self, u: Self, b: Self) -> Self {
TickData {
position: Vec3::quadratic_bezier(t, a.position, u.position, b.position),
angles: [
f32::quadratic_bezier(t, a.angles[0], u.angles[0], b.angles[0]),
f32::quadratic_bezier(t, a.angles[1], u.angles[1], b.angles[1]),
],
}
}
fn cubic_bezier(t: f32, a: Self, u: Self, v: Self, b: Self) -> Self {
TickData {
position: Vec3::cubic_bezier(t, a.position, u.position, v.position, b.position),
angles: [
f32::cubic_bezier(t, a.angles[0], u.angles[0], v.angles[0], b.angles[0]),
f32::cubic_bezier(t, a.angles[1], u.angles[1], v.angles[1], b.angles[1]),
],
}
}
fn cubic_bezier_mirrored(t: f32, a: Self, u: Self, v: Self, b: Self) -> Self {
TickData {
position: Vec3::cubic_bezier_mirrored(
t, a.position, u.position, v.position, b.position,
),
angles: [
f32::cubic_bezier_mirrored(t, a.angles[0], u.angles[0], v.angles[0], b.angles[0]),
f32::cubic_bezier_mirrored(t, a.angles[1], u.angles[1], v.angles[1], b.angles[1]),
],
}
}
}

View file

@ -16,7 +16,7 @@ use three_d::{vec3, Vec3};
pub struct DemoInfo { pub struct DemoInfo {
pub map: String, pub map: String,
pub positions: Vec<(Vec3, [f32; 2])>, pub positions: Vec<(u32, Vec3, [f32; 2])>,
pub start_tick: u32, pub start_tick: u32,
pub time_per_tick: f64, pub time_per_tick: f64,
} }
@ -42,7 +42,7 @@ struct PovAnalyzer {
last_position: Vector, last_position: Vector,
last_angles: [f32; 2], last_angles: [f32; 2],
view_offset: f32, view_offset: f32,
positions: Vec<(Vec3, [f32; 2])>, positions: Vec<(u32, Vec3, [f32; 2])>,
name: String, name: String,
player: Option<EntityId>, player: Option<EntityId>,
start_tick: u32, start_tick: u32,
@ -52,7 +52,7 @@ struct PovAnalyzer {
} }
impl MessageHandler for PovAnalyzer { impl MessageHandler for PovAnalyzer {
type Output = (Vec<(Vec3, [f32; 2])>, u32, f32); type Output = (Vec<(u32, Vec3, [f32; 2])>, u32, f32);
fn does_handle(message_type: MessageType) -> bool { fn does_handle(message_type: MessageType) -> bool {
matches!(message_type, MessageType::PacketEntities) matches!(message_type, MessageType::PacketEntities)
@ -65,31 +65,23 @@ impl MessageHandler for PovAnalyzer {
} }
} }
fn handle_packet_meta(&mut self, meta: &MessagePacketMeta) {
if self.is_pov {
self.last_angles = [
meta.view_angles.local_angles.1.x,
meta.view_angles.local_angles.1.y,
];
self.last_position = meta.view_angles.origin.1
}
}
fn handle_message(&mut self, message: &Message, tick: u32) { fn handle_message(&mut self, message: &Message, tick: u32) {
const LOCAL_ORIGIN: SendPropIdentifier = if tick != self.last_tick {
SendPropIdentifier::new("DT_TFLocalPlayerExclusive", "m_vecOrigin"); self.last_tick = tick;
let pos = map_coords(self.last_position);
self.positions.push((
tick,
vec3(pos[0], pos[1] + self.view_offset, pos[2]),
self.last_angles,
));
}
const NON_LOCAL_ORIGIN: SendPropIdentifier = const NON_LOCAL_ORIGIN: SendPropIdentifier =
SendPropIdentifier::new("DT_TFNonLocalPlayerExclusive", "m_vecOrigin"); SendPropIdentifier::new("DT_TFNonLocalPlayerExclusive", "m_vecOrigin");
const LOCAL_ORIGIN_Z: SendPropIdentifier =
SendPropIdentifier::new("DT_TFLocalPlayerExclusive", "m_vecOrigin[2]");
const NON_LOCAL_ORIGIN_Z: SendPropIdentifier = const NON_LOCAL_ORIGIN_Z: SendPropIdentifier =
SendPropIdentifier::new("DT_TFNonLocalPlayerExclusive", "m_vecOrigin[2]"); SendPropIdentifier::new("DT_TFNonLocalPlayerExclusive", "m_vecOrigin[2]");
const LOCAL_YAW_ANGLES: SendPropIdentifier =
SendPropIdentifier::new("DT_TFLocalPlayerExclusive", "m_angEyeAngles[1]");
const NON_LOCAL_YAW_ANGLES: SendPropIdentifier = const NON_LOCAL_YAW_ANGLES: SendPropIdentifier =
SendPropIdentifier::new("DT_TFNonLocalPlayerExclusive", "m_angEyeAngles[1]"); SendPropIdentifier::new("DT_TFNonLocalPlayerExclusive", "m_angEyeAngles[1]");
const LOCAL_PITCH_ANGLES: SendPropIdentifier =
SendPropIdentifier::new("DT_TFLocalPlayerExclusive", "m_angEyeAngles[0]");
const NON_LOCAL_PITCH_ANGLES: SendPropIdentifier = const NON_LOCAL_PITCH_ANGLES: SendPropIdentifier =
SendPropIdentifier::new("DT_TFNonLocalPlayerExclusive", "m_angEyeAngles[0]"); SendPropIdentifier::new("DT_TFNonLocalPlayerExclusive", "m_angEyeAngles[0]");
const VIEW_OFFSET: SendPropIdentifier = const VIEW_OFFSET: SendPropIdentifier =
@ -103,19 +95,19 @@ impl MessageHandler for PovAnalyzer {
if entity.entity_index == player_id { if entity.entity_index == player_id {
for prop in &entity.props { for prop in &entity.props {
match prop.identifier { match prop.identifier {
LOCAL_ORIGIN | NON_LOCAL_ORIGIN => { NON_LOCAL_ORIGIN => {
let pos_xy = VectorXY::try_from(&prop.value).unwrap_or_default(); let pos_xy = VectorXY::try_from(&prop.value).unwrap_or_default();
self.last_position.x = pos_xy.x; self.last_position.x = pos_xy.x;
self.last_position.y = pos_xy.y; self.last_position.y = pos_xy.y;
} }
LOCAL_ORIGIN_Z | NON_LOCAL_ORIGIN_Z => { NON_LOCAL_ORIGIN_Z => {
self.last_position.z = self.last_position.z =
f32::try_from(&prop.value).unwrap_or_default() f32::try_from(&prop.value).unwrap_or_default()
} }
LOCAL_YAW_ANGLES | NON_LOCAL_YAW_ANGLES => { NON_LOCAL_YAW_ANGLES => {
self.last_angles[1] = f32::try_from(&prop.value).unwrap_or_default() self.last_angles[1] = f32::try_from(&prop.value).unwrap_or_default()
} }
LOCAL_PITCH_ANGLES | NON_LOCAL_PITCH_ANGLES => { NON_LOCAL_PITCH_ANGLES => {
self.last_angles[0] = f32::try_from(&prop.value).unwrap_or_default() self.last_angles[0] = f32::try_from(&prop.value).unwrap_or_default()
} }
VIEW_OFFSET => { VIEW_OFFSET => {
@ -128,15 +120,6 @@ impl MessageHandler for PovAnalyzer {
} }
} }
} }
if tick > self.last_tick {
self.last_tick = tick;
let pos = map_coords(self.last_position);
self.positions.push((
vec3(pos[0], pos[1] + self.view_offset, pos[2]),
self.last_angles,
));
}
} }
fn handle_string_entry(&mut self, table: &str, _index: usize, entry: &StringTableEntry) { fn handle_string_entry(&mut self, table: &str, _index: usize, entry: &StringTableEntry) {
@ -148,6 +131,16 @@ impl MessageHandler for PovAnalyzer {
} }
} }
fn handle_packet_meta(&mut self, meta: &MessagePacketMeta) {
if self.is_pov {
self.last_angles = [
meta.view_angles.local_angles.1.x,
meta.view_angles.local_angles.1.y,
];
self.last_position = meta.view_angles.origin.1
}
}
fn into_output(self, state: &ParserState) -> Self::Output { fn into_output(self, state: &ParserState) -> Self::Output {
( (
self.positions, self.positions,