rive_rs/shapes/
path_composer.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use crate::component::Component;
use crate::component_dirt::ComponentDirt;
use crate::core::{Core, Object, ObjectRef, OnAdded};
use crate::option_cell::OptionCell;
use crate::shapes::command_path::{CommandPath, CommandPathBuilder};
use crate::shapes::{PathSpace, Shape};
use crate::TransformComponent;

#[derive(Debug, Default)]
pub struct PathComposer {
    component: Component,
    pub(crate) shape: OptionCell<Object<Shape>>,
    local_path: OptionCell<CommandPath>,
    world_path: OptionCell<CommandPath>,
}

impl ObjectRef<'_, PathComposer> {
    pub(crate) fn with_local_path(&self, f: impl FnMut(Option<&CommandPath>)) {
        self.local_path.with(f);
    }

    pub(crate) fn with_world_path(&self, f: impl FnMut(Option<&CommandPath>)) {
        self.world_path.with(f);
    }

    pub fn build_dependencies(&self) {
        let shape = self.shape.get().expect("shape should already be set in Path");
        let shape = shape.as_ref();

        shape.cast::<Component>().push_dependent(self.as_object().cast());

        for path in shape.paths() {
            path.cast::<Component>().as_ref().push_dependent(self.as_object().cast());
        }
    }

    pub fn update(&self, value: ComponentDirt) {
        if !Component::value_has_dirt(value, ComponentDirt::PATH) {
            return;
        }

        let shape = self.shape.get().expect("shape should already be set in Path");
        let shape = shape.as_ref();

        let space = shape.path_space();

        if space & PathSpace::LOCAL == PathSpace::LOCAL {
            let mut builder = CommandPathBuilder::new();

            let world = shape.cast::<TransformComponent>().world_transform();
            let inverse_world = world.invert().unwrap_or_default();

            for path in shape.paths() {
                let path = path.as_ref();

                let local_transform = inverse_world * path.transform();
                path.with_command_path(|command_path| {
                    builder.path(
                        command_path.expect("command_path should already be set"),
                        Some(local_transform),
                    );
                });
            }

            self.local_path.set(Some(builder.build()));
        }

        if space & PathSpace::WORLD == PathSpace::WORLD {
            let mut builder = CommandPathBuilder::new();

            for path in shape.paths() {
                let path = path.as_ref();

                let transform = path.transform();
                path.with_command_path(|command_path| {
                    builder.path(
                        command_path.expect("command_path should already be set"),
                        Some(transform),
                    );
                });
            }

            self.world_path.set(Some(builder.build()));
        }
    }
}

impl Core for PathComposer {
    parent_types![(component, Component)];

    properties!(component);
}

impl OnAdded for ObjectRef<'_, PathComposer> {
    on_added!(Component);
}