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]]
name = "libosu"
version = "0.0.12"
source = "git+https://github.com/iptq/libosu?rev=332b7a55559c0257cc4d39577240b1cab5ed3d07#332b7a55559c0257cc4d39577240b1cab5ed3d07"
version = "0.0.13"
source = "git+https://github.com/iptq/libosu?rev=dee4d05eeaba1313a17eefbbd7679a947b52fbc1#dee4d05eeaba1313a17eefbbd7679a947b52fbc1"
dependencies = [
"anyhow",
"bitflags",

View file

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

View file

@ -1,5 +1,5 @@
mod timeline;
mod sliders;
mod timeline;
use std::collections::HashMap;
use std::fs::File;
@ -114,8 +114,6 @@ impl Game {
color: Color,
}
self.draw_timeline(ctx, time)?;
let mut playfield_hitobjects = Vec::new();
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;
@ -164,6 +162,8 @@ impl Game {
}
}
self.draw_timeline(ctx, time)?;
let cs_scale = PLAYFIELD_BOUNDS.w / 640.0;
let osupx_scale_x = PLAYFIELD_BOUNDS.w / 512.0;
let osupx_scale_y = PLAYFIELD_BOUNDS.h / 384.0;

View file

@ -1,34 +1,108 @@
use anyhow::Result;
use ggez::{
graphics::{self, DrawParam, Mesh, Rect},
graphics::{self, Color, DrawParam, Mesh, Rect, WHITE},
nalgebra::Point2,
Context,
};
use libosu::TimingPointKind;
use crate::hit_object::HitObjectExt;
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 {
pub(super) fn draw_timeline(&self, ctx: &mut Context, time: f64) -> Result<()> {
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(
ctx,
&[
Point2::new(timeline_current_line_x, TIMELINE_BOUNDS.y),
Point2::new(
timeline_current_line_x,
TIMELINE_BOUNDS.y + TIMELINE_BOUNDS.h,
),
Point2::new(timeline_current_line_x, BOUNDS.y),
Point2::new(timeline_current_line_x, BOUNDS.y + BOUNDS.h),
],
2.0,
graphics::WHITE,
)?;
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(())
}
@ -43,6 +117,8 @@ impl Game {
let timeline_right = time + timeline_span / 2.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 = graphics::Color::new(
color.red as f32 / 256.0,
@ -51,23 +127,23 @@ impl Game {
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_x = timeline_percent as f32 * TIMELINE_BOUNDS.w + TIMELINE_BOUNDS.x;
let timeline_y = TIMELINE_BOUNDS.y;
let timeline_x = timeline_percent as f32 * BOUNDS.w + BOUNDS.x;
let timeline_y = BOUNDS.y;
self.skin.hitcircle.draw(
ctx,
(TIMELINE_BOUNDS.h, TIMELINE_BOUNDS.h),
(BOUNDS.h, BOUNDS.h),
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])
.color(color),
)?;
self.skin.hitcircleoverlay.draw(
ctx,
(TIMELINE_BOUNDS.h, TIMELINE_BOUNDS.h),
(BOUNDS.h, BOUNDS.h),
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]),
)?;
}