rive_rs/shapes/
path_vertex.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::cell::Cell;
6
7use crate::bones::Weight;
8use crate::container_component::ContainerComponent;
9use crate::core::{Core, CoreContext, Object, ObjectRef, OnAdded, Property};
10use crate::math::{self, Mat};
11use crate::option_cell::OptionCell;
12use crate::shapes::Path;
13use crate::status_code::StatusCode;
14use crate::Component;
15
16use super::CubicVertex;
17
18#[derive(Debug, Default)]
19pub struct PathVertex {
20    container_component: ContainerComponent,
21    x: Property<f32>,
22    y: Property<f32>,
23    weight: OptionCell<Object<Weight>>,
24}
25
26impl ObjectRef<'_, PathVertex> {
27    pub fn x(&self) -> f32 {
28        self.x.get()
29    }
30
31    pub fn set_x(&self, x: f32) {
32        if self.x() == x {
33            return;
34        }
35
36        self.x.set(x);
37
38        self.mark_path_dirty();
39
40        if let Some(cubic_vertex) = self.try_cast::<CubicVertex>() {
41            cubic_vertex.invalidate_in();
42            cubic_vertex.invalidate_out();
43        }
44    }
45
46    pub fn y(&self) -> f32 {
47        self.y.get()
48    }
49
50    pub fn set_y(&self, y: f32) {
51        if self.y() == y {
52            return;
53        }
54
55        self.y.set(y);
56
57        self.mark_path_dirty();
58
59        if let Some(cubic_vertex) = self.try_cast::<CubicVertex>() {
60            cubic_vertex.invalidate_in();
61            cubic_vertex.invalidate_out();
62        }
63    }
64}
65
66impl ObjectRef<'_, PathVertex> {
67    fn parent_path(&self) -> Option<Object<Path>> {
68        self.cast::<Component>().parent().and_then(|parent| parent.try_cast::<Path>())
69    }
70
71    pub(crate) fn mark_path_dirty(&self) {
72        if let Some(path) = self.parent_path() {
73            path.as_ref().mark_path_dirty();
74        }
75    }
76
77    pub fn weight(&self) -> Option<Object<Weight>> {
78        self.weight.get()
79    }
80
81    pub(crate) fn set_weight(&self, weight: Object<Weight>) {
82        self.weight.set(Some(weight));
83    }
84
85    pub fn deform(&self, world_transform: Mat, bone_transforms: &[Cell<Mat>]) {
86        if let Some(weight) = self.weight() {
87            let weight = weight.as_ref();
88            weight.set_translation(Weight::deform(
89                self.x(),
90                self.y(),
91                weight.indices() as usize,
92                weight.values() as usize,
93                world_transform,
94                bone_transforms,
95            ));
96        }
97
98        if let Some(cubic_vertex) = self.try_cast::<CubicVertex>() {
99            cubic_vertex.deform(world_transform, bone_transforms);
100        }
101    }
102
103    pub fn render_translation(&self) -> math::Vec {
104        self.weight()
105            .map(|weight| weight.as_ref().translation())
106            .unwrap_or_else(|| math::Vec::new(self.x(), self.y()))
107    }
108}
109
110impl Core for PathVertex {
111    parent_types![(container_component, ContainerComponent)];
112
113    properties![(24, x, set_x), (25, y, set_y), container_component];
114}
115
116impl OnAdded for ObjectRef<'_, PathVertex> {
117    on_added!([on_added_clean, import], ContainerComponent);
118
119    fn on_added_dirty(&self, context: &dyn CoreContext) -> StatusCode {
120        let code = self.cast::<ContainerComponent>().on_added_dirty(context);
121        if code != StatusCode::Ok {
122            return code;
123        }
124
125        if let Some(path) = self.parent_path() {
126            path.as_ref().push_vertex(self.as_object());
127            StatusCode::Ok
128        } else {
129            StatusCode::MissingObject
130        }
131    }
132}