Experimental animation support (#2443)

* Implement experimental time routing to the node graph

* Allow toggling live preview with SHIFT + SPACE

* Add animation message handler

* Fix hotkeys

* Fix milisecond node

* Adevertize set frame index action

* Fix frame index

* Fix year calculation

* Add comment for why month and day are not exposed

* Combine animation nodes and fix animation time implementation

* Fix animation time interaction with playback

* Add set animation time mode message

* Captalize UTC

* Fix compiling

* Fix crash and add text nodes

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Dennis Kobert
2025-03-19 01:19:49 -07:00
committed by GitHub
co-authored by Keavon Chambers
parent b98711dbdb
commit 44694ff8d6
31 changed files with 428 additions and 62 deletions
@@ -0,0 +1,17 @@
use crate::messages::prelude::*;
use super::animation_message_handler::AnimationTimeMode;
#[impl_message(Message, Animation)]
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum AnimationMessage {
ToggleLivePreview,
EnableLivePreview,
DisableLivePreview,
ResetAnimation,
SetFrameIndex(f64),
SetTime(f64),
UpdateTime,
IncrementFrameCounter,
SetAnimationTimeMode(AnimationTimeMode),
}
@@ -0,0 +1,84 @@
use std::time::Duration;
use crate::messages::prelude::*;
use super::TimingInformation;
#[derive(PartialEq, Clone, Default, Debug, serde::Serialize, serde::Deserialize)]
pub enum AnimationTimeMode {
#[default]
TimeBased,
FrameBased,
}
#[derive(Debug, Default)]
pub struct AnimationMessageHandler {
live_preview: bool,
timestamp: f64,
frame_index: f64,
animation_start: Option<f64>,
fps: f64,
animation_time_mode: AnimationTimeMode,
}
impl AnimationMessageHandler {
pub(crate) fn timing_information(&self) -> TimingInformation {
let animation_time = self.timestamp - self.animation_start.unwrap_or(self.timestamp);
let animation_time = match self.animation_time_mode {
AnimationTimeMode::TimeBased => Duration::from_millis(animation_time as u64),
AnimationTimeMode::FrameBased => Duration::from_secs((self.frame_index / self.fps) as u64),
};
TimingInformation { time: self.timestamp, animation_time }
}
}
impl MessageHandler<AnimationMessage, ()> for AnimationMessageHandler {
fn process_message(&mut self, message: AnimationMessage, responses: &mut VecDeque<Message>, _data: ()) {
match message {
AnimationMessage::ToggleLivePreview => {
if self.animation_start.is_none() {
self.animation_start = Some(self.timestamp);
}
self.live_preview = !self.live_preview
}
AnimationMessage::EnableLivePreview => {
if self.animation_start.is_none() {
self.animation_start = Some(self.timestamp);
}
self.live_preview = true
}
AnimationMessage::DisableLivePreview => self.live_preview = false,
AnimationMessage::SetFrameIndex(frame) => {
self.frame_index = frame;
log::debug!("set frame index to {}", frame);
responses.add(PortfolioMessage::SubmitActiveGraphRender)
}
AnimationMessage::SetTime(time) => {
self.timestamp = time;
responses.add(AnimationMessage::UpdateTime);
}
AnimationMessage::IncrementFrameCounter => {
if self.live_preview {
self.frame_index += 1.;
responses.add(AnimationMessage::UpdateTime);
}
}
AnimationMessage::UpdateTime => {
if self.live_preview {
responses.add(PortfolioMessage::SubmitActiveGraphRender)
}
}
AnimationMessage::ResetAnimation => {
self.frame_index = 0.;
self.animation_start = None;
responses.add(PortfolioMessage::SubmitActiveGraphRender)
}
AnimationMessage::SetAnimationTimeMode(animation_time_mode) => self.animation_time_mode = animation_time_mode,
}
}
advertise_actions!(AnimationMessageDiscriminant;
ToggleLivePreview,
SetFrameIndex,
ResetAnimation,
);
}
+9
View File
@@ -0,0 +1,9 @@
mod animation_message;
mod animation_message_handler;
#[doc(inline)]
pub use animation_message::{AnimationMessage, AnimationMessageDiscriminant};
#[doc(inline)]
pub use animation_message_handler::AnimationMessageHandler;
pub use graphene_core::application_io::TimingInformation;