shity basic one shot
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
use crate::graph::*;
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
|
||||
/// Shared, thread-safe handle to the graph being built. Every builder carries a clone.
|
||||
#[derive(Clone)]
|
||||
pub struct Aac {
|
||||
pub(crate) graph: Arc<Mutex<ControllerGraph>>,
|
||||
}
|
||||
|
||||
impl Default for Aac {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Aac {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
graph: Arc::new(Mutex::new(ControllerGraph::default())),
|
||||
}
|
||||
}
|
||||
|
||||
/// A poisoned lock still holds a usable graph; recovering avoids panicking across the FFI boundary.
|
||||
fn lock(&self) -> MutexGuard<'_, ControllerGraph> {
|
||||
self.graph.lock().unwrap_or_else(|e| e.into_inner())
|
||||
}
|
||||
|
||||
pub fn write<R>(&self, f: impl FnOnce(&mut ControllerGraph) -> R) -> R {
|
||||
f(&mut self.lock())
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameter handles only carry the name; conditions read nothing else from them.
|
||||
#[derive(Clone)]
|
||||
pub struct FloatParam {
|
||||
pub(crate) name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IntParam {
|
||||
pub(crate) name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BoolParam {
|
||||
pub(crate) name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ControllerBuilder {
|
||||
pub(crate) aac: Aac,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct LayerBuilder {
|
||||
pub(crate) aac: Aac,
|
||||
pub(crate) layer: usize,
|
||||
}
|
||||
|
||||
/// A state machine. `machine` is the chain of sub-machine indices from the layer root, so the empty
|
||||
/// chain is the layer's root machine and indices stay stable because machines are only ever appended.
|
||||
#[derive(Clone)]
|
||||
pub struct MachineRef {
|
||||
pub(crate) aac: Aac,
|
||||
pub(crate) layer: usize,
|
||||
pub(crate) machine: Vec<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StateRef {
|
||||
pub(crate) aac: Aac,
|
||||
pub(crate) layer: usize,
|
||||
pub(crate) machine: Vec<usize>,
|
||||
pub(crate) state: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AnyStateRef {
|
||||
pub(crate) aac: Aac,
|
||||
pub(crate) layer: usize,
|
||||
pub(crate) machine: Vec<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClipBuilder {
|
||||
pub(crate) aac: Aac,
|
||||
pub(crate) name: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BlendTreeBuilder {
|
||||
pub(crate) aac: Aac,
|
||||
pub(crate) name: String,
|
||||
}
|
||||
|
||||
/// `source` is the originating state, or `None` for an any-state transition.
|
||||
#[derive(Clone)]
|
||||
pub struct TransitionRef {
|
||||
pub(crate) aac: Aac,
|
||||
pub(crate) layer: usize,
|
||||
pub(crate) machine: Vec<usize>,
|
||||
pub(crate) source: Option<usize>,
|
||||
pub(crate) index: usize,
|
||||
}
|
||||
|
||||
pub(crate) fn machine_mut<'a>(
|
||||
graph: &'a mut ControllerGraph,
|
||||
layer: usize,
|
||||
path: &[usize],
|
||||
) -> &'a mut StateMachine {
|
||||
let mut machine = &mut graph.controller.layers[layer].state_machine;
|
||||
for &index in path {
|
||||
machine = &mut machine.sub_machines[index];
|
||||
}
|
||||
machine
|
||||
}
|
||||
|
||||
pub(crate) fn clip_mut<'a>(graph: &'a mut ControllerGraph, name: &str) -> Option<&'a mut ClipData> {
|
||||
graph.clips.iter_mut().find(|clip| clip.name == name)
|
||||
}
|
||||
|
||||
pub(crate) fn blend_tree_mut<'a>(
|
||||
graph: &'a mut ControllerGraph,
|
||||
name: &str,
|
||||
) -> Option<&'a mut BlendTreeData> {
|
||||
graph.blend_trees.iter_mut().find(|tree| tree.name == name)
|
||||
}
|
||||
|
||||
impl StateRef {
|
||||
pub fn state_name(&self) -> String {
|
||||
self.aac
|
||||
.write(|graph| machine_mut(graph, self.layer, &self.machine).states[self.state].name.clone())
|
||||
}
|
||||
|
||||
pub fn set_motion(&self, motion: MotionRef) {
|
||||
self.aac.write(|graph| {
|
||||
machine_mut(graph, self.layer, &self.machine).states[self.state].motion = Some(motion);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn transition_to(&self, target: &StateRef) -> TransitionRef {
|
||||
let to = target.state_name();
|
||||
let index = self.aac.write(|graph| {
|
||||
let state = &mut machine_mut(graph, self.layer, &self.machine).states[self.state];
|
||||
state.transitions.push(Transition::new(to));
|
||||
state.transitions.len() - 1
|
||||
});
|
||||
TransitionRef {
|
||||
aac: self.aac.clone(),
|
||||
layer: self.layer,
|
||||
machine: self.machine.clone(),
|
||||
source: Some(self.state),
|
||||
index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AnyStateRef {
|
||||
pub fn transition_to(&self, target: &StateRef) -> TransitionRef {
|
||||
let to = target.state_name();
|
||||
let index = self.aac.write(|graph| {
|
||||
let machine = machine_mut(graph, self.layer, &self.machine);
|
||||
machine.any_state_transitions.push(Transition::new(to));
|
||||
machine.any_state_transitions.len() - 1
|
||||
});
|
||||
TransitionRef {
|
||||
aac: self.aac.clone(),
|
||||
layer: self.layer,
|
||||
machine: self.machine.clone(),
|
||||
source: None,
|
||||
index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TransitionRef {
|
||||
/// Apply a mutation to the transition this handle points at.
|
||||
pub fn update(&self, f: impl FnOnce(&mut Transition)) {
|
||||
self.aac.write(|graph| {
|
||||
let machine = machine_mut(graph, self.layer, &self.machine);
|
||||
let transitions = match self.source {
|
||||
Some(state) => &mut machine.states[state].transitions,
|
||||
None => &mut machine.any_state_transitions,
|
||||
};
|
||||
f(&mut transitions[self.index]);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn add_conditions(&self, conditions: impl IntoIterator<Item = Condition>) {
|
||||
self.update(|transition| transition.conditions.extend(conditions));
|
||||
}
|
||||
}
|
||||
|
||||
impl ClipBuilder {
|
||||
pub fn data_mut<R>(&self, f: impl FnOnce(&mut ClipData) -> R) -> Option<R> {
|
||||
let name = self.name.clone();
|
||||
self.aac.write(|graph| clip_mut(graph, &name).map(f))
|
||||
}
|
||||
|
||||
/// Append one keyframe to the curve for (path, property), creating the curve if needed.
|
||||
pub fn push_key(&self, path: &str, property: &str, key: Keyframe) -> Result<(), String> {
|
||||
let target = infer_target(property).ok_or_else(|| {
|
||||
format!(
|
||||
"cannot tell which component `{property}` belongs to; \
|
||||
known properties are `m_IsActive` and `blendShape.*`"
|
||||
)
|
||||
})?;
|
||||
self.data_mut(|clip| {
|
||||
clip.curve_mut(path, target, property).keys.push(key);
|
||||
})
|
||||
.ok_or_else(|| format!("unknown clip `{}`", self.name))
|
||||
}
|
||||
}
|
||||
|
||||
impl BlendTreeBuilder {
|
||||
pub fn data_mut<R>(&self, f: impl FnOnce(&mut BlendTreeData) -> R) -> Option<R> {
|
||||
let name = self.name.clone();
|
||||
self.aac.write(|graph| blend_tree_mut(graph, &name).map(f))
|
||||
}
|
||||
|
||||
pub fn configure(&self, blend_type: BlendType, param_x: &str, param_y: Option<&str>) -> Result<(), String> {
|
||||
self.data_mut(|tree| {
|
||||
tree.blend_type = blend_type;
|
||||
tree.param_x = param_x.to_string();
|
||||
tree.param_y = param_y.map(str::to_string);
|
||||
})
|
||||
.ok_or_else(|| format!("unknown blend tree `{}`", self.name))
|
||||
}
|
||||
|
||||
pub fn push_child(&self, child: BlendChild) -> Result<(), String> {
|
||||
self.data_mut(|tree| tree.children.push(child))
|
||||
.ok_or_else(|| format!("unknown blend tree `{}`", self.name))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user