animgraph 0.1.0

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

use crate::{
    io::Resource, BlendSampleId, BlendTree, BoneGroup, Graph, GraphNodeConstructor, PoseNode,
    PoseParent,
};

use super::{GraphNode, GraphVisitor};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PoseMaskNode {
    pub bone_group: Resource<BoneGroup>,
}

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

    fn construct_entry(
        self,
        metrics: &crate::GraphMetrics,
    ) -> anyhow::Result<crate::GraphNodeEntry> {
        metrics.validate_resource(&self.bone_group, Self::identity())?;
        Ok(crate::GraphNodeEntry::PoseParent(Box::new(self)))
    }
}

impl GraphNode for PoseMaskNode {
    fn visit(&self, _visitor: &mut GraphVisitor) {}
}

impl PoseParent for PoseMaskNode {
    fn apply_parent(
        &self,
        tasks: &mut BlendTree,
        child_task: BlendSampleId,
        graph: &Graph,
    ) -> anyhow::Result<BlendSampleId> {
        if let Some(res) = self.bone_group.get(graph) {
            Ok(tasks.apply_mask(child_task, res.group))
        } else {
            Ok(child_task)
        }
    }

    fn as_pose(&self) -> Option<&dyn PoseNode> {
        None
    }
}

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

    use crate::{
        compiler::{
            context::NodeCompiler,
            prelude::{
                Extras, IOType, Node, NodeCompilationError, NodeSerializationContext, NodeSettings,
            },
        },
        io::Resource,
        model::{IOSlot, DEFAULT_INPUT_NAME},
        BoneGroup, GraphNodeConstructor,
    };

    pub use super::PoseMaskNode;

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

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

        fn input() -> &'static [(&'static str, IOType)] {
            &[(DEFAULT_INPUT_NAME, BoneGroup::IO_TYPE)]
        }

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

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

    impl NodeCompiler for PoseMaskNode {
        type Settings = PoseMaskNodeSettings;

        fn build<'a>(
            context: &NodeSerializationContext<'a>,
        ) -> Result<Value, NodeCompilationError> {
            let bone_group = context.input_resource(0)?;
            context.serialize_node(PoseMaskNode { bone_group })
        }
    }

    pub fn pose_mask(bone_group: impl IOSlot<Resource<BoneGroup>>) -> Node {
        let input = vec![bone_group.into_slot(DEFAULT_INPUT_NAME)];
        Node::new(input, vec![], PoseMaskNodeSettings).expect("Valid")
    }
}