draw ticks

This commit is contained in:
Michael Zhang 2021-01-08 19:47:15 -06:00
parent 448b8e4356
commit 300208e21a
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
4 changed files with 97 additions and 21 deletions

4
Cargo.lock generated
View file

@ -1037,8 +1037,8 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
[[package]] [[package]]
name = "libosu" name = "libosu"
version = "0.0.12" version = "0.0.13"
source = "git+https://github.com/iptq/libosu?rev=332b7a55559c0257cc4d39577240b1cab5ed3d07#332b7a55559c0257cc4d39577240b1cab5ed3d07" source = "git+https://github.com/iptq/libosu?rev=dee4d05eeaba1313a17eefbbd7679a947b52fbc1#dee4d05eeaba1313a17eefbbd7679a947b52fbc1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bitflags", "bitflags",

View file

@ -20,4 +20,4 @@ ordered-float = "2.0.1"
[dependencies.libosu] [dependencies.libosu]
git = "https://github.com/iptq/libosu" git = "https://github.com/iptq/libosu"
rev = "332b7a55559c0257cc4d39577240b1cab5ed3d07" rev = "dee4d05eeaba1313a17eefbbd7679a947b52fbc1"

View file

@ -1,5 +1,5 @@
mod timeline;
mod sliders; mod sliders;
mod timeline;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
@ -114,8 +114,6 @@ impl Game {
color: Color, color: Color,
} }
self.draw_timeline(ctx, time)?;
let mut playfield_hitobjects = Vec::new(); let mut playfield_hitobjects = Vec::new();
let preempt = (self.beatmap.inner.difficulty.approach_preempt() as f64) / 1000.0; let preempt = (self.beatmap.inner.difficulty.approach_preempt() as f64) / 1000.0;
let fade_in = (self.beatmap.inner.difficulty.approach_fade_time() as f64) / 1000.0; let fade_in = (self.beatmap.inner.difficulty.approach_fade_time() as f64) / 1000.0;
@ -164,6 +162,8 @@ impl Game {
} }
} }
self.draw_timeline(ctx, time)?;
let cs_scale = PLAYFIELD_BOUNDS.w / 640.0; let cs_scale = PLAYFIELD_BOUNDS.w / 640.0;
let osupx_scale_x = PLAYFIELD_BOUNDS.w / 512.0; let osupx_scale_x = PLAYFIELD_BOUNDS.w / 512.0;
let osupx_scale_y = PLAYFIELD_BOUNDS.h / 384.0; let osupx_scale_y = PLAYFIELD_BOUNDS.h / 384.0;

View file

