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
}
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> {
let time = unsafe {
let pos_bytes = bass::BASS_ChannelGetPosition(self.handle, BASS_POS_BYTE);

View file

@ -1,4 +1,5 @@
mod grid;
mod seeker;
mod sliders;
mod timeline;
@ -25,10 +26,7 @@ use crate::beatmap::{BeatmapExt, STACK_DISTANCE};
use crate::hitobject::HitObjectExt;
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 SEEKER_BOUNDS: Rect = Rect::new(46.0, 722.0, 932.0, 36.0);
pub type SliderCache = HashMap<Vec<Point<i32>>, Spline>;
@ -185,17 +183,22 @@ impl Game {
let mut slider_info = None;
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();
color.a = 0.6 * draw_info.opacity as f32;
let spline = render_slider(
let spline = Game::render_slider(
&mut self.slider_cache,
info,
control_points.as_ref(),
ctx,
PLAYFIELD_BOUNDS,
&self.beatmap.inner,
&ho.inner,
color,
)?;
slider_info = Some((info, spline));
slider_info = Some((info, control_points, spline));
let end_pos = ho.inner.end_pos().unwrap();
let end_pos = [
@ -225,7 +228,9 @@ impl Game {
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 {
let elapsed_time = 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)?;
self.frame += 1;
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 ggez::{
conf::NumSamples,
graphics::{
self, Canvas, Color, DrawMode, DrawParam, FillOptions, LineCap, LineJoin, Mesh, Rect,
StrokeOptions,
@ -10,127 +9,143 @@ use ggez::{
};
use libosu::{
beatmap::Beatmap,
hitobject::{HitObject, HitObjectKind},
hitobject::{HitObject, SliderInfo},
math::Point,
spline::Spline,
};
use crate::game::SliderCache;
use super::{Game, SliderCache};
pub fn render_slider<'a>(
slider_cache: &'a mut SliderCache,
ctx: &mut Context,
rect: Rect,
beatmap: &Beatmap,
slider: &HitObject,
color: Color,
) -> Result<&'a Spline> {
let mut control_points = vec![slider.pos];
let slider_info = match &slider.kind {
HitObjectKind::Slider(info) => info,
_ => unreachable!("retard"),
};
control_points.extend(&slider_info.control_points);
impl Game {
pub fn render_slider<'a>(
slider_cache: &'a mut SliderCache,
slider_info: &SliderInfo,
control_points: &[Point<i32>],
ctx: &mut Context,
rect: Rect,
beatmap: &Beatmap,
slider: &HitObject,
color: Color,
) -> Result<&'a Spline> {
let spline = if slider_cache.contains_key(control_points) {
slider_cache.get(control_points).unwrap()
} else {
let new_spline =
Spline::from_control(slider_info.kind, control_points, slider_info.pixel_length);
slider_cache.insert(control_points.to_vec(), new_spline);
slider_cache.get(control_points).unwrap()
};
let spline = if slider_cache.contains_key(&control_points) {
slider_cache.get(&control_points).unwrap()
} else {
let new_spline =
Spline::from_control(slider_info.kind, &control_points, slider_info.pixel_length);
slider_cache.insert(control_points.clone(), new_spline);
slider_cache.get(&control_points).unwrap()
};
let cs_scale = rect.w / 640.0;
let osupx_scale_x = rect.w as f64 / 512.0;
let osupx_scale_y = rect.h as f64 / 384.0;
let cs_osupx = beatmap.difficulty.circle_size_osupx() as f64;
let cs_real = cs_osupx * cs_scale as f64;
let cs_scale = rect.w / 640.0;
let osupx_scale_x = rect.w as f64 / 512.0;
let osupx_scale_y = rect.h as f64 / 384.0;
let cs_osupx = beatmap.difficulty.circle_size_osupx() as f64;
let cs_real = cs_osupx * cs_scale as f64;
let (mut boundx, mut boundy, mut boundw, mut boundh) = (f64::MAX, f64::MAX, 0.0f64, 0.0f64);
let spline_mapped = spline
.spline_points
.iter()
.map(|point| {
let (x, y) = (point.0, point.1);
let x2 = rect.x as f64 + osupx_scale_x * x;
let y2 = rect.y as f64 + osupx_scale_y * y;
boundx = boundx.min(x2 - cs_osupx);
boundy = boundy.min(y2 - cs_osupx);
boundw = boundw.max(x2 + cs_osupx - boundx);
boundh = boundh.max(y2 + cs_osupx - boundy);
[x2 as f32, y2 as f32].into()
})
.collect::<Vec<Point2<f32>>>();
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 spline_mapped = spline
.spline_points
.iter()
.map(|point| {
let (x, y) = (point.0, point.1);
let x2 = rect.x as f64 + osupx_scale_x * x;
let y2 = rect.y as f64 + osupx_scale_y * y;
boundx = boundx.min(x2 - cs_osupx);
boundy = boundy.min(y2 - cs_osupx);
boundw = boundw.max(x2 + cs_osupx - boundx);
boundh = boundh.max(y2 + cs_osupx - boundy);
[x2 as f32, y2 as f32].into()
})
.collect::<Vec<Point2<f32>>>();
// draw slider border
let canvas = Canvas::with_window_size(ctx)?;
let opts = StrokeOptions::default()
.with_line_cap(LineCap::Round)
.with_line_join(LineJoin::Round)
.with_line_width(cs_real as f32 * 2.0);
let body = Mesh::new_polyline(
ctx,
DrawMode::Stroke(opts),
spline_mapped.as_ref(),
graphics::WHITE,
)?;
graphics::set_canvas(ctx, Some(&canvas));
graphics::clear(ctx, Color::new(0.0, 0.0, 0.0, 0.0));
graphics::draw(ctx, &body, DrawParam::default())?;
graphics::set_canvas(ctx, None);
let mut border_color = graphics::WHITE;
border_color.a = color.a;
graphics::draw(ctx, &canvas, DrawParam::default().color(border_color))?;
// draw slider body
let canvas = Canvas::with_window_size(ctx)?;
let opts = StrokeOptions::default()
.with_line_cap(LineCap::Round)
.with_line_join(LineJoin::Round)
.with_line_width(cs_real as f32 * 1.8);
let body = Mesh::new_polyline(
ctx,
DrawMode::Stroke(opts),
spline_mapped.as_ref(),
graphics::WHITE,
)?;
graphics::set_canvas(ctx, Some(&canvas));
graphics::clear(ctx, Color::new(0.0, 0.0, 0.0, 0.0));
graphics::draw(ctx, &body, DrawParam::default())?;
graphics::set_canvas(ctx, None);
graphics::draw(ctx, &canvas, DrawParam::default().color(color))?;
// draw control points wireframe
let frame = Mesh::new_polyline(
ctx,
DrawMode::Stroke(StrokeOptions::default()),
&points_mapped,
graphics::WHITE,
)?;
graphics::draw(ctx, &frame, DrawParam::default())?;
// draw points on wireframe
for point in points_mapped {
let size = 5.0;
let rect = Rect::new(point.x - size, point.y - size, size * 2.0, size * 2.0);
let rect = Mesh::new_rectangle(
// draw slider border
let canvas = Canvas::with_window_size(ctx)?;
let opts = StrokeOptions::default()
.with_line_cap(LineCap::Round)
.with_line_join(LineJoin::Round)
.with_line_width(cs_real as f32 * 2.0);
let body = Mesh::new_polyline(
ctx,
DrawMode::Fill(FillOptions::default()),
rect,
DrawMode::Stroke(opts),
spline_mapped.as_ref(),
graphics::WHITE,
)?;
graphics::draw(ctx, &rect, DrawParam::default())?;
graphics::set_canvas(ctx, Some(&canvas));
graphics::clear(ctx, Color::new(0.0, 0.0, 0.0, 0.0));
graphics::draw(ctx, &body, DrawParam::default())?;
graphics::set_canvas(ctx, None);
let mut border_color = graphics::WHITE;
border_color.a = color.a;
graphics::draw(ctx, &canvas, DrawParam::default().color(border_color))?;
// draw slider body
let canvas = Canvas::with_window_size(ctx)?;
let opts = StrokeOptions::default()
.with_line_cap(LineCap::Round)
.with_line_join(LineJoin::Round)
.with_line_width(cs_real as f32 * 1.8);
let body = Mesh::new_polyline(
ctx,
DrawMode::Stroke(opts),
spline_mapped.as_ref(),
graphics::WHITE,
)?;
graphics::set_canvas(ctx, Some(&canvas));
graphics::clear(ctx, Color::new(0.0, 0.0, 0.0, 0.0));
graphics::draw(ctx, &body, DrawParam::default())?;
graphics::set_canvas(ctx, None);
graphics::draw(ctx, &canvas, DrawParam::default().color(color))?;
Ok(spline)
}
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
let frame = Mesh::new_polyline(
ctx,
DrawMode::Stroke(StrokeOptions::default()),
&points_mapped,
graphics::WHITE,
)?;
graphics::draw(ctx, &frame, DrawParam::default())?;
// draw points on wireframe
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 rect = Rect::new(fst.x - size, fst.y - size, size * 2.0, size * 2.0);
let rect =
Mesh::new_rectangle(ctx, DrawMode::Fill(FillOptions::default()), rect, color)?;
graphics::draw(ctx, &rect, DrawParam::default())?;
i += 1;
}
Ok(())
}
}