rive_rs/bones/
weight.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::component::Component;
8use crate::core::{Core, CoreContext, ObjectRef, OnAdded, Property};
9use crate::math::{self, Mat};
10use crate::shapes::PathVertex;
11use crate::status_code::StatusCode;
12
13#[derive(Debug)]
14pub struct Weight {
15    component: Component,
16    values: Property<u64>,
17    indices: Property<u64>,
18    translation: Cell<math::Vec>,
19}
20
21impl ObjectRef<'_, Weight> {
22    pub fn values(&self) -> u64 {
23        self.values.get()
24    }
25
26    pub fn set_values(&self, values: u64) {
27        self.values.set(values);
28    }
29
30    pub fn indices(&self) -> u64 {
31        self.indices.get()
32    }
33
34    pub fn set_indices(&self, indices: u64) {
35        self.indices.set(indices);
36    }
37}
38
39impl ObjectRef<'_, Weight> {
40    pub fn translation(&self) -> math::Vec {
41        self.translation.get()
42    }
43
44    pub fn set_translation(&self, translation: math::Vec) {
45        self.translation.set(translation);
46    }
47}
48
49impl Weight {
50    pub fn deform(
51        x: f32,
52        y: f32,
53        indices: usize,
54        weights: usize,
55        world: Mat,
56        bone_transforms: &[Cell<Mat>],
57    ) -> math::Vec {
58        let mut deformation = Mat::zero();
59        let r = world * math::Vec::new(x, y);
60
61        let encoded_weight_value = |index, data| (data >> (index * 8)) & 0xFF;
62
63        for i in 0usize..4 {
64            let weight = encoded_weight_value(i, weights);
65            if weight == 0 {
66                continue;
67            }
68
69            let normalized_weight = weight as f32 / 255.0;
70            let index = encoded_weight_value(i, indices);
71
72            let transform = bone_transforms[index].get();
73
74            deformation.scale_x += transform.scale_x * normalized_weight;
75            deformation.shear_y += transform.shear_y * normalized_weight;
76            deformation.shear_x += transform.shear_x * normalized_weight;
77            deformation.scale_y += transform.scale_y * normalized_weight;
78            deformation.translate_x += transform.translate_x * normalized_weight;
79            deformation.translate_y += transform.translate_y * normalized_weight;
80        }
81
82        deformation * r
83    }
84}
85
86impl Core for Weight {
87    parent_types![(component, Component)];
88
89    properties![(102, values, set_values), (103, indices, set_indices), component];
90}
91
92impl OnAdded for ObjectRef<'_, Weight> {
93    on_added!([on_added_clean, import], Component);
94
95    fn on_added_dirty(&self, context: &dyn CoreContext) -> StatusCode {
96        let component = self.cast::<Component>();
97
98        let code = component.on_added_dirty(context);
99        if code != StatusCode::Ok {
100            return code;
101        }
102
103        if let Some(parent) = component.parent().and_then(|core| core.try_cast::<PathVertex>()) {
104            parent.as_ref().set_weight(self.as_object());
105        } else {
106            return StatusCode::MissingObject;
107        }
108
109        StatusCode::Ok
110    }
111}
112
113impl Default for Weight {
114    fn default() -> Self {
115        Self {
116            component: Component::default(),
117            values: Property::new(255),
118            indices: Property::new(1),
119            translation: Cell::new(math::Vec::default()),
120        }
121    }
122}