@ -1,34 +1,108 @@
use anyhow::Result; use anyhow::Result;
use ggez::{ use ggez::{
graphics::{self, DrawParam, Mesh, Rect}, graphics::{self, Color, DrawParam, Mesh, Rect, WHITE},
nalgebra::Point2, nalgebra::Point2,
Context, Context,
}; };
use libosu::TimingPointKind;
use crate::hit_object::HitObjectExt; use crate::hit_object::HitObjectExt;
use super::Game; use super::Game;
pub const TIMELINE_BOUNDS: Rect = Rect::new(0.0, 0.0, 1024.0, 108.0); pub const BOUNDS: Rect = Rect::new(0.0, 54.0, 768.0, 54.0);
pub const RED: Color = Color::new(1.0, 0.0, 0.0, 1.0);
pub const BLUE: Color = Color::new(0.0, 0.0, 1.0, 1.0);
pub const TICKS: &[&[(Color, f32)]] = &[
&[],
&[],
&[],
&[],
&[(WHITE, 1.0), (BLUE, 0.5), (RED, 0.5), (BLUE, 0.5)],
];
impl Game { impl Game {
pub(super) fn draw_timeline(&self, ctx: &mut Context, time: f64) -> Result<()> { pub(super) fn draw_timeline(&self, ctx: &mut Context, time: f64) -> Result<()> {
let timeline_span = 6.0 / self.beatmap.inner.timeline_zoom; let timeline_span = 6.0 / self.beatmap.inner.timeline_zoom;
let timeline_current_line_x = TIMELINE_BOUNDS.x + TIMELINE_BOUNDS.w * 0.5; let timeline_left = time - timeline_span / 2.0;
let timeline_right = time + timeline_span / 2.0;
let timeline_current_line_x = BOUNDS.x + BOUNDS.w * 0.5;
// the vertical line
let current_line = Mesh::new_line( let current_line = Mesh::new_line(
ctx, ctx,
&[ &[
Point2::new(timeline_current_line_x, TIMELINE_BOUNDS.y), Point2::new(timeline_current_line_x, BOUNDS.y),
Point2::new( Point2::new(timeline_current_line_x, BOUNDS.y + BOUNDS.h),
timeline_current_line_x,
TIMELINE_BOUNDS.y + TIMELINE_BOUNDS.h,
),
], ],
2.0, 2.0,
graphics::WHITE, graphics::WHITE,
)?; )?;
graphics::draw(ctx, &current_line, DrawParam::default())?; graphics::draw(ctx, &current_line, DrawParam::default())?;
// timing sections in this little span
let mut last_uninherited = None;
for timing_points in self.beatmap.inner.timing_points.windows(2) {
let (fst, snd) = (&timing_points[0], &timing_points[1]);
let fst_time = fst.time.as_seconds();
let snd_time = snd.time.as_seconds();
if let TimingPointKind::Uninherited(info) = &fst.kind {
last_uninherited = Some(info);
}
if let Some(last_uninherited) = last_uninherited {
if (fst_time >= timeline_left && fst_time <= timeline_right)
|| (snd_time >= timeline_left && snd_time <= timeline_right)
|| (fst_time < timeline_left && snd_time > timeline_right)
{
// TODO: optimize this
let mut time = fst.time.as_seconds();
let beat = last_uninherited.mpb / 1000.0;
let ticks = TICKS[last_uninherited.meter as usize];
'outer: loop {
for i in 0..last_uninherited.meter as usize {
let tick_time = time + beat * i as f64 / last_uninherited.meter as f64;
if tick_time > snd_time.min(timeline_right) {
break 'outer;
}
let (color, height) = ticks[i];
let percent =
(tick_time - timeline_left) / (timeline_right - timeline_left);
let x = percent as f32 * BOUNDS.w + BOUNDS.x;
let y2 = BOUNDS.y + BOUNDS.h;
let y1 = y2 - BOUNDS.h * 0.3 * height;
let tick = Mesh::new_line(
ctx,
&[Point2::new(x, y1), Point2::new(x, y2)],
1.0,
color,
)?;
graphics::draw(ctx, &tick, DrawParam::default())?;
}
time += beat;
if time >= snd_time.min(timeline_right) {
break;
}
}
}
}
}
// draw a bottom line for the timeline
let bottom_line = Mesh::new_line(
ctx,
&[
Point2::new(BOUNDS.x, BOUNDS.y + BOUNDS.h),
Point2::new(BOUNDS.x + BOUNDS.w, BOUNDS.y + BOUNDS.h),
],
2.0,
graphics::WHITE,
)?;
graphics::draw(ctx, &bottom_line, DrawParam::default())?;
Ok(()) Ok(())
} }
@ -43,6 +117,8 @@ impl Game {
let timeline_right = time + timeline_span / 2.0; let timeline_right = time + timeline_span / 2.0;
let ho_time = (ho.inner.start_time.0 as f64) / 1000.0; let ho_time = (ho.inner.start_time.0 as f64) / 1000.0;
let end_time = (self.beatmap.inner.get_hitobject_end_time(&ho.inner).0 as f64) / 1000.0;
let color = self.beatmap.inner.colors[ho.color_idx]; let color = self.beatmap.inner.colors[ho.color_idx];
let color = graphics::Color::new( let color = graphics::Color::new(
color.red as f32 / 256.0, color.red as f32 / 256.0,
@ -51,23 +127,23 @@ impl Game {
1.0, 1.0,
); );
if ho_time >= timeline_left && ho_time <= timeline_right { if end_time >= timeline_left && ho_time <= timeline_right {
let timeline_percent = (ho_time - timeline_left) / (timeline_right - timeline_left); let timeline_percent = (ho_time - timeline_left) / (timeline_right - timeline_left);
let timeline_x = timeline_percent as f32 * TIMELINE_BOUNDS.w + TIMELINE_BOUNDS.x; let timeline_x = timeline_percent as f32 * BOUNDS.w + BOUNDS.x;
let timeline_y = TIMELINE_BOUNDS.y; let timeline_y = BOUNDS.y;
self.skin.hitcircle.draw( self.skin.hitcircle.draw(
ctx, ctx,
(TIMELINE_BOUNDS.h, TIMELINE_BOUNDS.h), (BOUNDS.h, BOUNDS.h),
DrawParam::default() DrawParam::default()
.dest([timeline_x, timeline_y + TIMELINE_BOUNDS.h / 2.0]) .dest([timeline_x, timeline_y + BOUNDS.h / 2.0])
.offset([0.5, 0.0]) .offset([0.5, 0.0])
.color(color), .color(color),
)?; )?;
self.skin.hitcircleoverlay.draw( self.skin.hitcircleoverlay.draw(
ctx, ctx,
(TIMELINE_BOUNDS.h, TIMELINE_BOUNDS.h), (BOUNDS.h, BOUNDS.h),
DrawParam::default() DrawParam::default()
.dest([timeline_x, timeline_y + TIMELINE_BOUNDS.h / 2.0]) .dest([timeline_x, timeline_y + BOUNDS.h / 2.0])
.offset([0.5, 0.0]), .offset([0.5, 0.0]),
)?; )?;
} }