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