anim.rs
1 /* This file is part of DarkFi (https://dark.fi) 2 * 3 * Copyright (C) 2020-2025 Dyne.org foundation 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU Affero General Public License as 7 * published by the Free Software Foundation, either version 3 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Affero General Public License for more details. 14 * 15 * You should have received a copy of the GNU Affero General Public License 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 */ 18 19 use std::collections::HashMap; 20 21 use super::{BufferId, DrawCall, GfxDrawCall, TextureId}; 22 23 #[derive(Debug, Clone)] 24 pub struct Frame { 25 /// Duration of this frame in ms 26 duration: u32, 27 dc: DrawCall, 28 } 29 30 impl Frame { 31 pub fn new(duration: u32, dc: DrawCall) -> Self { 32 Self { duration, dc } 33 } 34 } 35 36 #[derive(Debug, Clone)] 37 pub(super) struct GfxSeqAnim { 38 oneshot: bool, 39 frames: Vec<Option<GfxFrame>>, 40 /// Timer between frames 41 timer: std::time::Instant, 42 current_idx: usize, 43 pub(super) is_visible: bool, 44 } 45 46 impl GfxSeqAnim { 47 pub fn new(frames_len: usize, oneshot: bool) -> Self { 48 let frames = vec![None; frames_len]; 49 Self { 50 oneshot, 51 frames, 52 timer: std::time::Instant::now(), 53 current_idx: 0, 54 is_visible: false, 55 } 56 } 57 58 pub fn set( 59 &mut self, 60 frame_idx: usize, 61 frame: Frame, 62 textures: &HashMap<TextureId, miniquad::TextureId>, 63 buffers: &HashMap<BufferId, miniquad::BufferId>, 64 ) { 65 assert!(frame_idx < self.frames.len()); 66 let duration = std::time::Duration::from_millis(frame.duration as u64); 67 let dc = frame.dc.compile(textures, buffers, 0).unwrap(); 68 self.frames[frame_idx] = Some(GfxFrame { duration, dc }); 69 //t!("got frame {frame_idx}"); 70 } 71 72 fn curr_frame(&self) -> Option<&GfxFrame> { 73 assert!(self.current_idx < self.frames.len()); 74 self.frames[self.current_idx].as_ref() 75 } 76 77 pub fn tick(&mut self) -> Option<GfxDrawCall> { 78 //t!("tick"); 79 if self.curr_frame().is_none() { 80 assert_eq!(self.current_idx, 0); 81 return None 82 }; 83 84 self.increment(); 85 86 let curr_frame = self.curr_frame().unwrap().clone(); 87 Some(curr_frame.dc) 88 } 89 90 fn increment(&mut self) { 91 // One shot anims dont loop 92 if self.oneshot && self.current_idx + 1 == self.frames.len() { 93 return 94 } 95 96 let elapsed = self.timer.elapsed(); 97 let frame = self.curr_frame().unwrap(); 98 let curr_duration = frame.duration; 99 100 if elapsed >= curr_duration { 101 let next_idx = (self.current_idx + 1) % self.frames.len(); 102 // Only advance when the next frame is Some 103 // Otherwise stay on the same frame 104 if self.frames[next_idx].is_some() { 105 self.current_idx = next_idx; 106 // Reset the timer now we changed frame 107 self.timer = std::time::Instant::now(); 108 } 109 } 110 } 111 } 112 113 #[derive(Debug, Clone)] 114 struct GfxFrame { 115 duration: std::time::Duration, 116 dc: GfxDrawCall, 117 }