use std::sync::Arc;
use crate::{
input::{Input, event::InputEvent},
storage::asset::{
curve::multiplied_curve::{MultipliedCurve, RangePercentage},
project::Project,
scene::instance::SceneInstance,
},
};
pub(crate) trait InputEventState {
fn is_new(&self) -> bool;
fn is_live(&self) -> bool;
fn dimmer(&self) -> f32;
}
impl InputEventState for InputEvent {
fn is_new(&self) -> bool {
Input::is_event_new(self)
}
fn is_live(&self) -> bool {
Input::event_live_value(self).is_some()
}
fn dimmer(&self) -> f32 {
Input::event_live_value(self)
.map(|value| f32::from(value) / 255.0)
.unwrap_or(0.0)
}
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct SceneInputState {
active: bool,
flash: bool,
beat_progression_offset: MultipliedCurve<RangePercentage>,
input_dimmer: f32,
}
pub(crate) trait SceneInstanceInputs {
fn next_input_state(&self, beat_progression: f32) -> SceneInputState;
fn input_state(&self) -> SceneInputState;
fn set_input_state(&mut self, state: SceneInputState);
}
impl SceneInstanceInputs for SceneInstance {
fn next_input_state(&self, beat_progression: f32) -> SceneInputState {
let mut next = self.input_state();
if let Some(event) = self.activation_input.as_ref()
&& event.is_new()
{
next.active = !next.active;
}
if let Some(event) = self.flash_input.as_ref() {
let flash_active = event.is_live();
if !self.flash && flash_active && self.set_offset_on_flash {
next.beat_progression_offset =
MultipliedCurve::new_multiplier(4.0 - beat_progression % 4.0);
}
next.flash = flash_active;
}
if let Some(event) = self.dimmer_input.as_ref() {
next.input_dimmer = event.dimmer()
}
next
}
fn input_state(&self) -> SceneInputState {
SceneInputState {
active: self.active,
flash: self.flash,
beat_progression_offset: self.beat_progression_offset.clone(),
input_dimmer: self.input_dimmer,
}
}
fn set_input_state(&mut self, state: SceneInputState) {
let SceneInputState {
active,
flash,
beat_progression_offset,
input_dimmer,
} = state;
self.active = active;
self.flash = flash;
self.beat_progression_offset = beat_progression_offset;
self.input_dimmer = input_dimmer;
}
}
pub(crate) fn update_input_state(project: &mut Arc<Project>, beat_progression: f32) {
let changes: Vec<_> = project
.scenes_instances_grid
.iter()
.filter_map(|(location, instance)| {
let next = instance.next_input_state(beat_progression);
(next != instance.input_state()).then_some((*location, next))
})
.collect();
if changes.is_empty() {
return;
}
let project = Arc::make_mut(project);
for (location, state) in changes {
if let Some(instance) = project.scenes_instances_grid.get_mut(&location) {
instance.set_input_state(state);
}
}
}
pub(crate) trait ProjectInputs {
fn tap_input_is_new(&self) -> bool;
fn blackout_input_is_new(&self) -> bool;
fn blackout_hold_input_is_live(&self) -> bool;
fn half_input_is_new(&self) -> bool;
fn double_input_is_new(&self) -> bool;
}
impl ProjectInputs for Project {
fn tap_input_is_new(&self) -> bool {
self.tap_input_events.iter().any(|event| event.is_new())
}
fn blackout_input_is_new(&self) -> bool {
self.blackout_input_events
.iter()
.any(|event| event.is_new())
}
fn blackout_hold_input_is_live(&self) -> bool {
self.blackout_hold_input_events
.iter()
.any(|event| event.is_live())
}
fn half_input_is_new(&self) -> bool {
self.half_input_events.iter().any(|event| event.is_new())
}
fn double_input_is_new(&self) -> bool {
self.double_input_events.iter().any(|event| event.is_new())
}
}