re-use bezier buffers for all sliders
This commit is contained in:
+51
-19
@@ -11,6 +11,13 @@ const BEZIER_TOLERANCE: f32 = 0.25;
|
||||
const CATMULL_DETAIL: usize = 50;
|
||||
const CIRCULAR_ARC_TOLERANCE: f32 = 0.1;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct CurveBuffers {
|
||||
vertices: Vec<Pos2>,
|
||||
bezier: BezierBuffers,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct BezierBuffers {
|
||||
buf1: Vec<Pos2>,
|
||||
buf2: Vec<Pos2>,
|
||||
@@ -18,12 +25,22 @@ struct BezierBuffers {
|
||||
}
|
||||
|
||||
impl BezierBuffers {
|
||||
fn new(len: usize) -> Self {
|
||||
Self {
|
||||
buf1: vec![Pos2::zero(); len],
|
||||
buf2: vec![Pos2::zero(); len],
|
||||
buf3: vec![Pos2::zero(); len],
|
||||
/// Fill the buffers with new elements until a
|
||||
/// length of `len` is reached. Does nothing if `len`
|
||||
/// is already smaller than the current buffer size.
|
||||
fn extend_exact(&mut self, len: usize) {
|
||||
if len <= self.buf1.len() {
|
||||
return;
|
||||
}
|
||||
|
||||
let additional = len - self.buf1.len();
|
||||
|
||||
self.buf1
|
||||
.extend(iter::repeat(Pos2::zero()).take(additional));
|
||||
self.buf2
|
||||
.extend(iter::repeat(Pos2::zero()).take(additional));
|
||||
self.buf3
|
||||
.extend(iter::repeat(Pos2::zero()).take(additional));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +58,12 @@ pub(crate) struct Curve {
|
||||
}
|
||||
|
||||
impl Curve {
|
||||
pub(crate) fn new(points: &[PathControlPoint], expected_len: f32, buf: &mut Vec<Pos2>) -> Self {
|
||||
let mut path = Self::calculate_path(points, buf);
|
||||
pub(crate) fn new(
|
||||
points: &[PathControlPoint],
|
||||
expected_len: f32,
|
||||
bufs: &mut CurveBuffers,
|
||||
) -> Self {
|
||||
let mut path = Self::calculate_path(points, bufs);
|
||||
let lengths = Self::calculate_length(points, &mut path, expected_len);
|
||||
|
||||
Self { path, lengths }
|
||||
@@ -98,11 +119,13 @@ impl Curve {
|
||||
p0 + (p1 - p0) * w
|
||||
}
|
||||
|
||||
fn calculate_path(points: &[PathControlPoint], vertices: &mut Vec<Pos2>) -> Vec<Pos2> {
|
||||
fn calculate_path(points: &[PathControlPoint], bufs: &mut CurveBuffers) -> Vec<Pos2> {
|
||||
if points.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let CurveBuffers { vertices, bezier } = bufs;
|
||||
|
||||
vertices.clear();
|
||||
vertices.extend(points.iter().map(|p| p.pos));
|
||||
|
||||
@@ -118,7 +141,7 @@ impl Curve {
|
||||
let segment_vertices = &vertices[start..i + 1];
|
||||
let segment_kind = points[start].kind.unwrap_or(PathType::Linear);
|
||||
|
||||
Self::calculate_subpath(&mut path, segment_vertices, segment_kind);
|
||||
Self::calculate_subpath(&mut path, segment_vertices, segment_kind, bezier);
|
||||
|
||||
// * Start the new segment at the current vertex
|
||||
start = i;
|
||||
@@ -194,25 +217,32 @@ impl Curve {
|
||||
cumulative_len
|
||||
}
|
||||
|
||||
fn calculate_subpath(path: &mut Vec<Pos2>, sub_points: &[Pos2], kind: PathType) {
|
||||
fn calculate_subpath(
|
||||
path: &mut Vec<Pos2>,
|
||||
sub_points: &[Pos2],
|
||||
kind: PathType,
|
||||
bufs: &mut BezierBuffers,
|
||||
) {
|
||||
match kind {
|
||||
PathType::Bezier => Self::approximate_bezier(path, sub_points),
|
||||
PathType::Bezier => Self::approximate_bezier(path, sub_points, bufs),
|
||||
PathType::Catmull => Self::approximate_catmull(path, sub_points),
|
||||
PathType::Linear => Self::approximate_linear(path, sub_points),
|
||||
PathType::PerfectCurve => {
|
||||
if let [a, b, c] = sub_points {
|
||||
Self::approximate_circular_arc(path, *a, *b, *c)
|
||||
} else {
|
||||
Self::approximate_bezier(path, sub_points)
|
||||
if Self::approximate_circular_arc(path, *a, *b, *c) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Self::approximate_bezier(path, sub_points, bufs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn approximate_bezier(path: &mut Vec<Pos2>, points: &[Pos2]) {
|
||||
let mut bufs = BezierBuffers::new(points.len()); // TODO: argument?
|
||||
fn approximate_bezier(path: &mut Vec<Pos2>, points: &[Pos2], bufs: &mut BezierBuffers) {
|
||||
bufs.extend_exact(points.len());
|
||||
|
||||
Self::approximate_bspline(path, points, &mut bufs);
|
||||
Self::approximate_bspline(path, points, bufs);
|
||||
}
|
||||
|
||||
fn approximate_catmull(path: &mut Vec<Pos2>, points: &[Pos2]) {
|
||||
@@ -239,10 +269,10 @@ impl Curve {
|
||||
path.extend(points)
|
||||
}
|
||||
|
||||
fn approximate_circular_arc(path: &mut Vec<Pos2>, a: Pos2, b: Pos2, c: Pos2) {
|
||||
fn approximate_circular_arc(path: &mut Vec<Pos2>, a: Pos2, b: Pos2, c: Pos2) -> bool {
|
||||
let pr = match Self::circular_arc_properties(a, b, c) {
|
||||
Some(pr) => pr,
|
||||
None => return Self::approximate_bezier(path, &[a, b, c]),
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// * We select the amount of points for the approximation by requiring the discrete curvature
|
||||
@@ -272,6 +302,8 @@ impl Curve {
|
||||
});
|
||||
|
||||
path.extend(subpath);
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn approximate_bspline(path: &mut Vec<Pos2>, points: &[Pos2], bufs: &mut BezierBuffers) {
|
||||
|
||||
+5
-5
@@ -13,7 +13,7 @@ pub use pp::*;
|
||||
use slider_state::SliderState;
|
||||
|
||||
use crate::{
|
||||
curve::Curve,
|
||||
curve::{Curve, CurveBuffers},
|
||||
parse::{HitObjectKind, Pos2},
|
||||
Beatmap, Mods, Strains,
|
||||
};
|
||||
@@ -45,7 +45,7 @@ pub fn stars(
|
||||
let with_hr = mods.hr();
|
||||
let mut ticks = Vec::new(); // using the same buffer for all sliders
|
||||
let mut slider_state = SliderState::new(map);
|
||||
let mut curve_buf = Vec::new();
|
||||
let mut curve_bufs = CurveBuffers::default();
|
||||
|
||||
let mut fruits = 0;
|
||||
let mut droplets = 0;
|
||||
@@ -94,7 +94,7 @@ pub fn stars(
|
||||
/ 100.0;
|
||||
|
||||
// Build the curve w.r.t. the curve points
|
||||
let curve = Curve::new(control_points, *pixel_len, &mut curve_buf);
|
||||
let curve = Curve::new(control_points, *pixel_len, &mut curve_bufs);
|
||||
|
||||
let mut current_distance = tick_distance;
|
||||
let time_add = duration * (tick_distance / (*pixel_len * *repeats as f32));
|
||||
@@ -286,7 +286,7 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
|
||||
let with_hr = mods.hr();
|
||||
let mut ticks = Vec::new(); // using the same buffer for all sliders
|
||||
let mut slider_state = SliderState::new(map);
|
||||
let mut curve_buf = Vec::new();
|
||||
let mut curve_bufs = CurveBuffers::default();
|
||||
|
||||
// BUG: Incorrect object order on 2B maps that have fruits within sliders
|
||||
let mut hit_objects = map
|
||||
@@ -329,7 +329,7 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
|
||||
/ 100.0;
|
||||
|
||||
// Build the curve w.r.t. the curve points
|
||||
let curve = Curve::new(control_points, *pixel_len, &mut curve_buf);
|
||||
let curve = Curve::new(control_points, *pixel_len, &mut curve_bufs);
|
||||
|
||||
let mut current_distance = tick_distance;
|
||||
let time_add = duration * (tick_distance / (*pixel_len * *repeats as f32));
|
||||
|
||||
@@ -21,7 +21,7 @@ use skill::Skill;
|
||||
use skill_kind::SkillKind;
|
||||
use slider_state::SliderState;
|
||||
|
||||
use crate::{Beatmap, Mods, Strains};
|
||||
use crate::{curve::CurveBuffers, Beatmap, Mods, Strains};
|
||||
|
||||
const OBJECT_RADIUS: f32 = 64.0;
|
||||
const SECTION_LEN: f32 = 400.0;
|
||||
@@ -68,7 +68,7 @@ pub fn stars(
|
||||
}
|
||||
|
||||
let mut slider_state = SliderState::new(map);
|
||||
let mut curve_buf = Vec::new();
|
||||
let mut curve_bufs = CurveBuffers::default();
|
||||
let mut ticks_buf = Vec::new();
|
||||
|
||||
let mut hit_objects = map
|
||||
@@ -84,7 +84,7 @@ pub fn stars(
|
||||
&mut ticks_buf,
|
||||
&mut diff_attributes,
|
||||
&mut slider_state,
|
||||
&mut curve_buf,
|
||||
&mut curve_bufs,
|
||||
)
|
||||
})
|
||||
.map(|mut h| {
|
||||
@@ -241,7 +241,7 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
|
||||
|
||||
let mut slider_state = SliderState::new(map);
|
||||
let mut ticks_buf = Vec::new();
|
||||
let mut curve_buf = Vec::new();
|
||||
let mut curve_bufs = CurveBuffers::default();
|
||||
|
||||
let mut hit_objects = map.hit_objects.iter().filter_map(|h| {
|
||||
OsuObject::new(
|
||||
@@ -252,7 +252,7 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
|
||||
&mut ticks_buf,
|
||||
&mut diff_attributes,
|
||||
&mut slider_state,
|
||||
&mut curve_buf,
|
||||
&mut curve_bufs,
|
||||
)
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::super::super::DifficultyAttributes;
|
||||
use super::slider_state::SliderState;
|
||||
|
||||
use crate::{
|
||||
curve::Curve,
|
||||
curve::{Curve, CurveBuffers},
|
||||
parse::{HitObject, HitObjectKind, Pos2},
|
||||
Beatmap,
|
||||
};
|
||||
@@ -35,7 +35,7 @@ impl OsuObject {
|
||||
ticks: &mut Vec<f32>,
|
||||
attributes: &mut DifficultyAttributes,
|
||||
slider_state: &mut SliderState,
|
||||
slider_buf: &mut Vec<Pos2>,
|
||||
curve_bufs: &mut CurveBuffers,
|
||||
) -> Option<Self> {
|
||||
attributes.max_combo += 1; // hitcircle, slider head, or spinner
|
||||
|
||||
@@ -68,7 +68,7 @@ impl OsuObject {
|
||||
}
|
||||
|
||||
// Build the curve w.r.t. the curve points
|
||||
let curve = Curve::new(control_points, *pixel_len, slider_buf);
|
||||
let curve = Curve::new(control_points, *pixel_len, curve_bufs);
|
||||
|
||||
let velocity =
|
||||
(BASE_SCORING_DISTANCE * map.slider_mult * slider_state.slider_velocity)
|
||||
|
||||
Reference in New Issue
Block a user