Skip to content

Commit

Permalink
Refactor animated image an text handling
Browse files Browse the repository at this point in the history
This allows for widgets to be animated independently of each other
  • Loading branch information
llMBQll committed Jan 20, 2025
1 parent 911305b commit 246c16d
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 248 deletions.
8 changes: 5 additions & 3 deletions config/scripts.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ local function volume()
Text {
text = AUDIO.Name,
scrolling = true,
repeats = 'Once',
position = { x = 0, y = SCREEN.Height / 2 },
size = { width = SCREEN.Width, height = SCREEN.Height / 2 },
},
},
duration = 2000,
repeats = 'Once',
}
end

Expand All @@ -34,13 +34,16 @@ local function spotify()
Text {
text = string.format("%s - %s", SPOTIFY.Artist, SPOTIFY.Title),
scrolling = true,
animation_group = 1,
position = { x = 0, y = 2 },
size = { width = SCREEN.Width, height = 20 },
},
Text {
text = string.format("%02d:%02d", CLOCK.Hours, CLOCK.Minutes),
scrolling = true,
animation_group = 1,
position = { x = 0, y = SCREEN.Height - 18 },
size = { width = 50, height = 18 },
size = { width = 25, height = 18 },
},
Text {
text = string.format("%.3s%02d", CLOCK.MonthNames[CLOCK.Month], CLOCK.MonthDay),
Expand All @@ -55,7 +58,6 @@ local function spotify()
},
},
duration = SPOTIFY_DURATION,
repeats = 'ForDuration',
}
end

