animgraph 0.1.0

Animation data flow library using hierarchical state machines
Documentation
use serde_derive::{Deserialize, Serialize};

use crate::{io::NumberRef, GraphNodeConstructor, Alpha};

use super::{GraphNode, GraphVisitor};

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct SpeedScaleNode {
    pub scale: NumberRef<f32>,
    pub blend: NumberRef<Alpha>,
}

impl GraphNodeConstructor for SpeedScaleNode {
    fn identity() -> &'static str {
        "speed_scale"
    }

    fn construct_entry(
        self,
        metrics: &crate::GraphMetrics,
    ) -> anyhow::Result<crate::GraphNodeEntry> {
        metrics.validate_number_ref(&self.scale, Self::identity())?;
        metrics.validate_number_ref(&self.blend, Self::identity())?;
        Ok(crate::GraphNodeEntry::Process(Box::new(self)))
    }
}

impl GraphNode for SpeedScaleNode {
    fn visit(&self, visitor: &mut GraphVisitor) {
        let mut factor = self.scale.get(visitor.graph);
        let blend = self.blend.get(visitor.graph);
        factor = blend.lerp(1.0, factor);
        visitor.context.apply_time_scale(factor);
    }
}

#[cfg(feature = "compiler")]
pub mod compile {
    use serde_json::Value;

    use crate::{
        compiler::prelude::{
            Extras, IOSlot, IOType, Node, NodeCompilationError, NodeCompiler,
            NodeSerializationContext, NodeSettings,
        },
        GraphNodeConstructor, Alpha,
    };

    pub use super::SpeedScaleNode;

    #[derive(Default, Debug, Clone)]
    pub struct SpeedScaleSettings;

    impl NodeSettings for SpeedScaleSettings {
        fn name() -> &'static str {
            SpeedScaleNode::identity()
        }

        fn input() -> &'static [(&'static str, IOType)] {
            use IOType::*;
            &[("scale", Number), ("blend", Number)]
        }

        fn output() -> &'static [(&'static str, IOType)] {
            &[]
        }

        fn build(self) -> anyhow::Result<Extras> {
            Ok(Extras::default())
        }
    }

    impl NodeCompiler for SpeedScaleNode {
        type Settings = SpeedScaleSettings;

        fn build<'a>(
            context: &NodeSerializationContext<'a>,
        ) -> Result<Value, NodeCompilationError> {
            let scale = context.input_number(0)?;
            let blend = context.input_number(1)?;

            context.serialize_node(SpeedScaleNode { scale, blend })
        }
    }

    pub fn speed_scale(scale: impl IOSlot<f32>, blend: impl IOSlot<Alpha>) -> Node {
        let settings = SpeedScaleSettings;
        let input = vec![scale.into_slot("scale"), blend.into_slot("blend")];
        Node::new(input, [], settings).expect("Valid")
    }
}