rive_rs/shapes/
path_composer.rs
1use crate::component::Component;
6use crate::component_dirt::ComponentDirt;
7use crate::core::{Core, Object, ObjectRef, OnAdded};
8use crate::option_cell::OptionCell;
9use crate::shapes::command_path::{CommandPath, CommandPathBuilder};
10use crate::shapes::{PathSpace, Shape};
11use crate::TransformComponent;
12
13#[derive(Debug, Default)]
14pub struct PathComposer {
15 component: Component,
16 pub(crate) shape: OptionCell<Object<Shape>>,
17 local_path: OptionCell<CommandPath>,
18 world_path: OptionCell<CommandPath>,
19}
20
21impl ObjectRef<'_, PathComposer> {
22 pub(crate) fn with_local_path(&self, f: impl FnMut(Option<&CommandPath>)) {
23 self.local_path.with(f);
24 }
25
26 pub(crate) fn with_world_path(&self, f: impl FnMut(Option<&CommandPath>)) {
27 self.world_path.with(f);
28 }
29
30 pub fn build_dependencies(&self) {
31 let shape = self.shape.get().expect("shape should already be set in Path");
32 let shape = shape.as_ref();
33
34 shape.cast::<Component>().push_dependent(self.as_object().cast());
35
36 for path in shape.paths() {
37 path.cast::<Component>().as_ref().push_dependent(self.as_object().cast());
38 }
39 }
40
41 pub fn update(&self, value: ComponentDirt) {
42 if !Component::value_has_dirt(value, ComponentDirt::PATH) {
43 return;
44 }
45
46 let shape = self.shape.get().expect("shape should already be set in Path");
47 let shape = shape.as_ref();
48
49 let space = shape.path_space();
50
51 if space & PathSpace::LOCAL == PathSpace::LOCAL {
52 let mut builder = CommandPathBuilder::new();
53
54 let world = shape.cast::<TransformComponent>().world_transform();
55 let inverse_world = world.invert().unwrap_or_default();
56
57 for path in shape.paths() {
58 let path = path.as_ref();
59
60 let local_transform = inverse_world * path.transform();
61 path.with_command_path(|command_path| {
62 builder.path(
63 command_path.expect("command_path should already be set"),
64 Some(local_transform),
65 );
66 });
67 }
68
69 self.local_path.set(Some(builder.build()));
70 }
71
72 if space & PathSpace::WORLD == PathSpace::WORLD {
73 let mut builder = CommandPathBuilder::new();
74
75 for path in shape.paths() {
76 let path = path.as_ref();
77
78 let transform = path.transform();
79 path.with_command_path(|command_path| {
80 builder.path(
81 command_path.expect("command_path should already be set"),
82 Some(transform),
83 );
84 });
85 }
86
87 self.world_path.set(Some(builder.build()));
88 }
89 }
90}
91
92impl Core for PathComposer {
93 parent_types![(component, Component)];
94
95 properties!(component);
96}
97
98impl OnAdded for ObjectRef<'_, PathComposer> {
99 on_added!(Component);
100}