Expand Down
8 changes: 3 additions & 5 deletions omni-led/src/common/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,12 @@ pub fn proto_to_lua_value(lua: &Lua, field: Field) -> mlua::Result<Value> {
Ok(Value::Table(table))
}
Some(FieldEntry::FImageData(image)) => {
let mut image_data = ImageData {
let hash = hash(&image.data);
let image_data = ImageData {
format: image.format().into(),
bytes: image.data,
hash: None,
hash: Some(hash),
};
let hash = hash(&image_data);
image_data.hash = Some(hash);

let user_data = lua.create_any_userdata(image_data)?;
Ok(Value::UserData(user_data))
}
Expand Down
73 changes: 37 additions & 36 deletions omni-led/src/renderer/animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,28 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#[derive(Clone)]
use crate::script_handler::script_data_types::Repeat;

#[derive(Clone, Debug)]
pub struct Animation {
edge_step_time: usize,
step_time: usize,
steps: usize,
last_update_tick: usize,
total_time: usize,
repeat: Repeat,
current_tick: usize,
can_wrap: bool,
}

#[derive(Debug, PartialEq)]
pub struct Step {
pub offset: usize,
pub can_wrap: bool,
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum State {
InProgress,
Finished,
CanFinish,
}

impl Animation {
pub fn new(edge_step_time: usize, step_time: usize, steps: usize, tick: usize) -> Self {
pub fn new(edge_step_time: usize, step_time: usize, steps: usize, repeat: Repeat) -> Self {
let total_time = match steps {
1 => 0,
_ => edge_step_time * 2 + (steps - 2) * step_time,
Expand All @@ -43,13 +47,14 @@ impl Animation {
edge_step_time,
step_time,
steps,
last_update_tick: tick,
total_time,
repeat,
current_tick: 1,
can_wrap: false,
}
}

pub fn step(&mut self, tick: usize) -> Step {
pub fn step(&mut self) -> usize {
let (step, can_wrap) = if self.current_tick >= self.total_time {
(self.steps - 1, true)
} else if self.current_tick > self.total_time - self.edge_step_time {
Expand All @@ -63,19 +68,22 @@ impl Animation {
)
};

if tick != self.last_update_tick {
self.current_tick += 1;
self.last_update_tick = tick;
}
self.current_tick += 1;
self.can_wrap = can_wrap;

step
}

Step {
offset: step,
can_wrap,
pub fn state(&self) -> State {
match (self.repeat, self.can_wrap) {
(Repeat::Once, false) => State::InProgress,
(Repeat::Once, true) => State::Finished,
(Repeat::ForDuration, _) => State::CanFinish,
}
}

pub fn last_update_time(&self) -> usize {
self.last_update_tick
pub fn can_wrap(&self) -> bool {
self.can_wrap
}

pub fn reset(&mut self) {
Expand All @@ -88,21 +96,15 @@ mod tests {
use super::*;

macro_rules! step_and_assert_eq {
($tick:ident, $anim:ident, $step:expr, $can_wrap:expr) => {
$tick += 1;
assert_eq!(
$anim.step($tick),
Step {
offset: $step,
can_wrap: $can_wrap
}
);
($anim:ident, $step:expr, $can_wrap:expr, $state:expr) => {
assert_eq!($anim.step(), $step);
assert_eq!($anim.can_wrap(), $can_wrap);
assert_eq!($anim.state(), $state);
};
}

fn run_test(edge_time: usize, step_time: usize, steps: usize) {
let mut tick = 0;
let mut animation = Animation::new(edge_time, step_time, steps, 0);
let mut animation = Animation::new(edge_time, step_time, steps, Repeat::Once);

let total_time = if steps == 1 {
0
Expand All @@ -113,19 +115,19 @@ mod tests {
assert_eq!(animation.total_time, total_time);

for _ in 0..edge_time {
step_and_assert_eq!(tick, animation, 0, false);
step_and_assert_eq!(animation, 0, false, State::InProgress);
}

for step in 0..steps - 2 {
for _ in 0..step_time {
step_and_assert_eq!(tick, animation, step + 1, false);
step_and_assert_eq!(animation, step + 1, false, State::InProgress);
}
}

for _ in 0..edge_time - 1 {
step_and_assert_eq!(tick, animation, steps - 1, false);
step_and_assert_eq!(animation, steps - 1, false, State::InProgress);
}
step_and_assert_eq!(tick, animation, steps - 1, true);
step_and_assert_eq!(animation, steps - 1, true, State::Finished);
}

#[test]
Expand Down Expand Up @@ -161,11 +163,10 @@ mod tests {
const STEP_TIME: usize = 5;
const STEPS: usize = 1;

let mut tick = 0;
let mut animation = Animation::new(EDGE_TIME, STEP_TIME, STEPS, 0);
let mut animation = Animation::new(EDGE_TIME, STEP_TIME, STEPS, Repeat::Once);

assert_eq!(animation.total_time, 0);

step_and_assert_eq!(tick, animation, 0, true);
step_and_assert_eq!(animation, 0, true, State::Finished);
}
}
130 changes: 130 additions & 0 deletions omni-led/src/renderer/animation_group.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use crate::renderer::animation::{Animation, State};

#[derive(Clone)]
pub struct AnimationGroup {
items: Vec<Item>,
new_data: bool,
keep_in_sync: bool,
}

#[derive(Clone)]
struct Item {
hash: u64,
animation: Animation,
accessed: bool,
}

impl AnimationGroup {
pub fn new(keep_in_sync: bool) -> Self {
Self {
items: Vec::new(),
new_data: false,
keep_in_sync,
}
}

pub fn entry(&mut self, hash: u64) -> Entry {
let mut index = None;
for (i, item) in self.items.iter_mut().enumerate() {
if item.hash == hash {
index = Some(i);
break;
}
}

match index {
Some(index) => Entry::Occupied(OccupiedEntry {
_hash: hash,
item: &mut self.items[index],
}),
None => Entry::Vacant(VacantEntry { hash, group: self }),
}
}

pub fn pre_sync(&mut self) {
self.items.retain_mut(|item| {
if item.accessed {
if self.new_data && self.keep_in_sync {
item.animation.reset();
item.accessed = false;
}
true
} else {
false
}
});
self.new_data = false;
}

pub fn sync(&mut self) {
if self.keep_in_sync {
let all_can_wrap = self.items.iter().all(|item| item.animation.can_wrap());
if all_can_wrap {
for item in &mut self.items {
item.animation.reset();
}
}
} else {
for item in &mut self.items {
if item.animation.can_wrap() {
item.animation.reset();
}
}
}
}

pub fn states(&self) -> Vec<State> {
self.items
.iter()
.map(|item| item.animation.state())
.collect()
}
}

pub enum Entry<'a> {
Occupied(OccupiedEntry<'a>),
Vacant(VacantEntry<'a>),
}

impl<'a> Entry<'a> {
pub fn or_insert_with<F: FnOnce() -> Animation>(self, f: F) -> &'a mut Animation {
match self {
Entry::Occupied(entry) => {
entry.item.accessed = true;
&mut entry.item.animation
}
Entry::Vacant(entry) => {
entry.group.new_data = true;
entry.group.items.push(Item {
hash: entry.hash,
animation: f(),
accessed: true,
});
let index = entry.group.items.len() - 1;
&mut entry.group.items[index].animation
}
}
}

pub fn unwrap(self) -> &'a mut Animation {
match self {
Entry::Occupied(entry) => {
entry.item.accessed = true;
&mut entry.item.animation
}
Entry::Vacant(entry) => {
panic!("Entry with hash {} doesn't exist", entry.hash);
}
}
}
}

pub struct OccupiedEntry<'a> {
_hash: u64,
item: &'a mut Item,
}

pub struct VacantEntry<'a> {
hash: u64,
group: &'a mut AnimationGroup,
}
3 changes: 2 additions & 1 deletion omni-led/src/renderer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

pub mod animation;
pub mod animation_group;
pub mod buffer;
pub mod font_selector;
pub mod renderer;

mod animation;
mod bit;
mod font_manager;
mod images;
Loading

0 comments on commit 246c16d

Please sign in to comment.