blob: d7832a828f1a31f6880ae9940744a33948142013 [file] [log] [blame]
// 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 std::cell::Cell;
use crate::{
bones::Weight,
container_component::ContainerComponent,
core::{Core, CoreContext, Object, ObjectRef, OnAdded, Property},
math::{self, Mat},
option_cell::OptionCell,
shapes::Path,
status_code::StatusCode,
Component,
};
use super::CubicVertex;
#[derive(Debug, Default)]
pub struct PathVertex {
container_component: ContainerComponent,
x: Property<f32>,
y: Property<f32>,
weight: OptionCell<Object<Weight>>,
}
impl ObjectRef<'_, PathVertex> {
pub fn x(&self) -> f32 {
self.x.get()
}
pub fn set_x(&self, x: f32) {
if self.x() == x {
return;
}
self.x.set(x);
self.mark_path_dirty();
if let Some(cubic_vertex) = self.try_cast::<CubicVertex>() {
cubic_vertex.invalidate_in();
cubic_vertex.invalidate_out();
}
}
pub fn y(&self) -> f32 {
self.y.get()
}
pub fn set_y(&self, y: f32) {
if self.y() == y {
return;
}
self.y.set(y);
self.mark_path_dirty();
if let Some(cubic_vertex) = self.try_cast::<CubicVertex>() {
cubic_vertex.invalidate_in();
cubic_vertex.invalidate_out();
}
}
}
impl ObjectRef<'_, PathVertex> {
fn parent_path(&self) -> Option<Object<Path>> {
self.cast::<Component>().parent().and_then(|parent| parent.try_cast::<Path>())
}
pub(crate) fn mark_path_dirty(&self) {
if let Some(path) = self.parent_path() {
path.as_ref().mark_path_dirty();
}
}
pub fn weight(&self) -> Option<Object<Weight>> {
self.weight.get()
}
pub(crate) fn set_weight(&self, weight: Object<Weight>) {
self.weight.set(Some(weight));
}
pub fn deform(&self, world_transform: Mat, bone_transforms: &[Cell<Mat>]) {
if let Some(weight) = self.weight() {
let weight = weight.as_ref();
weight.set_translation(Weight::deform(
self.x(),
self.y(),
weight.indices() as usize,
weight.values() as usize,
world_transform,
bone_transforms,
));
}
if let Some(cubic_vertex) = self.try_cast::<CubicVertex>() {
cubic_vertex.deform(world_transform, bone_transforms);
}
}
pub fn render_translation(&self) -> math::Vec {
self.weight()
.map(|weight| weight.as_ref().translation())
.unwrap_or_else(|| math::Vec::new(self.x(), self.y()))
}
}
impl Core for PathVertex {
parent_types![(container_component, ContainerComponent)];
properties![(24, x, set_x), (25, y, set_y), container_component];
}
impl OnAdded for ObjectRef<'_, PathVertex> {
on_added!([on_added_clean, import], ContainerComponent);
fn on_added_dirty(&self, context: &dyn CoreContext) -> StatusCode {
let code = self.cast::<ContainerComponent>().on_added_dirty(context);
if code != StatusCode::Ok {
return code;
}
if let Some(path) = self.parent_path() {
path.as_ref().push_vertex(self.as_object());
StatusCode::Ok
} else {
StatusCode::MissingObject
}
}
}