From 527ab129200de590b108362083bb314827c20d56 Mon Sep 17 00:00:00 2001 From: khang Date: Fri, 29 Mar 2024 14:22:23 -0400 Subject: [PATCH 1/4] Add pitch smoothing --- src/modules/tas_studio/editor/mod.rs | 101 ++++++++++++++++++--------- 1 file changed, 69 insertions(+), 32 deletions(-) diff --git a/src/modules/tas_studio/editor/mod.rs b/src/modules/tas_studio/editor/mod.rs index 1ffac2b..f8d85e4 100644 --- a/src/modules/tas_studio/editor/mod.rs +++ b/src/modules/tas_studio/editor/mod.rs @@ -15,7 +15,7 @@ use hltas::types::{ VectorialStrafingConstraints, }; use hltas::HLTAS; -use itertools::Itertools; +use itertools::{izip, Itertools}; use thiserror::Error; use self::db::{Action, ActionKind, Branch, Db}; @@ -3508,7 +3508,7 @@ impl Editor { } let frames = &self.branch().frames; - let smoothed = smoothed_yaws( + let smoothed = smoothed_views( self.smooth_window_s, self.smooth_small_window_s, self.smooth_small_window_multiplier, @@ -3517,7 +3517,7 @@ impl Editor { let mut line = "target_yaw_override".to_string(); // Skip the first frame because it is the initial frame before the start of the TAS. - for yaw in &smoothed[1..] { + for yaw in &smoothed.1[1..] { let yaw = yaw.to_degrees(); write!(&mut line, " {yaw}").unwrap(); } @@ -3525,6 +3525,15 @@ impl Editor { let op = Operation::Insert { line_idx: 0, line }; self.apply_operation(op)?; + let mut line = "pitch_override".to_string(); + for pitch in &smoothed.0[1..] { + let pitch = pitch.to_degrees(); + write!(&mut line, " {pitch}").unwrap(); + } + + let op = Operation::Insert { line_idx: 1, line }; + self.apply_operation(op)?; + Ok(()) } @@ -3561,7 +3570,7 @@ impl Editor { )); } - let mut smoothed = smoothed_yaws( + let mut smoothed = smoothed_views( self.smooth_window_s, self.smooth_small_window_s, self.smooth_small_window_multiplier, @@ -3571,11 +3580,11 @@ impl Editor { // Skip the first frame because it is the initial frame before the start of the TAS. let first = start.max(1); if start == 0 { - smoothed.remove(0); + smoothed.1.remove(0); } // Convert to degrees for .hltas. - for yaw in &mut smoothed { + for yaw in &mut smoothed.1 { *yaw = yaw.to_degrees(); } @@ -3585,7 +3594,7 @@ impl Editor { if repeat == 0 { let mut line = "target_yaw_override".to_string(); - for yaw in smoothed { + for yaw in smoothed.1 { write!(&mut line, " {yaw}").unwrap(); } @@ -3594,7 +3603,7 @@ impl Editor { self.apply_operation(op)?; Ok(()) } else { - let target_yaw_override = Line::TargetYawOverride(smoothed); + let target_yaw_override = Line::TargetYawOverride(smoothed.1); // We need to insert the line in the middle of a frame bulk, so split it. let mut line = self.branch().branch.script.lines[line_idx].clone(); @@ -3780,20 +3789,27 @@ impl Editor { ); // Compute and insert the smoothed TargetYawOverride line. - let mut smoothed = smoothed_yaws( + let mut smoothed = smoothed_views( self.smooth_window_s, self.smooth_small_window_s, self.smooth_small_window_multiplier, &branch.frames, ); // First yaw corresponds to the initial frame, which is not controlled by the TAS. - smoothed.remove(0); - for yaw in &mut smoothed { + smoothed.0.remove(0); + smoothed.1.remove(0); + for yaw in &mut smoothed.1 { *yaw = yaw.to_degrees(); } - let line = Line::TargetYawOverride(smoothed); + let line = Line::TargetYawOverride(smoothed.1); smoothed_script.lines.insert(2, line); + for pitch in &mut smoothed.0 { + *pitch = pitch.to_degrees(); + } + let line = Line::PitchOverride(smoothed.0); + smoothed_script.lines.insert(3, line); + // Remove all lines disabling vectorial strafing. let mut i = 0; while i < smoothed_script.lines.len() { @@ -4555,43 +4571,56 @@ fn unwrap_angles(xs: impl Iterator) -> impl Iterator { }) } -fn smoothed_yaws( +fn smoothed_views( window_size: f32, small_window_size: f32, small_window_multiplier: f32, frames: &[Frame], -) -> Vec { +) -> (Vec, Vec) { if frames.is_empty() { - return vec![]; + return (vec![], vec![]); } let yaws = frames.iter().map(|f| f.state.prev_frame_input.yaw); - let unwrapped: Vec = unwrap_angles(yaws).collect(); - let mut rv = Vec::with_capacity(unwrapped.len()); + let unwrapped_yaws: Vec = unwrap_angles(yaws).collect(); + let mut rv_yaws = Vec::with_capacity(unwrapped_yaws.len()); + + let pitches = frames.iter().map(|f| f.state.prev_frame_input.pitch); + let unwrapped_pitches: Vec = unwrap_angles(pitches).collect(); + let mut rv_pitches = Vec::with_capacity(unwrapped_pitches.len()); fn frame_time(frame: &Frame) -> f32 { frame.parameters.frame_time } - let repeat_first = iter::repeat((frame_time(&frames[0]), unwrapped[0])); - let repeat_last = iter::repeat(( + let repeat_first_view = iter::repeat(( + frame_time(&frames[0]), + unwrapped_pitches[0], + unwrapped_yaws[0], + )); + let repeat_last_view = iter::repeat(( frame_time(frames.last().unwrap()), - *unwrapped.last().unwrap(), + *unwrapped_pitches.last().unwrap(), + *unwrapped_yaws.last().unwrap(), )); // The smoothing window is centered at the center of each yaw. - for i in 0..unwrapped.len() { + // For pitch smoothing, every frame has both pitch and yaw so iterate over this is ok. + for i in 0..unwrapped_yaws.len() { let mut total_yaw = 0.; + let mut total_pitch = 0.; let mut total_weight = 0.; let mut process_frame = - |(mut rem_win_size, mut rem_small_win_size), (mut frame_time, yaw): (f32, f32)| { + |(mut rem_win_size, mut rem_small_win_size), + (mut frame_time, pitch, yaw): (f32, f32, f32)| { // If there's any small window zone left to cover, do so. if rem_small_win_size > 0. { let dt = frame_time.min(rem_small_win_size); let weight = dt * small_window_multiplier; total_yaw += yaw * weight; + total_pitch += pitch * weight; total_weight += weight; rem_win_size -= dt; @@ -4615,6 +4644,7 @@ fn smoothed_yaws( let weight = dt; total_yaw += yaw * weight; + total_pitch += pitch * weight; total_weight += weight; rem_win_size -= dt; @@ -4633,34 +4663,41 @@ fn smoothed_yaws( let rem_small_win_size = small_window_size / 2.; // Start from the middle frame. - let middle_frame_half = iter::once((frames[i].parameters.frame_time / 2., unwrapped[i])); + let middle_frame_half = iter::once(( + frames[i].parameters.frame_time / 2., + unwrapped_pitches[i], + unwrapped_yaws[i], + )); // Walk back half an interval. middle_frame_half .clone() .chain( - zip( + izip!( frames[..i].iter().map(frame_time), - unwrapped[..i].iter().copied(), + unwrapped_pitches[..i].iter().copied(), + unwrapped_yaws[..i].iter().copied(), ) .rev(), ) - .chain(repeat_first.clone()) + .chain(repeat_first_view.clone()) .try_fold((rem_win_size, rem_small_win_size), &mut process_frame); // Walk forward half an interval. middle_frame_half - .chain(zip( + .chain(izip!( frames[i + 1..].iter().map(frame_time), - unwrapped[i + 1..].iter().copied(), + unwrapped_pitches[i + 1..].iter().copied(), + unwrapped_yaws[i + 1..].iter().copied(), )) - .chain(repeat_last.clone()) + .chain(repeat_last_view.clone()) .try_fold((rem_win_size, rem_small_win_size), &mut process_frame); - rv.push(total_yaw / total_weight); + rv_yaws.push(total_yaw / total_weight); + rv_pitches.push(total_pitch / total_weight); } - rv + (rv_pitches, rv_yaws) } fn replace_multiple_params<'a>( @@ -4923,7 +4960,7 @@ mod tests { }) .collect(); - let smoothed = smoothed_yaws(1., small_window_size, 4., &frames); + let smoothed = smoothed_views(1., small_window_size, 4., &frames); expect.assert_debug_eq(&smoothed); } From 6f3283d02d22b6ed57dfaa38c61401a7ca336f30 Mon Sep 17 00:00:00 2001 From: khang Date: Sat, 6 Apr 2024 14:52:34 -0400 Subject: [PATCH 2/4] fix test --- src/modules/tas_studio/editor/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/tas_studio/editor/mod.rs b/src/modules/tas_studio/editor/mod.rs index f8d85e4..1c7c9e6 100644 --- a/src/modules/tas_studio/editor/mod.rs +++ b/src/modules/tas_studio/editor/mod.rs @@ -4960,7 +4960,7 @@ mod tests { }) .collect(); - let smoothed = smoothed_views(1., small_window_size, 4., &frames); + let smoothed = smoothed_views(1., small_window_size, 4., &frames).1; expect.assert_debug_eq(&smoothed); } From f476b8e646cef67daf03f3bd0aba80a546d9a371 Mon Sep 17 00:00:00 2001 From: khang Date: Fri, 26 Apr 2024 16:21:25 -0400 Subject: [PATCH 3/4] changes suggested --- src/modules/tas_studio/editor/mod.rs | 125 ++++++++++++++------------- 1 file changed, 67 insertions(+), 58 deletions(-) diff --git a/src/modules/tas_studio/editor/mod.rs b/src/modules/tas_studio/editor/mod.rs index 1c7c9e6..0188c40 100644 --- a/src/modules/tas_studio/editor/mod.rs +++ b/src/modules/tas_studio/editor/mod.rs @@ -3508,16 +3508,29 @@ impl Editor { } let frames = &self.branch().frames; - let smoothed = smoothed_views( + + let yaws = frames.iter().map(|f| f.state.prev_frame_input.yaw); + let pitches = frames.iter().map(|f| f.state.prev_frame_input.pitch); + + let smoothed_yaws = smoothed_views( self.smooth_window_s, self.smooth_small_window_s, self.smooth_small_window_multiplier, &frames[..frames.len()], + yaws, + ); + + let smoothed_pitches = smoothed_views( + self.smooth_window_s, + self.smooth_small_window_s, + self.smooth_small_window_multiplier, + &frames[..frames.len()], + pitches, ); let mut line = "target_yaw_override".to_string(); // Skip the first frame because it is the initial frame before the start of the TAS. - for yaw in &smoothed.1[1..] { + for yaw in &smoothed_yaws[1..] { let yaw = yaw.to_degrees(); write!(&mut line, " {yaw}").unwrap(); } @@ -3526,7 +3539,7 @@ impl Editor { self.apply_operation(op)?; let mut line = "pitch_override".to_string(); - for pitch in &smoothed.0[1..] { + for pitch in &smoothed_pitches[1..] { let pitch = pitch.to_degrees(); write!(&mut line, " {pitch}").unwrap(); } @@ -3570,21 +3583,23 @@ impl Editor { )); } - let mut smoothed = smoothed_views( + let yaws = frames.iter().map(|f| f.state.prev_frame_input.yaw); + let mut smoothed_yaws = smoothed_views( self.smooth_window_s, self.smooth_small_window_s, self.smooth_small_window_multiplier, &frames[start..=end], + yaws, ); // Skip the first frame because it is the initial frame before the start of the TAS. let first = start.max(1); if start == 0 { - smoothed.1.remove(0); + smoothed_yaws.remove(0); } // Convert to degrees for .hltas. - for yaw in &mut smoothed.1 { + for yaw in &mut smoothed_yaws { *yaw = yaw.to_degrees(); } @@ -3594,7 +3609,7 @@ impl Editor { if repeat == 0 { let mut line = "target_yaw_override".to_string(); - for yaw in smoothed.1 { + for yaw in smoothed_yaws { write!(&mut line, " {yaw}").unwrap(); } @@ -3603,7 +3618,7 @@ impl Editor { self.apply_operation(op)?; Ok(()) } else { - let target_yaw_override = Line::TargetYawOverride(smoothed.1); + let target_yaw_override = Line::TargetYawOverride(smoothed_yaws); // We need to insert the line in the middle of a frame bulk, so split it. let mut line = self.branch().branch.script.lines[line_idx].clone(); @@ -3788,26 +3803,39 @@ impl Editor { ), ); - // Compute and insert the smoothed TargetYawOverride line. - let mut smoothed = smoothed_views( + // Compute and insert the smoothed TargetYawOverride and PitchOverride line. + let yaws = branch.frames.iter().map(|f| f.state.prev_frame_input.yaw); + let pitches = branch.frames.iter().map(|f| f.state.prev_frame_input.pitch); + + let mut smoothed_yaws = smoothed_views( self.smooth_window_s, self.smooth_small_window_s, self.smooth_small_window_multiplier, &branch.frames, + yaws, ); + let mut smoothed_pitches = smoothed_views( + self.smooth_window_s, + self.smooth_small_window_s, + self.smooth_small_window_multiplier, + &branch.frames, + pitches, + ); + // First yaw corresponds to the initial frame, which is not controlled by the TAS. - smoothed.0.remove(0); - smoothed.1.remove(0); - for yaw in &mut smoothed.1 { + smoothed_yaws.remove(0); + for yaw in &mut smoothed_yaws { *yaw = yaw.to_degrees(); } - let line = Line::TargetYawOverride(smoothed.1); + + let line = Line::TargetYawOverride(smoothed_yaws); smoothed_script.lines.insert(2, line); - for pitch in &mut smoothed.0 { + smoothed_pitches.remove(0); + for pitch in &mut smoothed_pitches { *pitch = pitch.to_degrees(); } - let line = Line::PitchOverride(smoothed.0); + let line = Line::PitchOverride(smoothed_pitches); smoothed_script.lines.insert(3, line); // Remove all lines disabling vectorial strafing. @@ -4576,51 +4604,39 @@ fn smoothed_views( small_window_size: f32, small_window_multiplier: f32, frames: &[Frame], -) -> (Vec, Vec) { + views: impl Iterator, +) -> Vec { if frames.is_empty() { - return (vec![], vec![]); + return vec![]; } - let yaws = frames.iter().map(|f| f.state.prev_frame_input.yaw); - let unwrapped_yaws: Vec = unwrap_angles(yaws).collect(); - let mut rv_yaws = Vec::with_capacity(unwrapped_yaws.len()); - - let pitches = frames.iter().map(|f| f.state.prev_frame_input.pitch); - let unwrapped_pitches: Vec = unwrap_angles(pitches).collect(); - let mut rv_pitches = Vec::with_capacity(unwrapped_pitches.len()); + let unwrapped: Vec = unwrap_angles(views).collect(); + let mut rv = Vec::with_capacity(unwrapped.len()); fn frame_time(frame: &Frame) -> f32 { frame.parameters.frame_time } - let repeat_first_view = iter::repeat(( - frame_time(&frames[0]), - unwrapped_pitches[0], - unwrapped_yaws[0], - )); - let repeat_last_view = iter::repeat(( + let repeat_first = iter::repeat((frame_time(&frames[0]), unwrapped[0])); + let repeat_last = iter::repeat(( frame_time(frames.last().unwrap()), - *unwrapped_pitches.last().unwrap(), - *unwrapped_yaws.last().unwrap(), + *unwrapped.last().unwrap(), )); // The smoothing window is centered at the center of each yaw. // For pitch smoothing, every frame has both pitch and yaw so iterate over this is ok. - for i in 0..unwrapped_yaws.len() { - let mut total_yaw = 0.; - let mut total_pitch = 0.; + for i in 0..unwrapped.len() { + let mut total_view = 0.; let mut total_weight = 0.; let mut process_frame = - |(mut rem_win_size, mut rem_small_win_size), - (mut frame_time, pitch, yaw): (f32, f32, f32)| { + |(mut rem_win_size, mut rem_small_win_size), (mut frame_time, view): (f32, f32)| { // If there's any small window zone left to cover, do so. if rem_small_win_size > 0. { let dt = frame_time.min(rem_small_win_size); let weight = dt * small_window_multiplier; - total_yaw += yaw * weight; - total_pitch += pitch * weight; + total_view += view * weight; total_weight += weight; rem_win_size -= dt; @@ -4643,8 +4659,7 @@ fn smoothed_views( let dt = frame_time.min(rem_win_size); let weight = dt; - total_yaw += yaw * weight; - total_pitch += pitch * weight; + total_view += view * weight; total_weight += weight; rem_win_size -= dt; @@ -4663,41 +4678,34 @@ fn smoothed_views( let rem_small_win_size = small_window_size / 2.; // Start from the middle frame. - let middle_frame_half = iter::once(( - frames[i].parameters.frame_time / 2., - unwrapped_pitches[i], - unwrapped_yaws[i], - )); + let middle_frame_half = iter::once((frames[i].parameters.frame_time / 2., unwrapped[i])); // Walk back half an interval. middle_frame_half .clone() .chain( - izip!( + zip( frames[..i].iter().map(frame_time), - unwrapped_pitches[..i].iter().copied(), - unwrapped_yaws[..i].iter().copied(), + unwrapped[..i].iter().copied(), ) .rev(), ) - .chain(repeat_first_view.clone()) + .chain(repeat_first.clone()) .try_fold((rem_win_size, rem_small_win_size), &mut process_frame); // Walk forward half an interval. middle_frame_half .chain(izip!( frames[i + 1..].iter().map(frame_time), - unwrapped_pitches[i + 1..].iter().copied(), - unwrapped_yaws[i + 1..].iter().copied(), + unwrapped[i + 1..].iter().copied(), )) - .chain(repeat_last_view.clone()) + .chain(repeat_last.clone()) .try_fold((rem_win_size, rem_small_win_size), &mut process_frame); - rv_yaws.push(total_yaw / total_weight); - rv_pitches.push(total_pitch / total_weight); + rv.push(total_view / total_weight); } - (rv_pitches, rv_yaws) + rv } fn replace_multiple_params<'a>( @@ -4960,7 +4968,8 @@ mod tests { }) .collect(); - let smoothed = smoothed_views(1., small_window_size, 4., &frames).1; + let yaws = frames.iter().map(|f| f.state.prev_frame_input.yaw); + let smoothed = smoothed_views(1., small_window_size, 4., &frames, yaws); expect.assert_debug_eq(&smoothed); } From 15fbcc1b23402dbf738f9f4cbeb706b1022c6929 Mon Sep 17 00:00:00 2001 From: khang Date: Thu, 11 Jul 2024 19:31:18 -0400 Subject: [PATCH 4/4] changes suggested --- src/modules/tas_studio/editor/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/tas_studio/editor/mod.rs b/src/modules/tas_studio/editor/mod.rs index 0188c40..bd7ff7e 100644 --- a/src/modules/tas_studio/editor/mod.rs +++ b/src/modules/tas_studio/editor/mod.rs @@ -15,7 +15,7 @@ use hltas::types::{ VectorialStrafingConstraints, }; use hltas::HLTAS; -use itertools::{izip, Itertools}; +use itertools::Itertools; use thiserror::Error; use self::db::{Action, ActionKind, Branch, Db}; @@ -4695,7 +4695,7 @@ fn smoothed_views( // Walk forward half an interval. middle_frame_half - .chain(izip!( + .chain(zip( frames[i + 1..].iter().map(frame_time), unwrapped[i + 1..].iter().copied(), ))