use bevy::{
asset::{AssetId, Assets, Handle},
ecs::{
resource::Resource,
system::{In, ResMut},
world::World,
},
platform::collections::HashMap,
};
use bevy_animation_graph::{
builtin_nodes::clip_node::ClipNode,
core::{
animated_scene::AnimatedScene,
animation_clip::GraphClip,
animation_graph::{AnimationGraph, NodeId, PinId, SourcePin, TargetPin},
animation_node::AnimationNode,
edge_data::DataSpec,
},
};
use super::{DynamicAction, run_handler};
use crate::ui::actions::ActionContext;
#[derive(Resource, Default)]
pub struct ClipPreviewScenes {
pub previews: HashMap<AssetId<GraphClip>, Handle<AnimatedScene>>,
}
#[derive(Resource, Default)]
pub struct NodePreviewScenes {
pub previews: HashMap<NodePreviewKey, Handle<AnimatedScene>>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct NodePreviewKey {
pub graph: AssetId<AnimationGraph>,
pub node_id: NodeId,
pub pose_pin: PinId,
}
#[derive(Clone)]
pub struct CreateClipPreview {
pub clip: Handle<GraphClip>,
pub scene: Handle<AnimatedScene>,
}
impl DynamicAction for CreateClipPreview {
fn handle(self: Box<Self>, world: &mut World, _: &mut ActionContext) {
run_handler(world, "Could not create clip preview")(Self::system, *self)
}
}
impl CreateClipPreview {
pub fn system(
In(action): In<Self>,
mut previews: ResMut<ClipPreviewScenes>,
mut graph_assets: ResMut<Assets<AnimationGraph>>,
mut scene_assets: ResMut<Assets<AnimatedScene>>,
) {
if previews.previews.contains_key(&action.clip.id()) {
return;
}
let mut new_graph = AnimationGraph::new();
let clip_node = AnimationNode::new("clip", ClipNode::new(action.clip.clone(), None, None));
let clip_node_id = clip_node.id;
new_graph.add_node(clip_node);
new_graph.add_output_data("pose".into(), DataSpec::Pose);
new_graph.add_output_time();
new_graph.add_edge(
SourcePin::NodeData(clip_node_id, ClipNode::OUT_POSE.into()),
TargetPin::OutputData("pose".into()),
);
new_graph.add_edge(SourcePin::NodeTime(clip_node_id), TargetPin::OutputTime);
let graph_handle = graph_assets.add(new_graph);
let Some(mut scene) = scene_assets.get(&action.scene).cloned() else {
return;
};
scene.processed_scene = None;
scene.animation_graph = graph_handle;
let scene_handle = scene_assets.add(scene);
previews.previews.insert(action.clip.id(), scene_handle);
}
}
#[derive(Clone)]
pub struct CreateTrackNodePreview {
pub preview_key: NodePreviewKey,
pub scene: Handle<AnimatedScene>,
}
impl DynamicAction for CreateTrackNodePreview {
fn handle(self: Box<Self>, world: &mut World, _: &mut ActionContext) {
run_handler(world, "Could not create clip preview")(Self::system, *self)
}
}
impl CreateTrackNodePreview {
pub fn system(
In(action): In<Self>,
mut previews: ResMut<NodePreviewScenes>,
mut graph_assets: ResMut<Assets<AnimationGraph>>,
mut scene_assets: ResMut<Assets<AnimatedScene>>,
) {
if previews.previews.contains_key(&action.preview_key) {
return;
}
let Some(existing_graph) = graph_assets.get(action.preview_key.graph) else {
return;
};
let mut new_graph = existing_graph.clone();
new_graph.add_output_data("pose".into(), DataSpec::Pose);
new_graph.add_output_time();
new_graph.add_edge(
SourcePin::NodeData(
action.preview_key.node_id,
action.preview_key.pose_pin.clone(),
),
TargetPin::OutputData("pose".into()),
);
new_graph.add_edge(
SourcePin::NodeTime(action.preview_key.node_id),
TargetPin::OutputTime,
);
let graph_handle = graph_assets.add(new_graph);
let Some(mut scene) = scene_assets.get(&action.scene).cloned() else {
return;
};
scene.processed_scene = None;
scene.animation_graph = graph_handle;
let scene_handle = scene_assets.add(scene);
previews.previews.insert(action.preview_key, scene_handle);
}
}