Skip to content

Commit b7a90ae

Browse files
authored
make bevy_mesh optional for bevy_animate (#20742)
# Objective - make bevy_mesh optional for bevy_animate as mentioned in #20714 (comment) ## Solution - copy paste the morph weights stuff out into a module, gate it, then add the optional dep
1 parent 7fc9bba commit b7a90ae

File tree

7 files changed

+227
-204
lines changed

7 files changed

+227
-204
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ default = [
167167
"hdr",
168168
"ktx2",
169169
"morph",
170+
"morph_animation",
170171
"multi_threaded",
171172
"png",
172173
"reflect_auto_register",
@@ -445,6 +446,9 @@ gltf_animation = ["bevy_internal/gltf_animation"]
445446
# Enables support for morph target weights in bevy_mesh
446447
morph = ["bevy_internal/morph"]
447448

449+
# Enables bevy_mesh and bevy_animation morph weight support
450+
morph_animation = ["bevy_internal/morph_animation"]
451+
448452
# Enable using a shared stdlib for cxx on Android
449453
android_shared_stdcxx = ["bevy_internal/android_shared_stdcxx"]
450454

crates/bevy_animation/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ bevy_asset = { path = "../bevy_asset", version = "0.18.0-dev" }
1616
bevy_color = { path = "../bevy_color", version = "0.18.0-dev" }
1717
bevy_derive = { path = "../bevy_derive", version = "0.18.0-dev" }
1818
bevy_math = { path = "../bevy_math", version = "0.18.0-dev" }
19-
bevy_mesh = { path = "../bevy_mesh", version = "0.18.0-dev", features = [
19+
bevy_mesh = { path = "../bevy_mesh", version = "0.18.0-dev", optional = true, features = [
2020
"morph",
2121
] }
2222
bevy_reflect = { path = "../bevy_reflect", version = "0.18.0-dev", features = [

crates/bevy_animation/src/animation_curves.rs

Lines changed: 3 additions & 203 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ use core::{
8989
marker::PhantomData,
9090
};
9191

92+
#[cfg(feature = "bevy_mesh")]
93+
pub use crate::morph::*;
9294
use crate::{
9395
graph::AnimationNodeIndex,
9496
prelude::{Animatable, BlendInput},
@@ -97,10 +99,8 @@ use crate::{
9799
use bevy_ecs::component::{Component, Mutable};
98100
use bevy_math::curve::{
99101
cores::{UnevenCore, UnevenCoreError},
100-
iterable::IterableCurve,
101102
Curve, Interval,
102103
};
103-
use bevy_mesh::morph::MorphWeights;
104104
use bevy_platform::hash::Hashed;
105105
use bevy_reflect::{FromReflect, Reflect, Reflectable, TypeInfo, Typed};
106106
use downcast_rs::{impl_downcast, Downcast};
@@ -420,206 +420,6 @@ impl<A: Animatable> AnimationCurveEvaluator for AnimatableCurveEvaluator<A> {
420420
}
421421
}
422422

423-
/// This type allows an [`IterableCurve`] valued in `f32` to be used as an [`AnimationCurve`]
424-
/// that animates [morph weights].
425-
///
426-
/// [morph weights]: MorphWeights
427-
#[derive(Debug, Clone, Reflect, FromReflect)]
428-
#[reflect(from_reflect = false)]
429-
pub struct WeightsCurve<C>(pub C);
430-
431-
#[derive(Reflect)]
432-
struct WeightsCurveEvaluator {
433-
/// The values of the stack, in which each element is a list of morph target
434-
/// weights.
435-
///
436-
/// The stack elements are concatenated and tightly packed together.
437-
///
438-
/// The number of elements in this stack will always be a multiple of
439-
/// [`Self::morph_target_count`].
440-
stack_morph_target_weights: Vec<f32>,
441-
442-
/// The blend weights and graph node indices for each element of the stack.
443-
///
444-
/// This should have as many elements as there are stack nodes. In other
445-
/// words, `Self::stack_morph_target_weights.len() *
446-
/// Self::morph_target_counts as usize ==
447-
/// Self::stack_blend_weights_and_graph_nodes`.
448-
stack_blend_weights_and_graph_nodes: Vec<(f32, AnimationNodeIndex)>,
449-
450-
/// The morph target weights in the blend register, if any.
451-
///
452-
/// This field should be ignored if [`Self::blend_register_blend_weight`] is
453-
/// `None`. If non-empty, it will always have [`Self::morph_target_count`]
454-
/// elements in it.
455-
blend_register_morph_target_weights: Vec<f32>,
456-
457-
/// The weight in the blend register.
458-
///
459-
/// This will be `None` if the blend register is empty. In that case,
460-
/// [`Self::blend_register_morph_target_weights`] will be empty.
461-
blend_register_blend_weight: Option<f32>,
462-
463-
/// The number of morph targets that are to be animated.
464-
morph_target_count: Option<u32>,
465-
}
466-
467-
impl<C> AnimationCurve for WeightsCurve<C>
468-
where
469-
C: IterableCurve<f32> + Debug + Clone + Reflectable,
470-
{
471-
fn clone_value(&self) -> Box<dyn AnimationCurve> {
472-
Box::new(self.clone())
473-
}
474-
475-
fn domain(&self) -> Interval {
476-
self.0.domain()
477-
}
478-
479-
fn evaluator_id(&self) -> EvaluatorId<'_> {
480-
EvaluatorId::Type(TypeId::of::<WeightsCurveEvaluator>())
481-
}
482-
483-
fn create_evaluator(&self) -> Box<dyn AnimationCurveEvaluator> {
484-
Box::new(WeightsCurveEvaluator {
485-
stack_morph_target_weights: vec![],
486-
stack_blend_weights_and_graph_nodes: vec![],
487-
blend_register_morph_target_weights: vec![],
488-
blend_register_blend_weight: None,
489-
morph_target_count: None,
490-
})
491-
}
492-
493-
fn apply(
494-
&self,
495-
curve_evaluator: &mut dyn AnimationCurveEvaluator,
496-
t: f32,
497-
weight: f32,
498-
graph_node: AnimationNodeIndex,
499-
) -> Result<(), AnimationEvaluationError> {
500-
let curve_evaluator = curve_evaluator
501-
.downcast_mut::<WeightsCurveEvaluator>()
502-
.unwrap();
503-
504-
let prev_morph_target_weights_len = curve_evaluator.stack_morph_target_weights.len();
505-
curve_evaluator
506-
.stack_morph_target_weights
507-
.extend(self.0.sample_iter_clamped(t));
508-
curve_evaluator.morph_target_count = Some(
509-
(curve_evaluator.stack_morph_target_weights.len() - prev_morph_target_weights_len)
510-
as u32,
511-
);
512-
513-
curve_evaluator
514-
.stack_blend_weights_and_graph_nodes
515-
.push((weight, graph_node));
516-
Ok(())
517-
}
518-
}
519-
520-
impl WeightsCurveEvaluator {
521-
fn combine(
522-
&mut self,
523-
graph_node: AnimationNodeIndex,
524-
additive: bool,
525-
) -> Result<(), AnimationEvaluationError> {
526-
let Some(&(_, top_graph_node)) = self.stack_blend_weights_and_graph_nodes.last() else {
527-
return Ok(());
528-
};
529-
if top_graph_node != graph_node {
530-
return Ok(());
531-
}
532-
533-
let (weight_to_blend, _) = self.stack_blend_weights_and_graph_nodes.pop().unwrap();
534-
let stack_iter = self.stack_morph_target_weights.drain(
535-
(self.stack_morph_target_weights.len() - self.morph_target_count.unwrap() as usize)..,
536-
);
537-
538-
match self.blend_register_blend_weight {
539-
None => {
540-
self.blend_register_blend_weight = Some(weight_to_blend);
541-
self.blend_register_morph_target_weights.clear();
542-
543-
// In the additive case, the values pushed onto the blend register need
544-
// to be scaled by the weight.
545-
if additive {
546-
self.blend_register_morph_target_weights
547-
.extend(stack_iter.map(|m| m * weight_to_blend));
548-
} else {
549-
self.blend_register_morph_target_weights.extend(stack_iter);
550-
}
551-
}
552-
553-
Some(ref mut current_weight) => {
554-
*current_weight += weight_to_blend;
555-
for (dest, src) in self
556-
.blend_register_morph_target_weights
557-
.iter_mut()
558-
.zip(stack_iter)
559-
{
560-
if additive {
561-
*dest += src * weight_to_blend;
562-
} else {
563-
*dest = f32::interpolate(dest, &src, weight_to_blend / *current_weight);
564-
}
565-
}
566-
}
567-
}
568-
569-
Ok(())
570-
}
571-
}
572-
573-
impl AnimationCurveEvaluator for WeightsCurveEvaluator {
574-
fn blend(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError> {
575-
self.combine(graph_node, /*additive=*/ false)
576-
}
577-
578-
fn add(&mut self, graph_node: AnimationNodeIndex) -> Result<(), AnimationEvaluationError> {
579-
self.combine(graph_node, /*additive=*/ true)
580-
}
581-
582-
fn push_blend_register(
583-
&mut self,
584-
weight: f32,
585-
graph_node: AnimationNodeIndex,
586-
) -> Result<(), AnimationEvaluationError> {
587-
if self.blend_register_blend_weight.take().is_some() {
588-
self.stack_morph_target_weights
589-
.append(&mut self.blend_register_morph_target_weights);
590-
self.stack_blend_weights_and_graph_nodes
591-
.push((weight, graph_node));
592-
}
593-
Ok(())
594-
}
595-
596-
fn commit(&mut self, mut entity: AnimationEntityMut) -> Result<(), AnimationEvaluationError> {
597-
if self.stack_morph_target_weights.is_empty() {
598-
return Ok(());
599-
}
600-
601-
// Compute the index of the first morph target in the last element of
602-
// the stack.
603-
let index_of_first_morph_target =
604-
self.stack_morph_target_weights.len() - self.morph_target_count.unwrap() as usize;
605-
606-
for (dest, src) in entity
607-
.get_mut::<MorphWeights>()
608-
.ok_or_else(|| {
609-
AnimationEvaluationError::ComponentNotPresent(TypeId::of::<MorphWeights>())
610-
})?
611-
.weights_mut()
612-
.iter_mut()
613-
.zip(self.stack_morph_target_weights[index_of_first_morph_target..].iter())
614-
{
615-
*dest = *src;
616-
}
617-
self.stack_morph_target_weights.clear();
618-
self.stack_blend_weights_and_graph_nodes.clear();
619-
Ok(())
620-
}
621-
}
622-
623423
#[derive(Reflect)]
624424
struct BasicAnimationCurveEvaluator<A>
625425
where
@@ -821,7 +621,7 @@ pub enum EvaluatorId<'a> {
821621
/// control over how animations are evaluated.
822622
///
823623
/// You can implement this trait when the generic [`AnimatableCurveEvaluator`]
824-
/// isn't sufficiently-expressive for your needs. For example, [`MorphWeights`]
624+
/// isn't sufficiently-expressive for your needs. For example, `MorphWeights`
825625
/// implements this trait instead of using [`AnimatableCurveEvaluator`] because
826626
/// it needs to animate arbitrarily many weights at once, which can't be done
827627
/// with [`Animatable`] as that works on fixed-size values only.

crates/bevy_animation/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pub mod animatable;
1313
pub mod animation_curves;
1414
pub mod gltf_curves;
1515
pub mod graph;
16+
#[cfg(feature = "bevy_mesh")]
17+
mod morph;
1618
pub mod transition;
1719

1820
mod animation_event;
@@ -1249,9 +1251,12 @@ impl Plugin for AnimationPlugin {
12491251
// it to its own system set after `Update` but before
12501252
// `PostUpdate`. For now, we just disable ambiguity testing
12511253
// for this system.
1254+
#[cfg(feature = "bevy_mesh")]
12521255
animate_targets
12531256
.before(bevy_mesh::InheritWeightSystems)
12541257
.ambiguous_with_all(),
1258+
#[cfg(not(feature = "bevy_mesh"))]
1259+
animate_targets.ambiguous_with_all(),
12551260
trigger_untargeted_animation_events,
12561261
expire_completed_transitions,
12571262
)

0 commit comments

Comments
 (0)