rewrote slider processing & fixed catmull
This commit is contained in:
+7
-3
@@ -243,6 +243,10 @@ impl Curve {
|
||||
}
|
||||
|
||||
fn approximate_catmull(path: &mut Vec<Pos2>, points: &[Pos2]) {
|
||||
if points.len() == 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
path.reserve_exact((points.len() - 1) * CATMULL_DETAIL * 2);
|
||||
|
||||
// Handle first iteration distinctly because of v1
|
||||
@@ -254,7 +258,7 @@ impl Curve {
|
||||
Self::catmull_subpath(path, v1, v2, v3, v4);
|
||||
|
||||
// Remaining iterations
|
||||
for (i, (&v1, &v2)) in (2..).zip(points.iter().zip(points.iter().skip(1))) {
|
||||
for (i, (&v1, &v2)) in (2..points.len()).zip(points.iter().zip(points.iter().skip(1))) {
|
||||
let v3 = points.get(i).copied().unwrap_or_else(|| v2 * 2.0 - v1);
|
||||
let v4 = points.get(i + 1).copied().unwrap_or_else(|| v3 * 2.0 - v2);
|
||||
|
||||
@@ -421,12 +425,12 @@ impl Curve {
|
||||
}
|
||||
|
||||
fn catmull_subpath(path: &mut Vec<Pos2>, v1: Pos2, v2: Pos2, v3: Pos2, v4: Pos2) {
|
||||
let x1 = 2.0 * v1.x;
|
||||
let x1 = 2.0 * v2.x;
|
||||
let x2 = -v1.x + v3.x;
|
||||
let x3 = 2.0 * v1.x - 5.0 * v2.x + 4.0 * v3.x - v4.x;
|
||||
let x4 = -v1.x + 3.0 * (v2.x - v3.x) + v4.x;
|
||||
|
||||
let y1 = 2.0 * v1.y;
|
||||
let y1 = 2.0 * v2.y;
|
||||
let y2 = -v1.y + v3.y;
|
||||
let y3 = 2.0 * v1.y - 5.0 * v2.y + 4.0 * v3.y - v4.y;
|
||||
let y4 = -v1.y + 3.0 * (v2.y - v3.y) + v4.y;
|
||||
|
||||
+2
-2
@@ -54,7 +54,7 @@ fn custom_osu() {
|
||||
|
||||
use crate::{Beatmap, OsuPP};
|
||||
|
||||
let path = "E:Games/osu!/beatmaps/156352_.osu";
|
||||
let path = "E:Games/osu!/beatmaps/70090.osu";
|
||||
let file = File::open(path).unwrap();
|
||||
|
||||
let start = Instant::now();
|
||||
@@ -76,7 +76,7 @@ fn custom_osu() {
|
||||
println!("Parsing average: {:?}", accum / iters);
|
||||
|
||||
let start = Instant::now();
|
||||
let result = OsuPP::new(&map).mods(1024).calculate();
|
||||
let result = OsuPP::new(&map).mods(8 + 16 + 64).calculate();
|
||||
|
||||
let iters = 100;
|
||||
let accum = start.elapsed();
|
||||
|
||||
@@ -84,7 +84,7 @@ pub fn stars(
|
||||
map,
|
||||
radius,
|
||||
scaling_factor,
|
||||
attributes: &mut diff_attributes,
|
||||
max_combo: &mut diff_attributes.max_combo,
|
||||
slider_state: SliderState::new(map),
|
||||
ticks: Vec::new(),
|
||||
curve_bufs: CurveBuffers::default(),
|
||||
@@ -292,7 +292,7 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
|
||||
map,
|
||||
radius,
|
||||
scaling_factor,
|
||||
attributes: &mut diff_attributes,
|
||||
max_combo: &mut diff_attributes.max_combo,
|
||||
slider_state: SliderState::new(map),
|
||||
ticks: Vec::new(),
|
||||
curve_bufs: CurveBuffers::default(),
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use super::super::super::DifficultyAttributes;
|
||||
use super::slider_state::SliderState;
|
||||
|
||||
use crate::{
|
||||
@@ -34,7 +33,7 @@ pub(crate) struct ObjectParameters<'a> {
|
||||
pub(crate) map: &'a Beatmap,
|
||||
pub(crate) radius: f32,
|
||||
pub(crate) scaling_factor: f32,
|
||||
pub(crate) attributes: &'a mut DifficultyAttributes,
|
||||
pub(crate) max_combo: &'a mut usize,
|
||||
pub(crate) ticks: Vec<f32>,
|
||||
pub(crate) slider_state: SliderState<'a>,
|
||||
pub(crate) curve_bufs: CurveBuffers,
|
||||
@@ -47,13 +46,13 @@ impl OsuObject {
|
||||
map,
|
||||
radius,
|
||||
scaling_factor,
|
||||
attributes,
|
||||
max_combo,
|
||||
ticks,
|
||||
slider_state,
|
||||
curve_bufs,
|
||||
} = params;
|
||||
|
||||
attributes.max_combo += 1; // hitcircle, slider head, or spinner
|
||||
**max_combo += 1; // hitcircle, slider head, or spinner
|
||||
let mut pos = h.pos;
|
||||
|
||||
if hr {
|
||||
@@ -103,10 +102,8 @@ impl OsuObject {
|
||||
// Called on each slider object except for the head.
|
||||
// Increases combo and adjusts `end_pos` and `travel_dist`
|
||||
// w.r.t. the object position at the given time on the slider curve.
|
||||
let mut compute_vertex = |time: f32| {
|
||||
attributes.max_combo += 1;
|
||||
|
||||
let mut progress = (time - h.start_time) / span_duration;
|
||||
let mut compute_vertex = |mut progress: f32| {
|
||||
**max_combo += 1;
|
||||
|
||||
if progress % 2.0 >= 1.0 {
|
||||
progress = 1.0 - progress % 1.0;
|
||||
@@ -114,7 +111,6 @@ impl OsuObject {
|
||||
progress %= 1.0;
|
||||
}
|
||||
|
||||
// TODO: Correct addition?
|
||||
let mut curr_pos = h.pos + curve.position_at(progress);
|
||||
|
||||
if hr {
|
||||
@@ -132,53 +128,60 @@ impl OsuObject {
|
||||
}
|
||||
};
|
||||
|
||||
let mut current_distance = tick_dist;
|
||||
let time_add = duration * (tick_dist / (pixel_len * span_count));
|
||||
// * A very lenient maximum length of a slider for ticks to be generated.
|
||||
// * This exists for edge cases such as /b/1573664 where the beatmap has
|
||||
// * been edited by the user, and should never be reached in normal usage.
|
||||
let max_len = 100_000.0;
|
||||
|
||||
let target = pixel_len - tick_dist / 8.0;
|
||||
ticks.reserve((target / tick_dist) as usize);
|
||||
let len = curve.dist().min(max_len);
|
||||
tick_dist = tick_dist.clamp(0.0, len);
|
||||
let min_dist_from_end = velocity * 10.0;
|
||||
|
||||
let mut curr_dist = tick_dist;
|
||||
|
||||
ticks.clear();
|
||||
ticks.reserve((len / tick_dist) as usize);
|
||||
|
||||
// Tick of the first span
|
||||
if current_distance < target {
|
||||
for tick_idx in 1.. {
|
||||
let time = h.start_time + time_add * tick_idx as f32;
|
||||
compute_vertex(time);
|
||||
ticks.push(time);
|
||||
current_distance += tick_dist;
|
||||
while curr_dist < len - min_dist_from_end {
|
||||
let progress = curr_dist / len;
|
||||
|
||||
if current_distance >= target {
|
||||
break;
|
||||
}
|
||||
}
|
||||
compute_vertex(progress);
|
||||
ticks.push(progress);
|
||||
|
||||
curr_dist += tick_dist;
|
||||
}
|
||||
|
||||
// Other spans
|
||||
if *repeats > 1 {
|
||||
for repeat_id in 1..*repeats {
|
||||
let time_offset = (duration / *repeats as f32) * repeat_id as f32;
|
||||
for span_idx in 1..=*repeats {
|
||||
let progress = (span_idx % 2 == 1) as u8 as f32;
|
||||
|
||||
// Reverse tick
|
||||
compute_vertex(h.start_time + time_offset);
|
||||
// Reverse tick
|
||||
compute_vertex(progress);
|
||||
|
||||
// Actual ticks
|
||||
if repeat_id & 1 == 1 {
|
||||
ticks.iter().rev().for_each(|&time| compute_vertex(time));
|
||||
} else {
|
||||
ticks.iter().for_each(|&time| compute_vertex(time));
|
||||
}
|
||||
// Actual ticks
|
||||
if span_idx & 1 == 1 {
|
||||
ticks
|
||||
.iter()
|
||||
.rev()
|
||||
.for_each(|&tick_progress| compute_vertex(tick_progress + progress));
|
||||
} else {
|
||||
ticks
|
||||
.iter()
|
||||
.for_each(|&tick_progress| compute_vertex(tick_progress + progress));
|
||||
}
|
||||
}
|
||||
|
||||
// Slider tail
|
||||
let final_span_idx = repeats.saturating_sub(1);
|
||||
let final_span_start_time = h.start_time + final_span_idx as f32 * span_duration;
|
||||
let final_span_start_time = h.start_time + *repeats as f32 * span_duration;
|
||||
let final_span_end_time = (h.start_time + duration / 2.0)
|
||||
.max(final_span_start_time + span_duration - LEGACY_LAST_TICK_OFFSET);
|
||||
compute_vertex(final_span_end_time);
|
||||
let progress = (*repeats % 2 == 1) as u8 as f32;
|
||||
let final_progress =
|
||||
(final_span_end_time - final_span_start_time) / span_duration + progress;
|
||||
|
||||
ticks.clear();
|
||||
compute_vertex(final_progress);
|
||||
|
||||
let progress = (*repeats % 2 == 0) as u8 as f32;
|
||||
let mut end_pos = h.pos + curve.position_at(progress);
|
||||
travel_dist *= *scaling_factor;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user