seeker + make slider nodes red

This commit is contained in:
Michael Zhang 2021-01-09 16:33:08 -06:00
parent a21bdbcafe
commit dad5f77816
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
4 changed files with 190 additions and 118 deletions

View file

@ -69,6 +69,14 @@ impl Sound {
self.handle self.handle
} }
pub fn length(&self) -> Result<f64> {
let length = unsafe {
let bytes = bass::BASS_ChannelGetLength(self.handle, BASS_POS_BYTE);
bass::BASS_ChannelBytes2Seconds(self.handle, bytes)
};
Ok(length)
}
pub fn position(&self) -> Result<f64> { pub fn position(&self) -> Result<f64> {
let time = unsafe { let time = unsafe {
let pos_bytes = bass::BASS_ChannelGetPosition(self.handle, BASS_POS_BYTE); let pos_bytes = bass::BASS_ChannelGetPosition(self.handle, BASS_POS_BYTE);

View file

@ -1,4 +1,5 @@
mod grid; mod grid;
mod seeker;
mod sliders; mod sliders;
mod timeline; mod timeline;
@ -25,10 +26,7 @@ use crate::beatmap::{BeatmapExt, STACK_DISTANCE};
use crate::hitobject::HitObjectExt; use crate::hitobject::HitObjectExt;
use crate::skin::Skin; use crate::skin::Skin;
use self::sliders::render_slider;
pub const PLAYFIELD_BOUNDS: Rect = Rect::new(112.0, 112.0, 800.0, 600.0); pub const PLAYFIELD_BOUNDS: Rect = Rect::new(112.0, 112.0, 800.0, 600.0);
pub const SEEKER_BOUNDS: Rect = Rect::new(46.0, 722.0, 932.0, 36.0);
pub type SliderCache = HashMap<Vec<Point<i32>>, Spline>; pub type SliderCache = HashMap<Vec<Point<i32>>, Spline>;
@ -185,17 +183,22 @@ impl Game {
let mut slider_info = None; let mut slider_info = None;
if let HitObjectKind::Slider(info) = &ho.inner.kind { if let HitObjectKind::Slider(info) = &ho.inner.kind {
let mut control_points = vec![ho.inner.pos];
control_points.extend(&info.control_points);
let mut color = color.clone(); let mut color = color.clone();
color.a = 0.6 * draw_info.opacity as f32; color.a = 0.6 * draw_info.opacity as f32;
let spline = render_slider( let spline = Game::render_slider(
&mut self.slider_cache, &mut self.slider_cache,
info,
control_points.as_ref(),
ctx, ctx,
PLAYFIELD_BOUNDS, PLAYFIELD_BOUNDS,
&self.beatmap.inner, &self.beatmap.inner,
&ho.inner, &ho.inner,
color, color,
)?; )?;
slider_info = Some((info, spline)); slider_info = Some((info, control_points, spline));
let end_pos = ho.inner.end_pos().unwrap(); let end_pos = ho.inner.end_pos().unwrap();
let end_pos = [ let end_pos = [
@ -225,7 +228,9 @@ impl Game {
DrawParam::default().dest(pos), DrawParam::default().dest(pos),
)?; )?;
if let Some((info, spline)) = slider_info { if let Some((info, control_points, spline)) = slider_info {
Game::render_slider_wireframe(ctx, &control_points, PLAYFIELD_BOUNDS)?;
if time > ho_time && time < draw_info.end_time { if time > ho_time && time < draw_info.end_time {
let elapsed_time = time - ho_time; let elapsed_time = time - ho_time;
let total_duration = draw_info.end_time - ho_time; let total_duration = draw_info.end_time - ho_time;
@ -263,6 +268,8 @@ impl Game {
} }
} }
self.draw_seeker(ctx)?;
graphics::present(ctx)?; graphics::present(ctx)?;
self.frame += 1; self.frame += 1;
Ok(()) Ok(())

42
src/game/seeker.rs Normal file
View file

@ -0,0 +1,42 @@
use anyhow::Result;
use ggez::{
graphics::{self, DrawParam, Mesh, Rect},
nalgebra::Point2,
Context,
};
use super::Game;
pub const BOUNDS: Rect = Rect::new(46.0, 722.0, 932.0, 36.0);
impl Game {
pub(super) fn draw_seeker(&self, ctx: &mut Context) -> Result<()> {
let line_y = BOUNDS.y + BOUNDS.h / 2.0;
let line = Mesh::new_line(
ctx,
&[
Point2::new(BOUNDS.x, line_y),
Point2::new(BOUNDS.x + BOUNDS.w, line_y),
],
1.0,
graphics::WHITE,
)?;
graphics::draw(ctx, &line, DrawParam::default())?;
if let Some(song) = &self.song {
let percent = song.position()? / song.length()?;
let x = BOUNDS.x + percent as f32 * BOUNDS.w;
let line = Mesh::new_line(
ctx,
&[
Point2::new(x, BOUNDS.y + 0.2 * BOUNDS.h),
Point2::new(x, BOUNDS.y + 0.8 * BOUNDS.h),
],
4.0,
graphics::WHITE,
)?;
graphics::draw(ctx, &line, DrawParam::default())?;
}
Ok(())
}
}

View file

@ -1,6 +1,5 @@
use anyhow::Result; use anyhow::Result;
use ggez::{ use ggez::{
conf::NumSamples,
graphics::{ graphics::{
self, Canvas, Color, DrawMode, DrawParam, FillOptions, LineCap, LineJoin, Mesh, Rect, self, Canvas, Color, DrawMode, DrawParam, FillOptions, LineCap, LineJoin, Mesh, Rect,
StrokeOptions, StrokeOptions,
@ -10,34 +9,31 @@ use ggez::{
}; };
use libosu::{ use libosu::{
beatmap::Beatmap, beatmap::Beatmap,
hitobject::{HitObject, HitObjectKind}, hitobject::{HitObject, SliderInfo},
math::Point,
spline::Spline, spline::Spline,
}; };
use crate::game::SliderCache; use super::{Game, SliderCache};
impl Game {
pub fn render_slider<'a>( pub fn render_slider<'a>(
slider_cache: &'a mut SliderCache, slider_cache: &'a mut SliderCache,
slider_info: &SliderInfo,
control_points: &[Point<i32>],
ctx: &mut Context, ctx: &mut Context,
rect: Rect, rect: Rect,
beatmap: &Beatmap, beatmap: &Beatmap,
slider: &HitObject, slider: &HitObject,
color: Color, color: Color,
) -> Result<&'a Spline> { ) -> Result<&'a Spline> {
let mut control_points = vec![slider.pos]; let spline = if slider_cache.contains_key(control_points) {
let slider_info = match &slider.kind { slider_cache.get(control_points).unwrap()
HitObjectKind::Slider(info) => info,
_ => unreachable!("retard"),
};
control_points.extend(&slider_info.control_points);
let spline = if slider_cache.contains_key(&control_points) {
slider_cache.get(&control_points).unwrap()
} else { } else {
let new_spline = let new_spline =
Spline::from_control(slider_info.kind, &control_points, slider_info.pixel_length); Spline::from_control(slider_info.kind, control_points, slider_info.pixel_length);
slider_cache.insert(control_points.clone(), new_spline); slider_cache.insert(control_points.to_vec(), new_spline);
slider_cache.get(&control_points).unwrap() slider_cache.get(control_points).unwrap()
}; };
let cs_scale = rect.w / 640.0; let cs_scale = rect.w / 640.0;
@ -46,16 +42,6 @@ pub fn render_slider<'a>(
let cs_osupx = beatmap.difficulty.circle_size_osupx() as f64; let cs_osupx = beatmap.difficulty.circle_size_osupx() as f64;
let cs_real = cs_osupx * cs_scale as f64; let cs_real = cs_osupx * cs_scale as f64;
let points_mapped = control_points
.iter()
.map(|point| {
let (x, y) = (point.0 as f64, point.1 as f64);
let x2 = rect.x as f64 + osupx_scale_x * x;
let y2 = rect.y as f64 + osupx_scale_y * y;
[x2 as f32, y2 as f32].into()
})
.collect::<Vec<Point2<_>>>();
let (mut boundx, mut boundy, mut boundw, mut boundh) = (f64::MAX, f64::MAX, 0.0f64, 0.0f64); let (mut boundx, mut boundy, mut boundw, mut boundh) = (f64::MAX, f64::MAX, 0.0f64, 0.0f64);
let spline_mapped = spline let spline_mapped = spline
.spline_points .spline_points
@ -110,6 +96,27 @@ pub fn render_slider<'a>(
graphics::set_canvas(ctx, None); graphics::set_canvas(ctx, None);
graphics::draw(ctx, &canvas, DrawParam::default().color(color))?; graphics::draw(ctx, &canvas, DrawParam::default().color(color))?;
Ok(spline)
}
pub fn render_slider_wireframe(
ctx: &mut Context,
control_points: &[Point<i32>],
rect: Rect,
) -> Result<()> {
let osupx_scale_x = rect.w as f64 / 512.0;
let osupx_scale_y = rect.h as f64 / 384.0;
let points_mapped = control_points
.iter()
.map(|point| {
let (x, y) = (point.0 as f64, point.1 as f64);
let x2 = rect.x as f64 + osupx_scale_x * x;
let y2 = rect.y as f64 + osupx_scale_y * y;
[x2 as f32, y2 as f32].into()
})
.collect::<Vec<Point2<_>>>();
// draw control points wireframe // draw control points wireframe
let frame = Mesh::new_polyline( let frame = Mesh::new_polyline(
ctx, ctx,
@ -120,17 +127,25 @@ pub fn render_slider<'a>(
graphics::draw(ctx, &frame, DrawParam::default())?; graphics::draw(ctx, &frame, DrawParam::default())?;
// draw points on wireframe // draw points on wireframe
for point in points_mapped { let mut i = 0;
while i < points_mapped.len() {
let fst = points_mapped[i];
let mut color = graphics::WHITE;
if i < points_mapped.len() - 1 {
let snd = points_mapped[i + 1];
if fst.eq(&snd) {
i += 1;
color = Color::new(1.0, 0.0, 0.0, 1.0);
}
}
let size = 5.0; let size = 5.0;
let rect = Rect::new(point.x - size, point.y - size, size * 2.0, size * 2.0); let rect = Rect::new(fst.x - size, fst.y - size, size * 2.0, size * 2.0);
let rect = Mesh::new_rectangle( let rect =
ctx, Mesh::new_rectangle(ctx, DrawMode::Fill(FillOptions::default()), rect, color)?;
DrawMode::Fill(FillOptions::default()),
rect,
graphics::WHITE,
)?;
graphics::draw(ctx, &rect, DrawParam::default())?; graphics::draw(ctx, &rect, DrawParam::default())?;
i += 1;
} }
Ok(spline) Ok(())
}
} }