use super::animation_state::collect_events;
use crate::{Event, EventData, EventTimeline};
use std::sync::Arc;
#[derive(Debug)]
struct Fail(String);
fn make_timeline(frames: &[f32]) -> (EventTimeline, Vec<char>) {
let mut names = Vec::with_capacity(frames.len());
let mut events = Vec::with_capacity(frames.len());
let data = Arc::new(EventData::new("event"));
for (i, &time) in frames.iter().enumerate() {
let ch = (b'a' + (i as u8)) as char;
names.push(ch);
let mut event = Event::new(time, Arc::clone(&data));
event.set_string(ch.to_string());
events.push(event);
}
(EventTimeline::from_events(events), names)
}
fn distinct_count(frames: &[f32]) -> usize {
let mut distinct = 0usize;
let mut last = f32::NAN;
for &t in frames {
if !(t == last) {
distinct += 1;
last = t;
}
}
distinct
}
fn fire(
frames: &[f32],
expected_names: &[char],
time_start: f32,
time_end: f32,
mut time_step: f32,
looped: bool,
) -> Result<(), Fail> {
if frames.is_empty() {
return Ok(());
}
time_step = time_step.max(0.00001);
let mut event_index = 0usize;
while frames[event_index] < time_start {
event_index += 1;
if event_index >= frames.len() {
return Ok(());
}
}
let mut events_count = frames.len();
while events_count > 0 && frames[events_count - 1] > time_end {
events_count -= 1;
}
if events_count <= event_index {
return Ok(());
}
events_count -= event_index;
let duration = frames[event_index + events_count - 1];
if looped && duration > 0.0 {
while time_step > duration / 2.0 {
time_step /= 2.0;
}
}
let (timeline, _) = make_timeline(frames);
let mut fired_events_count = 0usize;
let mut i = 0i32;
let mut last_time = time_start - 0.00001;
loop {
let time = (time_start + time_step * (i as f32)).min(time_end);
let mut last_time_looped = last_time;
let mut time_looped = time;
if looped && duration != 0.0 {
last_time_looped %= duration;
time_looped %= duration;
}
let mut fired = Vec::new();
collect_events(&timeline, last_time_looped, time_looped, &mut fired);
for event in fired {
let fired = event
.get_string()
.chars()
.next()
.ok_or_else(|| Fail("Event string was empty.".to_string()))?;
if looped {
event_index %= expected_names.len();
} else if fired_events_count >= events_count {
let mut ignored = Vec::new();
collect_events(&timeline, last_time_looped, time_looped, &mut ignored);
return Err(Fail(format!(
"Too many events fired. frames={frames:?} time_start={time_start} time_end={time_end} time_step={time_step} looped={looped}"
)));
}
if fired != expected_names[event_index] {
let mut ignored = Vec::new();
collect_events(&timeline, last_time_looped, time_looped, &mut ignored);
return Err(Fail(format!(
"Wrong event fired: got {fired:?}, expected {:?}. frames={frames:?} time_start={time_start} time_end={time_end} time_step={time_step} looped={looped}",
expected_names[event_index]
)));
}
event_index += 1;
fired_events_count += 1;
}
if time >= time_end {
break;
}
last_time = time;
i += 1;
}
if fired_events_count < events_count {
return Err(Fail(format!(
"Event not fired (expected at least {events_count}, got {}). frames={frames:?} time_start={time_start} time_end={time_end} time_step={time_step} looped={looped}",
fired_events_count
)));
}
Ok(())
}
fn run(frames: &[f32], time_start: f32, time_end: f32, time_step: f32) {
let (_, names) = make_timeline(frames);
let distinct = distinct_count(frames);
if let Err(err) = fire(frames, &names, time_start, time_end, time_step, false)
.and_then(|_| fire(frames, &names, time_start, time_end, time_step, true))
{
let mut message = err.0;
message.push_str(&format!(
" (distinct_frame_times={distinct}, frames={frames:?}, time_start={time_start}, time_end={time_end}, time_step={time_step})"
));
panic!("{message}");
}
}
fn test_frames(frames: &[f32]) {
let max_frame = frames.iter().copied().fold(0.0f32, |acc, v| acc.max(v));
run(frames, 0.0, 99.0, 0.1);
run(frames, 0.0, max_frame, 0.1);
run(frames, frames[0], 999.0, 2.0);
run(frames, frames[0], max_frame, 0.1);
run(frames, 0.0, max_frame, (max_frame / 100.0).ceil());
run(frames, 0.0, 99.0, 0.1);
run(frames, 0.0, 999.0, 100.0);
if distinct_count(frames) > 1 {
let epsilon = 0.02;
run(frames, frames[0], max_frame - epsilon, 0.1);
run(frames, 0.0, max_frame - epsilon, 0.1);
run(frames, frames[0] + epsilon, max_frame, 0.1);
run(frames, frames[0] + epsilon, 99.0, 0.1);
}
}
#[test]
fn event_timeline_libgdx_upstream_tests() {
test_frames(&[0.0]);
test_frames(&[1.0]);
test_frames(&[1.0, 1.0]);
test_frames(&[1.0, 2.0]);
test_frames(&[1.0, 2.0]);
test_frames(&[1.0, 2.0, 3.0]);
test_frames(&[1.0, 2.0, 3.0]);
test_frames(&[0.0, 0.0, 0.0]);
test_frames(&[0.0, 0.0, 1.0]);
test_frames(&[0.0, 1.0, 1.0]);
test_frames(&[1.0, 1.0, 1.0]);
test_frames(&[1.0, 2.0, 3.0, 4.0]);
test_frames(&[0.0, 2.0, 3.0, 4.0]);
test_frames(&[0.0, 2.0, 2.0, 4.0]);
test_frames(&[0.0, 0.0, 0.0, 0.0]);
test_frames(&[2.0, 2.0, 2.0, 2.0]);
test_frames(&[0.1]);
test_frames(&[0.1, 0.1]);
test_frames(&[0.1, 50.0]);
test_frames(&[0.1, 0.2, 0.3, 0.4]);
test_frames(&[
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 6.0, 7.0, 7.0, 8.0, 9.0, 10.0, 11.0, 11.01, 12.0, 12.0, 12.0,
12.0,
]);
}